This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: sys.settrace cause curried parms to show up as attributes
Type: Stage:
Components: Interpreter Core Versions: Python 2.6
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: loewis Nosy List: exarkun, georg.brandl, jhylton, josiahcarlson, jpe, loewis, scott_marks
Priority: normal Keywords:

Created on 2006-10-02 15:26 by scott_marks, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
tracing_bug.py scott_marks, 2006-10-02 15:58
Messages (13)
msg30109 - (view) Author: applebucks (scott_marks) Date: 2006-10-02 15:26
The code below exhibits different behavior depending on
whether it invokes sys.settrace ('-t' option) or not. 
This means that (in a more complicated case) debugging
the code (which uses sys.settrace) makes it fail. 
Reported v 2.4, but the same behavior on 2.5.  Any ideas?

""" Demonstrace that tracing messes up curried class
definitions """

# Some simple command line parsing: -t or --trace means
trace, nothing means don't trace
import sys

def usage( ):
    print 'Usage:', sys.argv[ 0 ], '[-t | --trace]'
    sys.exit( 1 )

if 1 == len( sys.argv ):
    pass
elif 2 == len( sys.argv ):
    if sys.argv[ 1 ]=='-t' or sys.argv[ 1 ]=='--trace':
        def trace ( frame, event, arg ):
            # print frame, event, arg
            return trace
        sys.settrace( trace )
    else:
        usage( )
else:
    usage( )



# The test: define a class factory with a curried
member function

def the_factory( parm1 ):
    class the_class( object ):
        def curried( self ): return parm1
    return the_class

x = the_factory( 42 )

y = x( )

try:
    x.parm1
    print "Failure: x (the manufactured class) has
attribute parm1?!"
except AttributeError:
    print "Success with the manufactured class!"

try:
    y.parm1
    print "Failure: y (the instance) has attribute parm1?!"
except AttributeError:
    print "Success with the instance!"

assert y.curried( ) == 42, "Currying didn't work?!" 
msg30110 - (view) Author: applebucks (scott_marks) Date: 2006-10-02 16:02
Logged In: YES 
user_id=120857

This bug actually causes a failure in a system that heavily
uses function-level programming and member delegation.  The
bug occurred when a class factory function formal parameter
name was the same as a field delegated by instances of the
generated class to a member -- when run in a debugger (i.e.
after a non-None call to sys.settrace) the delegating
descriptor was over-written by the value of the factory
function parameter.
msg30111 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2006-10-03 06:49
Logged In: YES 
user_id=849994

I'm afraid that this cannot be fixed.

In normal execution, the variable "parm1" is stored by the
compiler in the "fast locals" (that are referenced by index
into a list) for the function that is used to build the
class, which means that it is not in the dict of "normal
locals" (that are referenced by their name in the dict) that
is returned at the end.

If you set a trace function, on each call to the trace
function the "fast locals" are merged into the "normal
locals" in order to give the trace function full control
over the execution frame. This means that after the trace
function has been executed for the class' frame, the locals
will contain "parm1" which will then show up as an attribute
of that class.

Martin, do you you have an additional opinion?
msg30112 - (view) Author: applebucks (scott_marks) Date: 2006-10-04 02:32
Logged In: YES 
user_id=120857

"Cannot be fixed" sounds pretty final, and also a little
pessimistic.  From your description, it seems that the
correct functionality could be maintained at the cost of
retention of the keys in "normal locals" and dissection back
into "fast locals" and "normal locals" after the trace
function does ... whatever it does.  In particular, it seems
unacceptable that the invariants of the semantics of class
creation (on which introspection and other important
functionality depends) is borked by debugging in such a way
as to render quite misleading the process of debugging code
that depends on those invariants.

Not to mention that the workaround ("be sure to rename your
class factory function parameters so that they don't collide
with intended attributes of the created class") just makes
Python seem ... lame.

I hope for a more optimistic reply.
msg30113 - (view) Author: Josiah Carlson (josiahcarlson) * (Python triager) Date: 2006-10-07 16:54
Logged In: YES 
user_id=341410

I'm not going to comment on the internals, because I don't
know enough about them to make a positive comment, but it
seems to me that your statement of:

..."just makes Python seem ... lame."

is insulting to those who have helped to develop Python over
the years.  In my experience attempting to help, the surest
way of not getting what you want is to insult those who have
developed Python (nevermind that according to the lack of
bugs on the topic, very few people want/need the
functionality you expect).
msg30114 - (view) Author: applebucks (scott_marks) Date: 2006-10-08 23:54
Logged In: YES 
user_id=120857

I didn't say Python is lame.  I use Python heavily,
apparently an uncommonly large subset of Python
functionality at that, and largely love it.  That's why the
failure of semantic transparency caused by something
apparently irrelevant (tracing, as opposed to some kind of
deliberate stack frame munging) is disturbing.  

Not to mention it makes my debugging tough. :)

More seriously, one of the users of the subsystem in which
this bug shows us just (on Friday) lost a few hours chasing
a real bug that should have been obvious but which was
masked by this error as manifest by a bdb-based debugger.
msg30115 - (view) Author: John Ehresman (jpe) * Date: 2006-10-30 16:53
Logged In: YES 
user_id=22785

This could & probably should be fixed, at the cost of making
the core debugger support more complicated.  The current
version of TurboGears has code that triggers the same bug. 
That said, I don't have a patch to fix the core...
msg30116 - (view) Author: Jean-Paul Calderone (exarkun) * (Python committer) Date: 2007-02-25 18:21
Code coverage tools run afoul
msg30117 - (view) Author: Jean-Paul Calderone (exarkun) * (Python committer) Date: 2007-02-25 18:23
Ahem.

Code coverage tools run afoul of this bug as well.  A common case is to run coverage tools using a test suite.  If this bug is triggered, then the resulting coverage data isn't valid.
msg30118 - (view) Author: Jeremy Hylton (jhylton) (Python triager) Date: 2007-02-26 18:41
Fixed in rev. 53954.  Not sure if this should be backported.
msg77084 - (view) Author: Jean-Paul Calderone (exarkun) * (Python committer) Date: 2008-12-05 22:50
It would be great if this could be backported.
msg77101 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2008-12-06 08:05
Assigning to the 2.4/2.5 RM.
msg77107 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2008-12-06 09:45
Because of the incompatibility in locals(), this patch cannot be backported.
History
Date User Action Args
2022-04-11 14:56:20adminsetgithub: 44067
2008-12-06 09:45:52loewissetmessages: + msg77107
versions: + Python 2.6, - Python 2.4
2008-12-06 08:05:01georg.brandlsetassignee: jhylton -> loewis
messages: + msg77101
nosy: + loewis
2008-12-05 22:50:09exarkunsetmessages: + msg77084
2006-10-02 15:26:21scott_markscreate