def testGenerator(self): def returner(): return (str(x) for x in range(10)) # get the generator code object genCode = returner.func_code.co_consts[1] # FIXME: this is what co_varnames looks like, but I don't understand why # possible clue in Python, Lib/compiler/ast.py, class GenExpr if utils.pythonVersion() < utils.PYTHON_2_5: self.assertEquals(genCode.co_varnames, ('[outmost-iterable]', 'x')) else: self.assertEquals(genCode.co_varnames, ('.0', 'x')) # wrap it into a Funtion so we can look at it f = function.Function( function.FakeFunction(genCode.co_name, genCode)) self.failIf(f.isMethod) self.assertEquals(f.minArgs, 1) self.assertEquals(f.maxArgs, 1) if utils.pythonVersion() < utils.PYTHON_2_5: self.assertEquals(f.arguments(), ('[outmost-iterable]', )) else: self.assertEquals(f.arguments(), ('.0', ))
def test_star_import(self): warnings = self.check(['input/starimport.py', ]) self.assertEquals(len(warnings), 0, self.formatWarnings(warnings)) # check the module doing the star import pcmodule = pcmodules.getPCModule("starimport", moduleDir="input") self.assertEquals(pcmodule.moduleName, "starimport") self.assertEquals(pcmodule.moduleDir, "input") if utils.pythonVersion() >= utils.PYTHON_2_6: self.assertEquals(pcmodule.variables.keys(), ["__package__"]) else: self.assertEquals(pcmodule.variables.keys(), []) self.assertEquals(pcmodule.classes.keys(), []) self.assertEquals(pcmodule.functions.keys(), []) self.assertEquals(pcmodule.modules.keys(), ["gettext", ]) # check the code self.assertEquals(len(pcmodule.codes), 1) self.assertEquals(pcmodule.codes[0].func.function.func_name, '__main__') # FIXME: why do we have a non-empty stack here ? # self.assertEquals(pcmodule.codes[0].stack, []) modules = pcmodules._getPCModulesDict() for (name, moduleDir) in modules.keys(): self.failIf(name.find('*') > -1, 'Invalid loaded module name %s' % (name, )) # check the module from which we are starimporting; # it should have been loaded as a side effect pcmodule = pcmodules.getPCModule("starimportfrom", moduleDir="input") self.failUnless(pcmodule, pcmodules._getPCModulesDict()) self.assertEquals(pcmodule.moduleName, "starimportfrom") self.assertEquals(pcmodule.moduleDir, "input") variables = [v for v in pcmodule.variables.keys() if v not in Config._DEFAULT_VARIABLE_IGNORE_LIST] if utils.pythonVersion() >= utils.PYTHON_2_6: self.assertEquals(pcmodule.variables.keys(), ["__package__"]) else: self.assertEquals(pcmodule.variables.keys(), []) self.assertEquals(pcmodule.classes.keys(), []) self.assertEquals(pcmodule.functions.keys(), ["_", ]) self.assertEquals(pcmodule.modules.keys(), ["gettext", ]) # check the code self.assertEquals(len(pcmodule.codes), 0)
def test_nested(self): warnings = self.check(['input/nested.py', ]) self.assertEquals(len(warnings), 1, self.formatWarnings(warnings)) self.assertWarnings(warnings, ['input/nested.py']) # check the module and the code pcmodule = pcmodules.getPCModule("nested", moduleDir="input") self.assertEquals(pcmodule.moduleName, "nested") self.assertEquals(pcmodule.moduleDir, "input") if utils.pythonVersion() >= utils.PYTHON_2_6: self.assertEquals(pcmodule.variables.keys(), ["__package__"]) else: self.assertEquals(pcmodule.variables.keys(), []) self.assertEquals(pcmodule.classes.keys(), ["Result"]) self.assertEquals(pcmodule.functions.keys(), ["outside"]) # check the code self.assertEquals(len(pcmodule.codes), 4) self.assertEquals(pcmodule.codes[0].func.function.func_name, '__main__') # FIXME: this assert is wrong; the code should be named outside, # but since the code object got re-used for nested code, it's called # second self.assertEquals(pcmodule.codes[1].func.function.func_name, 'outside') self.assertEquals(pcmodule.codes[2].func.function.func_name, 'Result') self.assertEquals(pcmodule.codes[3].func.function.func_name, '__init__') self.failIf(pcmodule.codes[0].stack) # FIXME: why do we have a non-empty stack here ? # self.failIf(pcmodule.codes[1].stack, pcmodule.codes[1].stack) self.failIf(pcmodule.codes[2].stack) self.failIf(pcmodule.codes[3].stack)
def test_star_import_from(self): # First make sure that gettext only exists as a module, not as # a function warnings = self.check(['input/starimportfrom.py', ]) self.assertEquals(len(warnings), 0, self.formatWarnings(warnings)) pcmodule = pcmodules.getPCModule("starimportfrom", moduleDir="input") self.assertEquals(pcmodule.moduleName, "starimportfrom") self.assertEquals(pcmodule.moduleDir, "input") variables = [v for v in pcmodule.variables.keys() if v not in Config._DEFAULT_VARIABLE_IGNORE_LIST] if utils.pythonVersion() >= utils.PYTHON_2_6: self.assertEquals(variables, ["__package__"]) else: self.assertEquals(variables, []) self.assertEquals(pcmodule.classes.keys(), []) self.assertEquals(pcmodule.functions.keys(), ['_']) self.assertEquals(pcmodule.modules.keys(), ["gettext", ]) # check the code self.assertEquals(len(pcmodule.codes), 2, [c.func.function.func_name for c in pcmodule.codes]) self.assertEquals(pcmodule.codes[0].func.function.func_name, '__main__') self.assertEquals(pcmodule.codes[1].func.function.func_name, 'gettext') # FIXME: why do we have a non-empty stack here ? # self.assertEquals(pcmodule.codes[0].stack, []) self.assertEquals(pcmodule.codes[1].stack, [])
def _checkReturnWarnings(code) : is_getattr = code.func_code.co_name in ('__getattr__', '__getattribute__') if is_getattr : for line, retval, dummy in code.returnValues : if retval.isNone() : err = msgs.DONT_RETURN_NONE % code.func_code.co_name code.addWarning(err, line+1) # there must be at least 2 real return values to check for consistency returnValuesLen = len(code.returnValues) if returnValuesLen < 2 : return # if the last return is implicit, check if there are non None returns lastReturn = code.returnValues[-1] # Python 2.4 optimizes the dead implicit return out, so we can't # distinguish implicit and explicit "return None" if utils.pythonVersion() < utils.PYTHON_2_4 and \ not code.starts_and_ends_with_finally and \ cfg().checkImplicitReturns and lastReturn[1].isImplicitNone(): for line, retval, dummy in code.returnValues[:-1] : if not retval.isNone() : code.addWarning(msgs.IMPLICIT_AND_EXPLICIT_RETURNS, lastReturn[0]+1) break # __get*__ funcs can return different types, don't warn about inconsistency if utils.startswith(code.func_code.co_name, '__get') and \ utils.endswith(code.func_code.co_name, '__') : return returnType, returnData = None, None for line, value, dummy in code.returnValues : if not value.isNone() : valueType = value.getType(code.typeMap) if returnType is None and valueType not in _IGNORE_RETURN_TYPES : returnData = value returnType = valueType continue # always ignore None, None can be returned w/any other type # FIXME: if we stored func return values, we could do better if returnType is not None and not value.isNone() and \ valueType not in _IGNORE_RETURN_TYPES and \ returnData.type not in _IGNORE_RETURN_TYPES : ok = returnType in (type(value.data), valueType) if ok : if returnType == types.TupleType : # FIXME: this isn't perfect, if len == 0 # the length can really be 0 OR unknown # we shouldn't check the lengths for equality # ONLY IF one of the lengths is truly unknown if returnData.length > 0 and value.length > 0: ok = returnData.length == value.length else : ok = _checkSubclass(returnType, valueType) or \ _checkSubclass(valueType, returnType) if not ok : code.addWarning(msgs.INCONSISTENT_RETURN_TYPE, line)
def _setupBuiltinAttrs(): item = Stack.Item(None, None) BUILTIN_ATTRS[types.MethodType] = dir(item.__init__) del item if utils.pythonVersion() >= utils.PYTHON_2_2: # FIXME: I'm sure more types need to be added here BUILTIN_ATTRS[types.StringType] = dir("".__class__) BUILTIN_ATTRS[types.ListType] = dir([].__class__) BUILTIN_ATTRS[types.DictType] = dir({}.__class__) try: import warnings _MSG = "xrange object's 'start', 'stop' and 'step' attributes are deprecated" warnings.filterwarnings("ignore", _MSG) del warnings, _MSG except (ImportError, AssertionError): pass BUILTIN_ATTRS[types.XRangeType] = dir(xrange(0)) try: BUILTIN_ATTRS[types.ComplexType] = dir(complex(0, 1)) except: pass try: BUILTIN_ATTRS[types.UnicodeType] = dir(unicode("")) except: pass try: BUILTIN_ATTRS[types.CodeType] = dir(_setupBuiltinAttrs.func_code) except: pass try: BUILTIN_ATTRS[types.FileType] = dir(sys.__stdin__) except: pass try: raise TypeError except TypeError: try: tb = sys.exc_info()[2] BUILTIN_ATTRS[types.TracebackType] = dir(tb) BUILTIN_ATTRS[types.FrameType] = dir(tb.tb_frame) except: pass tb = None
def _setupBuiltinAttrs(): item = Stack.Item(None, None) BUILTIN_ATTRS[types.MethodType] = dir(item.__init__) del item if utils.pythonVersion() >= utils.PYTHON_2_2: # FIXME: I'm sure more types need to be added here BUILTIN_ATTRS[types.StringType] = dir(''.__class__) BUILTIN_ATTRS[types.ListType] = dir([].__class__) BUILTIN_ATTRS[types.DictType] = dir({}.__class__) try: import warnings _MSG = "xrange object's 'start', 'stop' and 'step' attributes are deprecated" warnings.filterwarnings('ignore', _MSG) del warnings, _MSG except (ImportError, AssertionError): pass BUILTIN_ATTRS[types.XRangeType] = dir(xrange(0)) try: BUILTIN_ATTRS[types.ComplexType] = dir(complex(0, 1)) except: pass try: BUILTIN_ATTRS[types.UnicodeType] = dir(unicode('')) except: pass try: BUILTIN_ATTRS[types.CodeType] = dir(_setupBuiltinAttrs.func_code) except: pass try: BUILTIN_ATTRS[types.FileType] = dir(sys.__stdin__) except: pass try: raise TypeError except TypeError: try: tb = sys.exc_info()[2] BUILTIN_ATTRS[types.TracebackType] = dir(tb) BUILTIN_ATTRS[types.FrameType] = dir(tb.tb_frame) except: pass tb = None
def test_unused_import(self): warnings = self.check(['input/unused_import.py', ]) self.assertEquals(len(warnings), 4, self.formatWarnings(warnings)) self.assertWarnings(warnings, ['input/unused_import.py']) # check the module and the code pcmodule = pcmodules.getPCModule("unused_import", moduleDir="input") self.assertEquals(pcmodule.moduleName, "unused_import") self.assertEquals(pcmodule.moduleDir, "input") if utils.pythonVersion() >= utils.PYTHON_2_6: self.assertEquals(pcmodule.variables.keys(), ["__package__"]) else: self.assertEquals(pcmodule.variables.keys(), []) self.assertEquals(pcmodule.classes, {}) self.assertEquals(pcmodule.functions.keys(), ["do"]) # check the code self.assertEquals(len(pcmodule.codes), 2) main = pcmodule.codes[0] # all triggered warnings were import warnings self.failIf(main.warnings) # FIXME: should the stack not be empty after processing it all ? # self.failIf(main.stack) modules = pcmodule.modules.keys() modules.sort() self.assertEquals(modules, ["dom", "path", "sax", "sys"]) self.assertEquals(pcmodule.moduleLineNums, { 'dom': ('input/unused_import.py', 10), 'do': ('input/unused_import.py', 12), 'sys': ('input/unused_import.py', 4), 'path': ('input/unused_import.py', 6), ('os', 'path'): ('input/unused_import.py', 6), ('os',): ('input/unused_import.py', 6), 'sax': ('input/unused_import.py', 8), 'xml.sax': ('input/unused_import.py', 8), ('xml', ): ('input/unused_import.py', 10), ('xml', 'dom'): ('input/unused_import.py', 10), })
def _setupBuiltinMethods() : if utils.pythonVersion() >= utils.PYTHON_2_2 : PY22_DICT_METHODS = { 'iteritems': (types.ListType, 0, 0), 'iterkeys': (types.ListType, 0, 0), 'itervalues': (types.ListType, 0, 0), } BUILTIN_METHODS[types.DictType].update(PY22_DICT_METHODS) try : BUILTIN_METHODS[types.ComplexType] = \ { 'conjugate': (types.ComplexType, 0, 0), } except AttributeError : pass if len(dir('')) > 0 : BUILTIN_METHODS[types.StringType] = _STRING_METHODS try : BUILTIN_METHODS[types.UnicodeType] = _STRING_METHODS except AttributeError : pass
'round': (types.FloatType, 1, 2), 'setattr': (types.NoneType, 3, 3), 'slice': (types.SliceType, 1, 3), 'str': (types.StringType, 1, 1), 'tuple': (types.TupleType, 1, 1), 'type': (types.TypeType, 1, 1), 'vars': (types.DictType, 0, 1), 'xrange': (types.ListType, 1, 3), } if hasattr(types, 'UnicodeType'): GLOBAL_FUNC_INFO['unichr'] = (types.UnicodeType, 1, 1) GLOBAL_FUNC_INFO['unicode'] = (types.UnicodeType, 1, 3, ['string', 'encoding', 'errors']) if utils.pythonVersion() >= utils.PYTHON_2_2: GLOBAL_FUNC_INFO['compile'] = (types.CodeType, 3, 5) GLOBAL_FUNC_INFO['dict'] = (types.DictType, 0, 1, ['items']) GLOBAL_FUNC_INFO['file'] = GLOBAL_FUNC_INFO['open'] GLOBAL_FUNC_INFO['float'] = (types.FloatType, 0, 1, ['x']) GLOBAL_FUNC_INFO['int'] = (types.IntType, 0, 2, ['x']) GLOBAL_FUNC_INFO['list'] = (types.ListType, 0, 1, ['sequence']) GLOBAL_FUNC_INFO['long'] = (types.LongType, 0, 2, ['x']) GLOBAL_FUNC_INFO['str'] = (types.StringType, 0, 1, ['object']) # FIXME: type doesn't take 2 args, only 1 or 3 GLOBAL_FUNC_INFO['type'] = (types.TypeType, 1, 3, ['name', 'bases', 'dict']) GLOBAL_FUNC_INFO['tuple'] = (types.TupleType, 0, 1, ['sequence']) GLOBAL_FUNC_INFO['classmethod'] = (types.MethodType, 1, 1) GLOBAL_FUNC_INFO['iter'] = (Stack.TYPE_UNKNOWN, 1, 2)
'repr': (types.StringType, 1, 1), 'round': (types.FloatType, 1, 2), 'setattr': (types.NoneType, 3, 3), 'slice': (types.SliceType, 1, 3), 'str': (types.StringType, 1, 1), 'tuple': (types.TupleType, 1, 1), 'type': (types.TypeType, 1, 1), 'vars': (types.DictType, 0, 1), 'xrange': (types.ListType, 1, 3), } if hasattr(types, 'UnicodeType') : GLOBAL_FUNC_INFO['unichr'] = (types.UnicodeType, 1, 1) GLOBAL_FUNC_INFO['unicode'] = (types.UnicodeType, 1, 3, ['string', 'encoding', 'errors']) if utils.pythonVersion() >= utils.PYTHON_2_2 : GLOBAL_FUNC_INFO['compile'] = (types.CodeType, 3, 5) GLOBAL_FUNC_INFO['dict'] = (types.DictType, 0, 1, ['items']) GLOBAL_FUNC_INFO['file'] = GLOBAL_FUNC_INFO['open'] GLOBAL_FUNC_INFO['float'] = (types.FloatType, 0, 1, ['x']) GLOBAL_FUNC_INFO['int'] = (types.IntType, 0, 2, ['x']) GLOBAL_FUNC_INFO['list'] = (types.ListType, 0, 1, ['sequence']) GLOBAL_FUNC_INFO['long'] = (types.LongType, 0, 2, ['x']) GLOBAL_FUNC_INFO['str'] = (types.StringType, 0, 1, ['object']) # FIXME: type doesn't take 2 args, only 1 or 3 GLOBAL_FUNC_INFO['type'] = (types.TypeType, 1, 3, ['name', 'bases', 'dict']) GLOBAL_FUNC_INFO['tuple'] = (types.TupleType, 0, 1, ['sequence']) GLOBAL_FUNC_INFO['classmethod'] = (types.MethodType, 1, 1) GLOBAL_FUNC_INFO['iter'] = (Stack.TYPE_UNKNOWN, 1, 2) GLOBAL_FUNC_INFO['property'] = (Stack.TYPE_UNKNOWN, 0, 4, ['fget', 'fset', 'fdel', 'doc'])
return op == 127 def LOAD_GLOBAL(op): return op == 116 def LOAD_CONST(op): return op == 100 def LOAD_FAST(op): return op == 124 if utils.pythonVersion() >= utils.PYTHON_2_7: def LOAD_ATTR(op): return op == 106 else: def LOAD_ATTR(op): return op == 105 def LOAD_DEREF(op): return op == 136 def STORE_ATTR(op): return op == 95
# Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Python byte code operations. Very similar to the dis and opcode module, but dis does not exist in Jython, so recreate the small portion we need here. """ from pychecker import utils def LINE_NUM(op): return op == 127 def LOAD_GLOBAL(op): return op == 116 def LOAD_CONST(op): return op == 100 def LOAD_FAST(op): return op == 124 if utils.pythonVersion() >= utils.PYTHON_2_7: def LOAD_ATTR(op): return op == 106 else: def LOAD_ATTR(op): return op == 105 def LOAD_DEREF(op): return op == 136 def STORE_ATTR(op): return op == 95 def POP_TOP(op): return op == 1 if utils.pythonVersion() >= utils.PYTHON_2_7: def IMPORT_FROM(op): return op == 109 else: def IMPORT_FROM(op): return op == 108 def IMPORT_STAR(op): return op == 84 def UNARY_POSITIVE(op): return op == 10 def UNARY_NEGATIVE(op): return op == 11 def UNARY_INVERT(op): return op == 15 def RETURN_VALUE(op): return op == 83