Ticket #2718: unused-in-function-2718-3.diff

File unused-in-function-2718-3.diff, 13.1 kB (added by jml, 1 year ago)

New diff with style changes.

  • pyflakes/checker.py

    old new  
    88from pyflakes import messages 
    99 
    1010 
     11 
    1112class Binding(object): 
    1213    """ 
     14    Represents the binding of a value to a name. 
     15 
     16    The checker uses this to keep track of which names have been bound and 
     17    which names have not. See L{Assignment} for a special type of binding that 
     18    is checked with stricter rules. 
     19 
    1320    @ivar used: pair of (L{Scope}, line-number) indicating the scope and 
    1421                line number that this binding was last used 
    1522    """ 
     23 
    1624    def __init__(self, name, source): 
    1725        self.name = name 
    1826        self.source = source 
    1927        self.used = False 
    2028 
     29 
    2130    def __str__(self): 
    2231        return self.name 
    2332 
     33 
    2434    def __repr__(self): 
    2535        return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__, 
    2636                                                        self.name, 
    2737                                                        self.source.lineno, 
    2838                                                        id(self)) 
    2939 
     40 
     41 
    3042class UnBinding(Binding): 
    3143    '''Created by the 'del' operator.''' 
    3244 
     
    3547        name = name.split('.')[0] 
    3648        super(Importation, self).__init__(name, source) 
    3749 
     50 
     51 
     52class Argument(Binding): 
     53    """ 
     54    Represents binding a name as an argument. 
     55    """ 
     56 
     57 
     58 
    3859class Assignment(Binding): 
    39     pass 
     60    """ 
     61    Represents binding a name with an explicit assignment. 
     62 
     63    The checker will raise warnings for any Assignment that isn't used. Also, 
     64    the checker does not consider assignments in tuple/list unpacking to be 
     65    Assignments, rather it treats them as simple Bindings. 
     66    """ 
     67 
     68 
    4069 
    4170class FunctionDefinition(Binding): 
    4271    pass 
    4372 
    4473 
     74 
    4575class Scope(dict): 
    4676    importStarred = False       # set to True when import * is found 
    4777 
     78 
    4879    def __repr__(self): 
    4980        return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self)) 
    5081 
     82 
    5183    def __init__(self): 
    5284        super(Scope, self).__init__() 
    5385 
     86 
     87 
    5488class ClassScope(Scope): 
    5589    pass 
    5690 
     
    72106    pass 
    73107 
    74108 
     109 
    75110class Checker(object): 
    76111    nodeDepth = 0 
    77112    traceTree = False 
    78113 
    79114    def __init__(self, tree, filename='(none)'): 
    80         self.deferred = [] 
     115        self._deferredFunctions = [] 
     116        self._deferredAssignments = [] 
    81117        self.dead_scopes = [] 
    82118        self.messages = [] 
    83119        self.filename = filename 
    84120        self.scopeStack = [ModuleScope()] 
    85121        self.futuresAllowed = True 
    86  
    87122        self.handleChildren(tree) 
    88         for handler, scope in self.deferred: 
    89             self.scopeStack = scope 
    90             handler() 
     123        self._runDeferred(self._deferredFunctions) 
     124        self._runDeferred(self._deferredAssignments) 
    91125        del self.scopeStack[1:] 
    92126        self.popScope() 
    93127        self.check_dead_scopes() 
    94128 
    95     def defer(self, callable): 
    96         '''Schedule something to be called after just before completion. 
     129 
     130    def deferFunction(self, callable): 
     131        ''' 
     132        Schedule a function handler to be called after just before completion. 
    97133 
    98134        This is used for handling function bodies, which must be deferred 
    99135        because code later in the file might modify the global scope. When 
    100136        `callable` is called, the scope at the time this is called will be 
    101137        restored, however it will contain any new bindings added to it. 
    102138        ''' 
    103         self.deferred.append( (callable, self.scopeStack[:]) ) 
     139        self._deferredFunctions.append((callable, self.scopeStack[:])) 
     140 
     141 
     142    def deferAssignment(self, callable): 
     143        """ 
     144        Schedule an assignment handler to be called after just before 
     145        completion. 
     146        """ 
     147        self._deferredAssignments.append((callable, self.scopeStack[:])) 
     148 
     149 
     150    def _runDeferred(self, deferred): 
     151        """ 
     152        Run the callables in C{deferred} using their associated scope stack. 
     153        """ 
     154        for handler, scope in deferred: 
     155            self.scopeStack = scope 
     156            handler() 
     157 
    104158 
    105159    def scope(self): 
    106160        return self.scopeStack[-1] 
     
    126180 
    127181    def handleChildren(self, tree): 
    128182        for node in tree.getChildNodes(): 
    129             self.handleNode(node
     183            self.handleNode(node, tree
    130184 
    131     def handleNode(self, node): 
     185    def handleNode(self, node, parent=None): 
     186        node.parent = parent 
    132187        if self.traceTree: 
    133188            print '  ' * self.nodeDepth + node.__class__.__name__ 
    134189        self.nodeDepth += 1 
     
    226281 
    227282    def LISTCOMP(self, node): 
    228283        for qual in node.quals: 
    229             self.handleNode(qual
    230         self.handleNode(node.expr
     284            self.handleNode(qual, node
     285        self.handleNode(node.expr, node
    231286 
    232287    GENEXPRINNER = LISTCOMP 
    233288 
     
    299354 
    300355    def LAMBDA(self, node): 
    301356        for default in node.defaults: 
    302             self.handleNode(default
     357            self.handleNode(default, node
    303358 
    304359        def runFunction(): 
    305360            args = [] 
     
    316371            self.pushFunctionScope() 
    317372            addArgs(node.argnames) 
    318373            for name in args: 
    319                 self.addBinding(node.lineno, Assignment(name, node), reportRedef=False) 
    320             self.handleNode(node.code) 
     374                self.addBinding(node.lineno, Argument(name, node), reportRedef=False) 
     375            self.handleNode(node.code, node) 
     376            def checkUnusedAssignments(): 
     377                """ 
     378                Check to see if any assignments have not been used. 
     379                """ 
     380                for name, binding in self.scope.iteritems(): 
     381                    if (not binding.used and not name in self.scope.globals 
     382                        and isinstance(binding, Assignment)): 
     383                        self.report(messages.UnusedVariable, 
     384                                    binding.source.lineno, name) 
     385            self.deferAssignment(checkUnusedAssignments) 
    321386            self.popScope() 
    322387 
    323         self.defer(runFunction) 
     388        self.deferFunction(runFunction) 
    324389 
    325390    def CLASS(self, node): 
    326         self.addBinding(node.lineno, Assignment(node.name, node)) 
     391        self.addBinding(node.lineno, Binding(node.name, node)) 
    327392        for baseNode in node.bases: 
    328             self.handleNode(baseNode
     393            self.handleNode(baseNode, node
    329394        self.pushClassScope() 
    330395        self.handleChildren(node.code) 
    331396        self.popScope() 
     
    357422                                    scope[node.name].source.lineno) 
    358423                        break 
    359424 
    360             self.addBinding(node.lineno, Assignment(node.name, node)) 
     425            if isinstance(node.parent, 
     426                          (ast.For, ast.ListCompFor, ast.GenExprFor, 
     427                           ast.AssTuple, ast.AssList)): 
     428                binding = Binding(node.name, node) 
     429            else: 
     430                binding = Assignment(node.name, node) 
     431            if node.name in self.scope: 
     432                binding.used = self.scope[node.name].used 
     433            self.addBinding(node.lineno, binding) 
    361434 
    362435    def ASSIGN(self, node): 
    363         self.handleNode(node.expr
     436        self.handleNode(node.expr, node
    364437        for subnode in node.nodes[::-1]: 
    365             self.handleNode(subnode
     438            self.handleNode(subnode, node
    366439 
    367440    def IMPORT(self, node): 
    368441        for name, alias in node.names: 
  • pyflakes/messages.py

    old new  
    7171    def __init__(self, filename, lineno, names): 
    7272        Message.__init__(self, filename, lineno) 
    7373        self.message_args = (names,) 
     74 
     75 
     76class UnusedVariable(Message): 
     77    """ 
     78    Indicates that a variable has been explicity assigned to but not actually 
     79    used. 
     80    """ 
     81 
     82    message = 'local variable %r is assigned to but never used' 
     83    def __init__(self, filename, lineno, names): 
     84        Message.__init__(self, filename, lineno) 
     85        self.message_args = (names,) 
  • pyflakes/test/test_imports.py

    old new  
    401401        import fu 
    402402        def a(): 
    403403            fu = 3 
     404            return fu 
    404405        fu 
    405406        ''') 
    406407 
  • pyflakes/test/test_other.py

    old new  
    7575 
    7676 
    7777 
     78class TestUnusedAssignment(harness.Test): 
     79    """ 
     80    Tests for warning about unused assignments. 
     81    """ 
     82 
     83    def test_unusedVariable(self): 
     84        """ 
     85        Warn when a variable in a function is assigned a value that's never 
     86        used. 
     87        """ 
     88        self.flakes(''' 
     89        def a(): 
     90            b = 1 
     91        ''', m.UnusedVariable) 
     92 
     93 
     94    def test_assignToGlobal(self): 
     95        """ 
     96        Assigning to a global and then not using that global is perfectly 
     97        acceptable. Do not mistake it for an unused local variable. 
     98        """ 
     99        self.flakes(''' 
     100        b = 0 
     101        def a(): 
     102            global b 
     103            b = 1 
     104        ''') 
     105 
     106 
     107    def test_assignToMember(self): 
     108        """ 
     109        Assigning to a member of another object and then not using that member 
     110        variable is perfectly acceptable. Do not mistake it for an unused 
     111        local variable. 
     112        """ 
     113        # XXX: Adding this test didn't generate a failure. Maybe not 
     114        # necessary? 
     115        self.flakes(''' 
     116        class b: 
     117            pass 
     118        def a(): 
     119            b.foo = 1 
     120        ''') 
     121 
     122 
     123    def test_assignInForLoop(self): 
     124        """ 
     125        Don't warn when a variable in a for loop is assigned to but not used. 
     126        """ 
     127        self.flakes(''' 
     128        def f(): 
     129            for i in range(10): 
     130                pass 
     131        ''') 
     132 
     133 
     134    def test_assignInListComprehension(self): 
     135        """ 
     136        Don't warn when a variable in a for loop is assigned to but not used. 
     137        """ 
     138        self.flakes(''' 
     139        def f(): 
     140            [None for i in range(10)] 
     141        ''') 
     142 
     143 
     144    def test_generatorComprehension(self): 
     145        """ 
     146        Don't warn when a variable in a for loop is assigned to but not used. 
     147        """ 
     148        self.flakes(''' 
     149        def f(): 
     150            (None for i in range(10)) 
     151        ''') 
     152 
     153 
     154    def test_assignmentInsideLoop(self): 
     155        """ 
     156        Don't warn when a variable assignment occurs lexically after its use. 
     157        """ 
     158        self.flakes(''' 
     159        def f(): 
     160            x = None 
     161            for i in range(10): 
     162                if i > 2: 
     163                    return x 
     164                x = i * 2 
     165        ''') 
     166 
     167 
     168    def test_tupleUnpacking(self): 
     169        """ 
     170        Don't warn when a variable included in tuple unpacking is unused. It's 
     171        very common for variables in a tuple unpacking assignment to be unused 
     172        in good Python code, so warning will only create false positives. 
     173        """ 
     174        self.flakes(''' 
     175        def f(): 
     176            (x, y) = 1, 2 
     177        ''') 
     178 
     179 
     180    def test_listUnpacking(self): 
     181        """ 
     182        Don't warn when a variable included in list unpacking is unused. 
     183        """ 
     184        self.flakes(''' 
     185        def f(): 
     186            [x, y] = [1, 2] 
     187        ''') 
     188 
     189 
     190    def test_closedOver(self): 
     191        """ 
     192        Don't warn when the assignment is used in an inner function. 
     193        """ 
     194        self.flakes(''' 
     195        def barMaker(): 
     196            foo = 5 
     197            def bar(): 
     198                return foo 
     199            return bar 
     200        ''') 
     201 
     202 
     203    def test_doubleClosedOver(self): 
     204        """ 
     205        Don't warn when the assignment is used in an inner function, even if 
     206        that inner function itself is in an inner function. 
     207        """ 
     208        self.flakes(''' 
     209        def barMaker(): 
     210            foo = 5 
     211            def bar(): 
     212                def baz(): 
     213                    return foo 
     214            return bar 
     215        ''') 
     216 
     217 
     218 
    78219class Python25Test(harness.Test): 
    79220    """ 
    80221    Tests for checking of syntax only available in Python 2.5 and newer. 
  • pyflakes/test/test_undefined_names.py

    old new  
    9191        def fun(): 
    9292            a 
    9393            a = 2 
     94            return a 
    9495        ''', m.UndefinedLocal) 
    9596 
    9697    def test_laterRedefinedGlobalFromNestedScope2(self): 
     
    106107                def fun2(): 
    107108                    a 
    108109                    a = 2 
     110                    return a 
    109111        ''', m.UndefinedLocal) 
    110112 
    111113 
     
    124126                    def c(): 
    125127                        x 
    126128                        x = 3 
     129                        return x 
     130                    return x 
     131                return x 
    127132        ''', m.UndefinedLocal).messages[0] 
    128133        self.assertEqual(exc.message_args, ('x', 5)) 
    129134 
     
    139144                def fun2(): 
    140145                    a 
    141146                    a = 1 
     147                    return a 
     148                return a 
    142149        ''', m.UndefinedLocal) 
    143150 
    144151    def test_nestedClass(self): 
     
    161168            class C: 
    162169                bar = foo 
    163170            foo = 456 
    164  
     171            return foo 
    165172        f() 
    166173        ''', m.UndefinedName) 
    167174 
jethro@divmod.org