One of the things I'm trying to do with building OpenGL-ctypes is to figure out just what's needed to wrap complex software using the package, and (eventually) to be able to suggest ways to make ctypes easier to use for such tasks. Part of doing that is getting it wrong a couple of times, and today I addressed the biggest "wrong" thing in the project to date and did something else "wrong" in the process.
I've been treating the ctypes cFunction objects as "the function", with the Wrapper classes as nothing more than glorified closures that provided better documentation. Tonight I moved the extra argument annotations into the wrapper class, and added quite a few convenience methods to it so that people registering converters for a given argument can specify the argument by name, instead of index.
Anyway, the result is that it's considerably easier to figure out what you want to do for wrapping any given function wrt converters. It's so much easier I actually converted a few previously hand-coded operations to using the wrapper.
To give you an idea of how easy it's getting to use, the entire GLE wrapper is 43 lines of custom code (most of that just being a trivial class that calculates the length of a given argument in the argument list) plus the two auto-generated modules (constants and the ctypes-derived auto-generated module). Now, that's probably more writing than would be needed with SWIG's name-inferred matching (probably around 15 or 20 lines there), but it's quite reasonable.
Now, after having said all that, I'm beginning to realise that there's going to be one more major rewrite. You see, what I've been doing is annotating the functions, what I should be doing is annotating the parameters. The problem has been that I've been thinking of the ctypes argtypes as if they were the parameters, and as a result I haven't been able to annotate them (they're shared among hundreds of calls).
What I should be doing is having parameters declared that themselves have attributes, one being type, one being input/output direction, one being whether they appear in the Python argument list, one being whether they appear in the C argument list, and others being the converters/resolvers. Then only those things which are truly function-wide will be stored in the wrapper directly.
That is, for the GLE functions, the code would look something like:
gleSpiral.getParameter( 'ncp' ).setup(
inPyArgs = False,
cConverter = _lengthOfArg(
'contour', 2, arrays.GLdoubleArray
That, however, will have to wait for tomorrow.
Pingbacks are closed.