A lot of my work these days revolves around writing system tests using IronPython: our principal SDK is written in C/C++, but we have a thin .NET wrapper around it. A separate software group integrates our hardware in a C# application, and the principal developers are all pretty keen on C# as a language.
Parenthetically I'd note that I've long felt that dynamic languages like Python are well-suited for testing tasks, going so far as to write a Boost wrapper around a custom expression parser at my old job for unit testing: mocking up 40-50 tests and writing the wrapper consumed roughly four hours of time, and a lot of that was trying to understand the virtually non-existent Boost documentation. It was a great deal faster than your standard compile-execute-report method and integrated into our already-existing test framework (which I also wrote in Python).
We've been trying to identify a few issues in some third-party hardware over the past few weeks, and that means using an oscilloscope. For a software guy like me, learning to use the scope--and to program it--has been harder than I had expected.
Python offers a couple of key feature that make this process a lot easier than might be expected:
- dynamic runtime attribute binding
- decorators
Python treats functions as first-order objects, so functions can consume other functions and return functions as a result: this is what a decorator is. Python has some syntactic sugar for doing this:
@some_decorator def some_function( some_param ): pass
In my case, I'd like to be able to instrument a function on the oscilloscope
dynamically. As it happens, classes that implement __call__
can be used as
decorators, and that's what I ended up doing:
osc = Oscilloscope( ip_address ) instrumented_function = osc( instrumented_function )
(This second line is equivalent to the syntactic sugar of function
decoration. Those who were used to the old-style way of declaring methods
using staticmethod
in Python should be familiar.)
I'll discuss implementation later, if time permits; as a final point, I'd note that what's really nice here is that it offers a complete aspect-oriented way of coding: when I want to instrument hardware on the scope when running a function, none of the code I wrote originally is polluted by what I've written now. This sort of flexibility is one of the reasons I really love working with Python.