A Post in Three Parts
Assume You Checked Your Assumptions!
Ever look at a piece of code and wonder: “why did I do it that way?” Sometimes there is a nagging warning in the back of your head: “because the other way didn’t work!” Sadly, in the foolish pursuit of perfection, you refactor to the “other way” seeing no obvious reason why it shouldn’t work great.
Command Queueing using a Mutex in Python
I encountered this today while factoring some code out of an application into a framework. The abstraction is a Python-Cocoa application that communicates asynchronously with a command-oriented device over a serial port. Handles command queueing, blocking IO in a separate thread, time-outs, reconnects, call-backs, etc. Anyway, I couldn’t remember why I was passing the name of the calling method when doing an invocation. Why not just look one frame up in the call stack with “sys._getframe(1).f_code.co_name”? There turned out to be a good reason.
I’m using a mutex in Python to effect the queueing, which works pretty slick. I lock on an asynchronous call like this:
def getRampSlope(self, callback): self._mutex.lock(self._asyncCommand, {'command': 'RampSlope', 'response_type': int, 'callback': callback, 'method': 'getRampSlope'})
In “_asyncCommand” I do a blocking write to the serial port, and then launch a thread to read from it in the background. When that thread is finished reading a response, it does the callback and unlocks the mutex:
def serialPortReadData_(self, event): frag = NSString.alloc().initWithData_encoding_( event['data'], NSASCIIStringEncoding) self._response_buff += frag if not self._last_cmd_timed_out and self._response_buff.endswith("r"): self._processResponse() # will write the next command to the filehandle and spawn a new reader # thread. self._mutex.unlock() # ...
Python has been keeping track of all the “_asyncCommand” calls that are locked on the mutex. It dequeues the next one on unlock(), and a new command is run, background thread launched, etc. The background threads are launched in objective-c land, btw, and so they’re shown to interoperate with the Python mutex without problems.
So I’m asking myself “why am I passing ‘method’ to asyncCommand?” Well, it’s because the true caller in the stack could be e.g. getRampSlope if there is no queueing going on, but otherwise it will end up being serialPortReadData!
VIM Macros to the Rescue
I remembered this the hard way by stripping out all the ‘method’: params anyway. With no undo buffer or easy source control reversion, VIM macros came to the rescue!
I needed to:
- Find the next method declaration.
- Copy it’s name and seek to the end of its _asyncCommand call.
- Insert a ‘method’ parameter with the caller name as the value.
- Repeat n times.
- Clean up the code.
This took exactly 1:19 using VIM macros. I’m sure other editors have similar capabilities, but I’m not sure they can reproduce the elegance of VIM’s command and visual modes while doing so:


