[matplotlib-devel] Possible bug in matplotlib.cbook.CallbackRegistry

2011-10-17 Thread tobin
Within matplotlib.cbook.CallbackRegistry both the connect() and process() 
methods check for dead references when called.  If a reference is dead it 
deletes it from the callback list.

I have found a situation where this presents a problem.

First, a "button_press_event" calls the process method() which begins a loop 
over all of the callback items for this event. One of these items is a dead 
reference but appears late in the list.  The first callback within the loop 
creates a new connection and calls the connect method.  During this connect 
call the dead reference is deleted from the callback list.  Then when it gets 
back to the loop within the process method the callback no longer exists in the 
list it is iterating over and there is an error thrown when it tries to delete 
the dead reference for the second time.

The problem is coordination between these two places that both could 
potentially delete a dead reference to a BoundMethodProxy.  In my case, because 
one loop has started ... the attempt is made twice ... and obviously the second 
results in an error.

I could put together a simple example if needed to demonstrate the error.

I think the easy way to handle would be to first call a method who's job is 
only to delete dead references.  Then each method could call this first before 
handling the callbacks.  This would keep the intermingling of the two loops 
that both check for dead references.

Another (potentially more obscure approach) could be to just wrap the delete 
with a try/except - but this suffers from not fixing a bit of a design problem.

There are likely more approaches to solving.



--
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense.
http://p.sf.net/sfu/splunk-d2d-oct
___
Matplotlib-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel


Re: [matplotlib-devel] Possible bug in matplotlib.cbook.CallbackRegistry

2011-10-25 Thread tobin
Here is a bit more detail and a simple example.

The example below places red squares in an axes.  When the user clicks on an 
existing red square - another square is created and added. When the user hits 
any key a square is deleted from the axes.  The error is triggered by clicking 
on the red square and then hitting any key, and then clicking a red square 
again.

Diagnosis:
By monitoring cbook.py line 235 and cbook.py line 263 it can be seen that after 
the second mouse click (following one of the squares being deleted), that the 
process() function builds a loop and begins handling the button press 
callbacks.  Note that there is a dead reference coming later in this list.  The 
first callback involves another square being created and the connect() method 
being called.  In the connect() call - the dead reference is deleted from the 
callback list.  Now upon returning to the process() callback this dead 
reference is no longer in the callback list and a Key Exception is triggered 
once it gets to it in the loop.

Problem:
There are two locations where dead references are cleared from the callback 
list.  When these loops get intermingled - as the case with a callback leading 
to another connect mid-loop - the exception occurs when both loops attempt to 
delete the dead reference.

Possible Solutions:
1. Trap the KeyException at the point of attempting to delete it from the list 
in both places.

2. Place the dead reference check and deletion within a single method ... and 
perform this check at beginning of the process() and connect() methods before 
processing callbacks.


Sample Code


import matplotlib
matplotlib.use('WXAGG')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.pyplot import Figure, Axes, Rectangle

import wx
import random

class SquareManager(object):
def __init__(self, axes):
self.axes = axes
self.canvas = axes.figure.canvas 
self.squares = []
self.last_x = 0

self.canvas.mpl_connect('key_press_event', self.on_key_press)

def add_square(self):
self.last_x += .1
s = Square(self, self.axes, [self.last_x, .4],
   .05, .05, facecolor='red', edgecolor='black')
self.squares.append(s)
self._refresh()

def on_key_press(self, evt):
if len(self.squares) == 0: return

# delete the first square - results in no error
# self.squares[0].remove()
# del self.squares[0]

# delete the last square - results in the error
self.squares[-1].remove()
del self.squares[-1]

self._refresh()

def _refresh(self):
self.canvas.draw()


class Square(Rectangle):
def __init__(self, manager, axes, *args, **kwds):
Rectangle.__init__(self, *args, **kwds)
axes.add_patch(self)

self.manager = manager
axes.figure.canvas.mpl_connect('button_press_event', self.selected)

def selected(self, evt):
within, _ = self.contains(evt)
if within:
self.manager.add_square()


app = wx.PySimpleApp()
frame = wx.Frame(None)
fig = Figure()
canvas = FigureCanvasWxAgg(frame, -1, fig)
a = Axes(fig, [.1, .1, .8, .8])
fig.add_axes(a)

sm = SquareManager(a)
sm.add_square()

frame.Show()
app.MainLoop()


# To demonstrate the error:
#
# 1. click on red sqaure
# 2. press any key
# 3. click on red sqaure again



 





--
The demand for IT networking professionals continues to grow, and the
demand for specialized networking skills is growing even more rapidly.
Take a complimentary Learning@Cisco Self-Assessment and learn 
about Cisco certifications, training, and career opportunities. 
http://p.sf.net/sfu/cisco-dev2dev
___
Matplotlib-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel


Re: [matplotlib-devel] Possible bug in matplotlib.cbook.CallbackRegistry

2011-10-25 Thread Tobin H. Van Pelt

Daniel -

Yes that works.  In my case - I hate to edit any existing third party  
code bases - or it bites me later when I upgrade.


For now - I simply do my own dead reference clean up externally when  
doing the deletes. Really, that would be the same as just doing a  
disconnect - but for other reasons (not worth going into detail here)  
- I prefer deleting and not having to know all of the connection  
points.  My solution ensures that the dead references aren't around  
later.


I mainly wanted to get it out into the devel community - get smart  
eyeballs on it - and hope that it gets addresses in a future release.


It will likely be a fairly straightforward fix - as you show.


--
The demand for IT networking professionals continues to grow, and the
demand for specialized networking skills is growing even more rapidly.
Take a complimentary Learning@Cisco Self-Assessment and learn 
about Cisco certifications, training, and career opportunities. 
http://p.sf.net/sfu/cisco-dev2dev___
Matplotlib-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel