Peter's Blog

Redefining the Impossible

Items filed under swig


I've been trying Wing IDE a development environment for Python. I've tried some in the past and always fell back to using VIM and print statements:

IDLE
cannot debug GUI applications (IDLEfork might, haven't tried it)
PythonWin
cannot debug GUI applications, doesn't appear to have evolved in the last few years
Boa Constructor
haven't tried it for a while, back then it was flaky and didn't work with the contemporary wxPython (which is a moving target anyway). Recent reports say the debugger is still flaky.
pdb
python's own debugger, command line based sad

I was interested in Wing IDE (WingIDE?) as it would be nice to have a decent debugger. Simple things like:

  • double click exception stack dump to take me to point of exception in source
  • breakpoints (!)
  • single step

I tried the cheap 'personal' edition and here's a potted review:

  • on pentium 2 450M with 256M ram on windows XP it is very sluggish. It uses 40M of memory so it is probably swapping. On 1.5G Centrino with 512M it is much more useable. Single steps still take a second or so each (like walking through mud). When it runs the target the target runs at full speed. The help file makes mention of it being slow when it is loading symbols on startup but the slowness I see effects it all the time.
  • editor is ok in a Visual Studio kind of way. It's not VIM but I can still use VIM in the same way that I still use it with Visual Studio. Write code in VIM, correct it in IDE.
  • editor has auto-completion (fills in the rest of an identifier for you) but it's kinda slow to come up and VIM has a way to do this that is simplistic but useful (CTRL-N for the uninitiated).
  • first project I ran generated an exception in the startup code, something mysterious in Swig generated code. Wing is supposed to intelligently tell the difference between exceptions that you trap yourself in your code and ones that you don't trap: presumably it only drops into the debugger on an unhandled exception. This particular exception was in the Swig stuff so it may have been under some C code, in which case the exception always stops in the debugger (in Wing terminology this is a 'false positive'). However, Wing has a useful option to learn which exceptions you want to always ignore so I set this up and was not bothered by it again. The details of the exception were presumably stored in the project file.
  • IDE and debugger works as you would expect from standards set by Turbo C 15 years ago.
  • in the personal edition, when the debugger comes in you cannot evaluate expressions or examine variables, you can only look at the values of variables in the stack trace. There is a python shell but it is independent from the script you are debugging so it is only useful for experiments.
  • from visual studio I am used to hovering the cursor over a variable name and seeing it's value in a tool tip, or being able to right click and see it's value. Wing does not do this, it seem you have to look through the stack trace to find the value of variable.
  • coolest feature is remote debugging. You can edit a script to add a line to import a Wing module and from then on, if the script raises an exception it will find the Wing IDE and you can start debugging. This is useful if, for example, you are debugging CGI scripts that are launched from Apache: the scripts can find Wing IDE and you can debug them, they don't have to be launched from Wing IDE itself.
  • it works fine debugging wxPython and has been solid so far.
  • I left it running a program for an hour. The program generated lots of print output which was caught and displayed in the debugger. After an hour the debugger was using over 100M of ram: it doesn't seem to want to limit the size of the debug buffer. Maybe there is an option to stop this but it's odd that it should do this by default.

Conclusion: I can live with it's lethargy just to have a useable debugger. I'm still on the free trial, time will tell if I want to shell out $35 for the personal edition (less than £20, not bad).

There are other open source alternatives I haven't looked at:

spe: looks like work in progress

Eclipse: written in java, mainly for java


2 Comments

A quick reminder on how to use Swig under Windows XP to generate Python modules with Visual Studio 6.

  • Download Windows version of Swig
  • Unzip it somewhere, I put it in c:/Python24/Swig
  • Create the following environment variables:
    PYTHONINCLUDE = c:\python24\include
    PYTHONLIB = c:\Python24\Libs
    
  • Create a project in Visual Studio for a plain empty win32 dll.
  • In all build settings, make sure the following settings are added:
    Additional include directories = c:\python24\include
    Additional library path = c:\python24\libs
    
  • Create swig definition file. Here is mine, it's for a CAN bus control module:
       1  %module pyCan
       2  %include exception.i
       3  %{
       4  #include <windows.h>
       5  #include <stdlib.h>
       6  #include <stdio.h>
       7  #include <string.h>
       8  #include "pyCan.h"
       9  %}
      10  
      11  /*
      12   * When a c++ exception occurs, this code will turn it into
      13   * a python exception. Cool.
      14   */
      15  %exception {
      16      try {
      17          $action
      18      } catch( char *strError) {
      19          PyErr_SetString(PyExc_RuntimeError, strError);
      20          return NULL;
      21      }
      22  }
      23  
      24  /*
      25   * The function GetRxPacket returns a new object that python
      26   * memory management must delete when required.
      27   */
      28  %newobject GetRxPacket;
      29  
      30  /*
      31   * Class that will become a python class. The python class will have
      32   * the same methods available.
      33   */
      34  class pyCan {
      35  public:
      36      pyCan( void);
      37      ~pyCan( void);
      38      void Initialise( void);
      39      void Poll( void);
      40      pyCanPacket *GetRxPacket( void);
      41      void TxPacket( int nID, PyObject *);
      42  };
    
  • Add the Swig file to the project, right click and select 'settings'. Set the custom build commands something like the following:
    c:\python24\swig\swig -c++ -module pyCan -python c:\projects\694\src\pyCan\pyCan\pyCan.swig
    
    Where
    
        -c++ = generate c++
        -module pyCan = output module is called 'pyCan
        -python = generate python module
        c:\projects\694\src\pyCan\pyCan\pyCan.swig = swig file name
    
  • The above will generate a c++ file called 'pyCan_wrap.cxx'. This should be put into the 'Outputs' box in the custom build step.
  • Run the build on the swig file to create the wrapper file pyCan_wrap.cxx and add that file to the project.
  • Set the link target to something like
    _pyCan.dll
    
    I.e. the name of the module with an underscore in front.
  • Create a 'real' c++ header and implementation for your classes. They can be totally straight c++, e.g.:
    class pyCan {
    public:
        pyCan( void);
        ~pyCan( void);
        void Initialise( void);
        void Poll( void);
        pyCanPacket *GetRxPacket( void);
        void TxPacket( int nID, PyObject *);
    };
    
    In the above example I am passing a PyObject * to the function TxPacket. This is because I want to be able to pass python strings that may contain null characters and I want access to both the pointer to the data and the data length, which the raw PyObject gives me. If I only wanted a char * I would simply put that in the argument.
  • Build it
  • Swig will create a file called 'pyCan.py' which is the python wrapper module that loads the dll. It is the file that your python must import. You might want to add a post-build step to copy this somewhere more useful. You may also put the link target file in the same directory or you will get errors when you import the module.
  • Write some python:
    import pyCan
    
    o = pyCan.pyCan()
    o.Initialise()
    while 1:
        o.Poll()
        r = o.GetRxPacket()
        if r:
            print r
    

Swig is quite easy to get going. I think it has real power but there is a lot of documentation to go through to fully understand what it can do and the documentation and semantics are not all that clear. The PyObject trick above was a guess of mine that happened to work.


Filed under: python swig windows

2 Comments

Decided to write a python extension module. Swig looks like the easiest way to do it. Given a simple definition file, e.g.:

%module mod552
extern int Wiffle( int a);
extern char *Poopie( char *strPoop);
extern int jetty( int a, char *strB);

%{
#include "Giblets.h"
%}

class Giblets
{
public:
  int Mandible( void);
};

Swig will generate a file full of c++ wrapper code for the python objects. The code for the library is written in straight C, e.g.:

   1  #include <string.h>
   2  #include <stdlib.h>
   3  #include "Giblets.h"
   4  
   5  int Wiffle( int a)
   6  {
   7      return a + 5;
   8  }
   9  
  10  char *Poopie( char *strPoop)
  11  {
  12      static char strBuff[1000];
  13  
  14      strcpy( strBuff, strPoop);
  15      strBuff[3] = 'p';
  16      strBuff[4] = 'c';
  17      strBuff[5] = 'w';
  18  
  19      return strBuff;
  20  }
  21  
  22  int jetty( int a, char *strB)
  23  {
  24      return a + atoi( strB);
  25  }
  26  
  27  int Giblets::Mandible( void)
  28  {
  29      return 97;
  30  }

The module is used in python as you would expect:

   1  C:\552\Src\Mod552\Mod552>python
   2  Python 2.3.4 (#53, May 25 2004, 21:17:02) [MSC v.1200 32 bit (Intel)] on win32
   3  Type "help", "copyright", "credits" or "license" for more information.
   4  >>> import mod552
   5  >>> dir(mod552)
   6  ['Giblets', 'GibletsPtr', 'Poopie', 'Wiffle', '__builtins__', '__doc__', '__file
   7  __', '__name__', '_mod552', '_newclass', '_object', '_swig_getattr', '_swig_seta
   8  ttr', 'jetty']
   9  >>> o = mod552.Giblets()
  10  >>> o.Mandible()
  11  97
  12  >>>

This article is a useful introduction to the process although you have to be savvy with Visual C++ to follow it.


Filed under: python swig

Add a comment