help: Unit test fixture returning the same object

Michael McCracken mmccrack at gradlab.ucsd.edu
Wed Aug 4 21:25:47 CEST 2004


Roy Smith <roy at panix.com> writes:

> michael_mccracken at mac.com (Michael McCracken) wrote:
> > So, I'm still surprised that id() would point to the same object every
> > time, but I'm willing to believe it. However, I don't think that's the
> > only thing that's going on - the reason I noticed this in the first
> > place is that the setUp method was opening a file and populating some
> > lists in my File object, and those lists were accumulating objects
> > between test methods.
> 
> My first guess would be that you're using class variables instead of 
> instance variables, but you say:
> 
> > I don't think I'm accidentally using class variables
> 
> so I'm stumped.  Can you post your code?

I managed to fix my problem, but I don't understand why the fix works
yet, so I'm not quite satisfied.

I am trying to narrow it down so I can post more informatively.

So far my attempts at making a minimal example don't exhibit the same
problem.  While I'm trying to get the smallest example with the
problem, I will describe what happened and how I 'fixed' it.

The File id() was indeed a red herring. 

The problem was that in __init__, File reads a bunch of stuff (in XML
using libxml2) and populates some internal lists. The one that had the
problem was a list of Modules, which has a list of Procedures which
has a list of Blocks. Each Block has predecessors and successors.

Block looks like this:

class Block:
    def __init__(self, name, preds = [], succs = []):
        self.name = name
        
        self.predecessors = preds
        self.successors = succs
        self.metrics = []
        
        for pred in self.predecessors:
            pred.addSuccessor(self)
        for succ in self.successors:
            succ.addPredecessor(self)

	# add* just append to the lists, avoiding cycles.

    def __repr__(self):
	s = "{%d -> %s (0x%d) -> %d (%d)}" %\
            (len(self.predecessors), self.name,\
	     id(self), len(self.successors), 
             len(self.metrics))
        return s

In File, Blocks are created in a method that gets called as we're
parsing out the Procedures and Modules. I make a new Block with empty
preds and succs initially, then link them up after they're all
created:

in File.py:

    def blockForXMLNode(self, n):
        name = safeGetAttribute(n, "label", xlinkNSURI)
        # this is called during the first pass, can't link up yet
        preds = []
        succs = []
        block = Block.Block(name)# preds, succs)
	print 'DEBUG: Making new block: ', block

The problem: if I run it as is, I get this output:
(During the first testCase:)
DEBUG: Making new block:  {0 -> no_exit.1 (0x2714520) -> 0 (0)}
DEBUG: Making new block:  {0 -> loopexit.1 (0x2714840) -> 0 (0)}
DEBUG: Making new block:  {0 -> loopexit.0 (0x2715000) -> 0 (0)}
(During the next testCase:)
DEBUG: Making new block:  {3 -> no_exit.1 (0x2735080) -> 5 (0)}
DEBUG: Making new block:  {4 -> loopexit.1 (0x2735400) -> 6 (0)}
DEBUG: Making new block:  {5 -> loopexit.0 (0x2735560) -> 7 (0)}
(and so on...)

So it does look like a class variable vs. instance variable problem,
but I can't say why. The fix is to uncomment the "# preds, succs)" and
pass in those empty lists to the Block constructor. That gives the
expected results, but I can't explain the difference.

-mike


-- 



More information about the Python-list mailing list