Python bug? Named parameters in recursive calls sometimes confuses python?

Magnus Lyck? magnus at thinkware.se
Fri Nov 28 18:07:13 CET 2003


Michael Hudson <mwh at python.net> wrote in message news:<m3ad6gww80.fsf at pc150.maths.bris.ac.uk>...
> magnus at thinkware.se (Magnus Lyck?) writes:
> 
> Isn't it possible that the code has just returned twice?

I don't know... But in that case, we have accidentally
retained the value of "column" which we had one step
down in the recursion, instead of reverting to the object
which is bound to the local variable at this level. Still
a Python bug!

I wrote:
> 2. Column G46_ANSTID (10002728) Table TGLON (10002512)
> 3. Column G46_ANSTID (10002728) Table TGANST (9282768)  <= N.B. 

As you can see below, the variables passed in to recursiveCopy
as column and table are reassigned together, in:
"for child_table, column in self.getDepTables(..."
getDepTables returns data it gets directly from SQL queries,
so it should never return a value which is passed in, and
either way, in my case it's table that changes while column
stays the same. (Are unicode objects interned?) Anyway,
there is no way that the database could return the
combination G46_ANSTID / TGANST.

G46_ANSTID belongs with TGLON, and TGLON is dependant on
TGANST. *IF* we simply returned from the recursive call to 
the previous level, column should be G06_PERS_INTRID (9282024),
just as it was before, when table was TGANST (9282768).

Column and table are reassigned together. If one of them changes
while the other doesn't, there is something wrong!

It happens here:

    def recursiveCopy(self, table, column, old_val, new_val):
        # Fetch row from source database
        print "1. Column %s (%i) Table %s (%i)" % (column, id(column), 
                                                   table, id(table))

        sql = "SELECT * FROM %(schema)s.%(table)s WHERE %(column)s = ?"
        rows = self.src_fetch(sql, params=(old_val,), table=table,
                              column=column)
               # I use "sql % kwargs" in a method called by src_fetch

        print "2. Column %s (%i) Table %s (%i)" % (column, id(column), 
                                                   table, id(table))

        for row in rows:
            # Replace foreign key with value for target DB

            print "3. Column %s (%i) Table %s (%i)" % (column, id(column), 
                                                       table, id(table))

            row[column] = new_val  # <= This is where it crashes.
            # What's interesting is the print above before the crash.
            # row is a db_row.IMetaRow instance instance.

            # We need primary key values for recursive find
            # Only bother for table with a single p.k.
            parent_p_key_cols = self.getPK(table)
            if len(parent_p_key_cols) == 1:
                parent_p_key_col = parent_p_key_cols[0]
                oldId = row[parent_p_key_col]
                newId = self.insertIntoTarget(table, row)
                for child_table, column in self.getDepTables(table,
                                                             parent_p_key_col):
                    self.recursiveCopy(child_table, column, oldId, newId)

> Unless you can produce an example that can be run somewhere other than
> your setup, it's going to be pretty hard for someone else to debug
> this!

I realize that... :) I was hoping that someone else
had seen something similar. Unfortunately I'm not even
at liberty to publish the code I write now... The bug
only appears for particular data (but it occurred twice,
on different computers) and the program assumes a certain
database etc. I doubt that I'll be able to reproduce it
in a small package, and it wouldn't surprise me if it's
an NT 4 specific bug. (Not a lot of users on that old
platform I guess...)

Assuming I have understood what the problem is, the
relevant parts of the code looks something like this:

class X:
    def fetch(self, sql, params, **kwargs):
        ...
        cursor.execute(sql % kwargs, params)
        return a list of db_row objects from cursor.fetchall()

    def recCopy(self, table, column, ...):
        sql = '...'
        rows = self.fetch(sql, params=(...), table=table, column=column)
        for row in rows:
            ...
            for child_table, foreign_key_col in getDependantTables(table):
                self.recCopy(child_table, foreign_key_col , ...)

In the middle of one call of recCopy, a local variable seems to be
rebound. The suspects are:
 * Recursion?
 * Named parameters, especially "x=x"?
 * Unicode objects?
 * Something in win32all/adodbapi?
 * Something in db_row? Metaclasses? (It's the pure Python version 0.8)
 * Windows NT 4.0 SP 6?
 * Just me?

Can anyone suggest a way to go forward here? I have found ways
to avoid the problem, but there seems to be a sinister Python 
bug lurking here and I would like to help bring it to the surface. 

Can I see what recursion depth I'm currently at? I have never
used the more arcane powers of Python introspection such as the
inspect module etc.




More information about the Python-list mailing list