Sunday, June 18, 2006

Chasing an unseen bug

A few days ago I was contacted by M.H., a professor in the U.S. who teaches Introduction to Computer Programming every year and was thinking of using RUR-PLE. [Great, I thought, more user feedback to be expected.] Unfortunately, M.H. had tried the latest version and found that the code highlighting feature [described in this post] did not work.

How could I possibly find a bug that I can not reproduce? I thought... Thus began an exchange of emails that led me to find a way to reproduce the bug and, eventually, to solve it. The final solution was somewhat typical of my experience with Python: try the obvious!

These last three words are probably the best words of advice I could give to anyone who writes computer programs using Python. If you are reading this blog as a potential source of useful tips [you fool!], you should probably stop now as nothing else I will write is likely to come even close to being as useful to you.

However, if you want to get a good laugh at my expense, you are invited to continue reading.

I first started by asking M.H. what everyone always asks me when I claim to find a bug or when I don't understand the behaviour of some module and post some question on various lists.

What OS and what version of wxPython are you using?

I expected that M.H. was using Mac OS or Linux, in which case I was getting ready to diplomatically tell him that he was likely out of luck as I'm [shame on me], a Windows user. However, M.H. told me that he was using Win XP (same here), Python 2.4.3 (I'm using 2.4.2) and wxPython 2.6 (same here).

Ok. I was more stumped then ever. This was bugging me... These days, I'm working on Crunchy Frog which will, eventually, include and supersede RUR-PLE. As it is, I have a lot more ideas than time at my disposal to work on Crunchy Frog, and this "distraction" was not welcome. However, I could not ignore it.

Since I couldn't reproduce the bug, I asked M.H. if he could do me a favour and insert a print statement in the method where the line number was set for the purpose of highlighting. As I wrote the email, I had a "clever" thought. M.H. is in the U.S. He's probably using the ansi version of wxPython whereas I'm using the unicode version. I bet you something's wrong with that version... Sure enough, my first hunch was right: M.H. was using the ansi version. And the print statement was outputting the same result on his computer as it was on mine. So, if one hunch was right... I asked M.H. to install the wxPython unicode version, which he kindly agreed to.

Same result... Of course, you are no doubt thinking. However, you are not trying to quash a bug you can't even reproduce. [That's my excuse, anyway.]

At that time I was visiting my partner who, unfortunately, lives 300 km (200 mi) from where I live. Fortunately, she is extremely patient and puts up with me when I am distracted by a programming problem. I decided to install wxPython and the latest version of RUR-PLE on her computer to investigate some more.

Ooops... wxPython is now at version I am sure the version installed on my computer is I read over the "changes" document to see if I can find anything that I can use. There does not appear to be anything relevant. I install the new version ... sure enough, I can "see" the bug (or, should I say, I can't see anything as no highlighting is taking place).

I read the "changes" document a second (and third) time, just to be sure. No luck.

Time to dig in my code. [... Where is this object initialised?... This could have been written so much better... What was I thinking then (about a year ago)... ] After staring at the code for a while, being convinced that the highlighting information is properly set (it was working before, after all) I am convinced it is a wxPython bug that was introduced. I file a bug report and expect to leave it at that.

However, my conscience is nagging me. I decide to look at the code again, staring at the method where the highlighting updates should take place. Here it is, with a few added notes.
def update_refresh(self, robot, name):
if 'robot' in self.robot_dict: # (1)
arg = self.parent.status_bar.beeper_field, self.robot_dict['robot']._beeper_bag
event_manager.SendCustomEvent(self.parent, arg)
time.sleep(robot.delay) # (2)
wx.Yield() # (3) #(4)
self.WorldDisplay.drawImage() #(5)
if name:
self.WorldDisplay.scrollWorld(name) # (6)
self.WorldDisplay.Refresh() # (7)
  1. The information in the status bar (number of beepers carried by robot, etc.) is updated.
  2. The animation is paused at each step.
  3. Making sure other controls of the application are responsive so that the program can be paused or stopped altogether by pressing the appropriate button, etc.
  4. Update the (in-memory) image based on the latest robot action.
  5. Update the screen image.
  6. Prevent the robot from going off the screen.
  7. Refresh the screen [Refresh() is a wxPython method.]
That's it. Not much there. I refresh the screen so as to ensure that the robot world, right next to the code "window", gets updated on the screen when a new line of code is executed, and should be highlighted in the code window.

Can you see the bug?

I didn't refresh the code window. It worked before though.

How do I do this... the robot world is a ScrolledWindow whereas the code window is a StyledTextControl... Where do I find the relevant documentation...

That's when I thought of the three important words I mentioned before: try the obvious. I typed in

and launched RUR-PLE. Problem solved. I guess it was just dumb luck that this refresh statement was not required before. All I have to do now is fix the bug and update the version on sourceforge ... before I go back and rewrite the parts of the code that I didn't find easy to read just a few days ago.

No comments: