VariableChecks.py :  » Development » PyChecker » pychecker-0.8.18 » pychecker2 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » PyChecker 
PyChecker » pychecker 0.8.18 » pychecker2 » VariableChecks.py
from pychecker2.Check import Check
from pychecker2.Options import Opt,BoolOpt
from pychecker2.Warning import Warning
from pychecker2.util import *
from pychecker2 import symbols

from compiler import ast,walk

def _is_method(scope):
    return scope.__class__ is symbols.FunctionScope and \
           scope.parent.__class__ is symbols.ClassScope

def _is_self(scope, name):
    return _is_method(scope) and name in scope.node.argnames[:1]

def is_arg_and_defaulted_to_same_name(name, scope):
    if isinstance(scope, symbols.FunctionScope):
        if name in scope.node.argnames and scope.node.defaults:
            # compute default args
            args = scope.node.argnames[:]
            # knock off kwargs
            if scope.node.kwargs:
                args = args[:-1]
            # knock off varags 
            if scope.node.varargs:
                args = args[:-1]
            # take the last args as the defaults
            args = args[-len(scope.node.defaults):]
            try:
                # get the corresponding default arg value
                default = scope.node.defaults[args.index(name)]
                # must be a Name node of the same name
                if isinstance(default, ast.Name) and \
                   default.name == name:
                    return 1
            except ValueError:
                pass
    return None


class ShadowCheck(Check):
    """Use symbol information to check that no scope defines a name
    already known to a parent scope"""

    defineNone = Warning('Report any redefinition of None',
                         'Do not redefine None')
    shadowBuiltins = Warning('Report names that shadow builtins',
                            'Identifier (%s) shadows builtin', 0)
    shadowIdentifier = Warning('Report names already defined in outer scopes',
                               'Identifier (%s) shadows definition in scope %s')
    def check(self, file, unused_checker):
        # warn if any name defined in a scope is defined in a parent scope
        # or even the builtins
        for node, scope in file.not_class_scopes():
            for name in scope.defs:
                if name == 'None':
                    file.warning(scope.defs[name], self.defineNone)
                    continue
                if name in scope.globals:
                    continue
                if is_arg_and_defaulted_to_same_name(name, scope):
                    continue
                if _is_self(scope, name):
                    continue
                if __builtins__.has_key(name):
                    file.warning(scope.defs[name], self.shadowBuiltins, name)
                for p in parents(scope):
                    if p.defs.has_key(name) and \
                       not isinstance(p, symbols.ClassScope):
                        file.warning(scope.defs[name], \
                                     self.shadowIdentifier, name, `p`)

def _str_value(s):
    if type(s) == type(''):
        return eval(s)
    return s


def _empty_function(stmts):
    if not stmts:
        return 1
    stmt = stmts[0]
    # functions which only raise exceptions 
    if isinstance(stmt, ast.Raise):
        return 1
    # functions which do nothing 
    if len(stmts) == 1 and isinstance(stmt, ast.Pass):
        return 1
    # functions which just return a constant 
    if len(stmts) == 1 and \
       isinstance(stmt, ast.Return) and isinstance(stmt.value, ast.Const):
        return 1
    # functions which only assert falsehood 
    if isinstance(stmt, ast.Assert):
        if (isinstance(stmt.test, ast.Const) and not stmt.test.value) or \
            (isinstance(stmt.test, ast.Name) and stmt.test.name == 'None'):
            return 1
    return 0

class UnusedCheck(Check):
    """Use symbol information to check that no scope defines a name
    not used in this or any child scope"""

    unused = Warning('Report names not used', 'Identifier (%s) not used')

    def __init__(self):
        self.reportUnusedSelf = None
        self.unusedPrefixes = None

    def get_options(self, options):
        desc = 'Ignore unused identifiers that start with these values'
        default = ['unused', 'empty', 'dummy',
                   '__pychecker__', '__all__', '__version__', 'ignored']
        options.add(Opt(self, 'unusedPrefixes', desc, default))
        
        desc = 'Ignore unused method "self" parameter'
        options.add(BoolOpt(self, 'reportUnusedSelf', desc))

    def check(self, file, unused_checker):
        self.unusedPrefixes = _str_value(self.unusedPrefixes)

        def used(name, parent_scope):
            if parent_scope.uses.has_key(name):
                return 1
            for c in parent_scope.get_children():
                if used(name, c):
                    return 1
            return 0

        for nodes, scope in file.not_class_scopes():
            if isinstance(nodes, ast.Function):
                if _empty_function(nodes.code.nodes):
                    continue
            
            # ensure that every defined variable is used in some scope
            for var in scope.defs:
                # ignore '_'... just because
                if var == '_':
                    continue

                # check for method self
                if not self.reportUnusedSelf and _is_self(scope, var):
                    continue

                # ignore names in the root scope which are not imported:
                # class defs, function defs, variables, etc, unless
                # they start with '_'
                if scope == file.root_scope:
                    if not scope.imports.has_key(var):
                        if not var.startswith('_'):
                            continue

                for prefix in self.unusedPrefixes:
                    if var.startswith(prefix):
                        break
                else:
                    if not used(var, scope) and not scope.globals.has_key(var):
                        file.warning(scope.defs[var], self.unused, var)

def _importedName(scope, name):
    if scope.imports.has_key(name):
        return 1
    if scope.parent:
        return _importedName(scope.parent, name)
    return None

class UnknownCheck(Check):
    """Use symbol information to check that no scope uses a name
    not defined in a parent scope"""

    unknown = Warning('Report names that are not defined',
                      'Unknown identifier: %s')

    builtins = {}
    builtins.update(__builtins__)
    builtins['__builtins__'] = __builtins__
    builtins['WindowsError'] = getattr(__builtins__, 'WindowsError', None)

    def check(self, file, unused_checker):

        # if a name used is not found in the defined variables, complain
        for scope in file.scopes.values():
            unknown = dict_minus(scope.uses, scope.defs)
            unknown = dict_minus(unknown, self.builtins)
            for var in unknown:
                for p in parents(scope):
                    if p.defs.has_key(var):
                        break
                else:
                    if not _importedName(scope, var):
                        file.warning(scope.uses[var], self.unknown, var)

def _first_arg_defaulted(function_node):
    count = len(function_node.argnames)
    if function_node.varargs:
        count -= 1
    if function_node.kwargs:
        count -= 1
    if count > 0 and len(function_node.defaults) == count:
        return 1
    return None

class SelfCheck(Check):
    'Check for simple self parameter'
    
    selfName = Warning('Report any methods whose first argument is not self',
                       'First argument to method %s (%s) is not in %s')
    selfDefault = Warning('Report a self parameter with a default value',
                          'First argument to method %s (%s) has a default value')
    
    functionSelf = Warning('Report functions (not methods) with '
                           'arguments named "self"',
                           'Argument to function (%s) is "%s"')
    
    missingSelf = Warning('Report methods without "self"',
                          'Method %s is missing self parameter')
    
    def get_options(self, options):
        desc = 'Name of self parameter'
        default = ["self", "this", "s"]
        options.add(Opt(self, 'selfNames', desc, default))

        desc = 'Suspicious self parameters'
        self.selfSuspicious = ["self"]
        options.add(Opt(self, 'selfSuspicious', desc, self.selfSuspicious))

    def check(self, file, unused_checker):
        self.selfNames      = _str_value(self.selfNames)
        self.selfSuspicious = _str_value(self.selfSuspicious)

        for node, scope in file.function_scopes():
            args = node.argnames
            name = getattr(scope.node, 'name', 'lambda')
            if _is_method(scope):
                if not args:
                    file.warning(scope.node, self.missingSelf, name)
                else:
                    if args[0] not in self.selfNames:
                        file.warning(scope.node, self.selfName,
                                     name, args[0], `self.selfNames`)
                    if _first_arg_defaulted(scope.node):
                        file.warning(scope.node, self.selfDefault,
                                     name, args[0])
            else:
                for arg in args:
                    if arg in self.selfSuspicious:
                        file.warning(scope.defs[arg], self.functionSelf,
                                     name, arg)

                

class UnpackCheck(Check):
    'Mark all unpacked variables as used'

    def __init__(self):
        self.unpackedUsed = None

    def get_options(self, options):
        desc = 'Do not treat variables used in tuple assignment as used'
        options.add(BoolOpt(self, 'unpackedUsed', desc, 1))

    def check(self, file, unused_checker):
        if not self.unpackedUsed:
            return

        class Visitor:
            def visitAssTuple(self, node):
                for c in node.getChildNodes():
                    for n in parents(c):
                        try:
                            file.scopes[n].uses[c.name] = node
                            break
                        except (KeyError, AttributeError):
                            pass
            visitAssList = visitAssTuple

        # local args unpacked on the `def' line are used, too
        for scope_node, scope in file.function_scopes():
            for arg in type_filter(scope_node.argnames, tuple):
                for unpacked in ast.flatten(arg):
                    scope.uses[unpacked] = scope.uses.get(unpacked, scope_node)

        if file.root_scope:
            walk(file.root_scope.node, Visitor())

def intersect2(a, b):
    return [i for i in a if i in b]

def intersect(items):
    result = items[0]
    for item in items[1:]:
        result = intersect2(result, item)
    return result

class UsedBeforeSetCheck(Check):

    usedBeforeDefined = \
          Warning('Report variables that may be used before they are defined',
                  'The local %s may be used before defined')

    def check(self, file, unused_checker):
        class Visitor(BaseVisitor):
            def __init__(self, defines = None, uses = None):
                # list of vars defined
                self.defines = []
                # name->node vars used before defined                    
                self.uses = {}
                if defines is not None:
                    self.defines = defines[:]
                if uses is not None:
                    self.uses = uses.copy()
            def visitFunction(self, n):
                self.defines.append(n.name)
                
            visitClass = visitFunction
            visitAssName = visitFunction

            def visitGlobal(self, node):
                for name in node.names:
                    self.defines.append(name)
            
            def visitListComp(self, n):
                # visit qualifiers before expression
                children = ast.flatten_nodes(n.quals) + [n.expr]
                for c in children:
                    self.visit(c)
            
            def visitName(self, n):
                if n.name not in self.defines:
                    self.uses[n.name] = self.uses.get(n.name, n)

            def visitIf(self, n):
                if not n.else_:
                    return
                visits = []
                for test, code in n.tests:
                    visits.append(walk(code, Visitor(self.defines, self.uses)))
                visits.append(walk(n.else_, Visitor(self.defines, self.uses)))
                # compute the intersection of defines
                self.defines = intersect([v.defines for v in visits])
                # compute the union of uses, perserving first occurances
                union = {}
                visits.reverse()
                for v in visits:
                    union.update(v.uses)
                union.update(self.uses)
                self.uses = union
                        
        for node, scope in file.function_scopes():
            predefined = ast.flatten(scope.params) + scope.imports.keys()
            visitor = walk(node.code, Visitor(predefined))
            usedBefore = dict_intersect(visitor.uses, scope.defs)
            for name, use_node in usedBefore.items():
                file.warning(use_node, self.usedBeforeDefined, name)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.