Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Debugging python-fu scripts in Windows
#1
Debugging python-fu scripts

As Brian Kernighan wrote, "The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.".

On Linux (and likely OSX) things are easy: if you start Gimp from a terminal, all the output from print statements in Python plugins will be displayed in the terminal.

But on Windows, the output of plain print statements cannot be seen, so you have two options:

Using gimp_message()

This is a simple method which is OK to diagnose small and local problems, but it is better used on code which is known to be mostly working.
  • start the Error console dialog
  • use gimp_message() instead of print (if the Error console dialog is not up, Gimp stops with a dialog for each use of gimp_message())

Running your script in the python-fu console

This method is a bit more complex, but all the output is visible, even from parts of Python that you don't control (error messages, etc...)

We just have to overcome a few hurdles, namely:
  • by default Python doesn't look in the directory where your code is
  • the registration code doesn't work in the python-fu console, if fact it makes it crash.
  • taking the new version in account with minimal effort after editing the code

So, assuming you are working on plugin.py, with an entry point (the function you point to in the register() call) named execPlugin that takes an image and a layer, and that the file is in the plug-ins directory of your profile:
  • while testing the function, comment out the register() and main() call in your python
  • make sure your file name is a valid python identifier (no dashes in the name, for instance)
  • start the python-fu console, make sure you have one single image loaded and enter:
Code:
import sys;

# extend the python path to include the plug-ins directory
sys.path=[gimp.directory+'/plug-ins']+sys.path

#import the plugin
import plugin
  • to run the function:
Code:
# retrieve the image (if you have several images, it will be a bit more complicated)
# here we bluntly retrieve the first image in the list of loaded images  
image=gimp.image_list()[0]

# Call the function: note that the function name is prefixed with the module name
plugin.execPlugin(image,image.active_layer)
  • if you edit the file, to reload the new version of the code:
Code:
reload(plugin)
  • if your plugin function takes more parameters you have to provide them "manually". In most cases they will just be strings (text, but also file names, fonts, brushes,...) or numbers. The semi-difficult cases are layers and other images, because the parameter is an object, so you have to retrieve it with python code (obtain the other image in gimp.image_list(), for instance, or a drawable from image.layers and checking its name).
  • to start afresh, just close and reopen the python console
  • when done, don't forget to:
    • uncomment the registration code
    • remove the print statements... in Windows they can freeze your script if the total length of output is bigger than 4KB (because there is nothing to read it)

Routing python outputs to file

(this method inspired by a post by SeldomNeedy on the Gimp user mailing list)

This is a rather simple method, which is best used with an editor clever enough to reload the file when it notices changes. With this method, everything Python would write on the console (print statements, error messages... ) goes to a file, that you can check with a text editor. At the beginning of the file, do:
Code:
import sys
sys.stderr = open('C:/temp/python-fu-output.txt','a')
sys.stdout=sys.stderr # So that they both go to the same file

Other locations are possible:
Code:
sys.stderr = open(gimp.directory+'/../My Documents/python-fu-output.txt','a')

(contrary to popular belief, forward slashes are usable as path separators on Windows, only the command prompt parser doesn't like them).

When you are done with debugging, you can disable all the tracing by simply replacing the initial file opening.
Code:
Code:
import os
sys.stderr = open(os.path.devnull,'a')

os.path.devnull is the right "bit bucket" for the platform the code is running on, so this makes your plugin compatible with Windows, Linux, and OSX.
Reply
#2
One advantage of the stderr re-direction to a file is that you can then get the error messages from registration:
Code:
Traceback (most recent call last):
  File "C:\Users\username\Downloads\audit\python\kjp_temp.py", line 30, in <module>
    menu="<Image>/contributed/KJP Temp...")
TypeError: register() takes at least 11 non-keyword arguments (10 given)
Reply


Forum Jump: