If you have a method on an object that doesn’t return and that takes a long time to complete then you can use this pattern to spin it off into an unmonitored thread.

I’m going to use medusa_http.QuixoteHandler.continue_request as an example. This function doesn’t return a value, instead it manipulates some instance variables and calls methods on its own object, which makes it perfect for this.

Move the continue_request function above the class definition of QuixoteHandler then outdent(!) it one level. Where continue_request used to be, add the function:

def continue_request(self, body, request):
    import thread
    thread.start_new_thread(continue_request, (self, body, request))

This takes advantage of the fact that self has no special meaning in Python, and the function continue_request can still use it, even if it is passed from the method continue_request’s instance.

I’m aware that having self as a variable name in a function is potentially misleading, but this is a pretty nifty shortcut IMHO. An even shorter and more obfuscated shortcut could be:

def continue_request(*args):
    __import__('thread').start_new_thread(continue_request, args)

Or, for the Python 2.3 users, how about:

def make_thread_method(function_name, instance):
    import new
    f = globals()[function_name]
    def tmp(*args):
        __import__('thread').start_new_thread(f, args)
    i = new.instancemethod(tmp, instance, instance.__class__)
    setattr(instance, function_name, i)

# [...]

    def __init__ (self, publisher, server_name, server):
        [...]
        make_thread_method('continue_request', self)

I wish Python had macros.

By the way, the medusa_thread_http module is hopelessly optimistic, and probably shouldn’t be used for a real deployment.

Update: After reading Ben Last’s blog and seeing a link to this recipe, I can remove self from the parameters!

def make_thread_method(function_name):
    import sys
    import new
    instance = sys._getframe(1).f_locals['self']
    f = globals()[function_name]
    def tmp(*args):
        __import__('thread').start_new_thread(f, args)
    i = new.instancemethod(tmp, instance, instance.__class__)
    setattr(instance, function_name, i)

# [...]

    def __init__ (self, publisher, server_name, server):
        [...]
        make_thread_method('continue_request')</code></pre>

2nd Update: Okay, after more tinkering and taking advantage of my Daily Python URL temporary fame, I have the below:

def threadmethod(f, i=None):
    import new
    import sys
    if not i:
        i = sys._getframe(1).f_locals['self']
    def tmp(*args):
        __import__('thread').start_new_thread(f, args)
    return new.instancemethod(tmp, i, i.__class__)

class A:
    def do_thing(self):
        import time
        time.sleep(5)
        print "Wootle"
    do_thing = staticmethod(do_thing)
    def __init__(self):
        self.do_thing = threadmethod(self.do_thing)

a = A()

a.do_thing()

My question is: how can I make the line inside __init__ more like staticmethod (or can I?). Ideally what I want is:

class A:
[...]
    do_thing = staticmethod(do_thing)
    do_thing = threadmethod(do_thing)

3rd Update: Daniel Brodie writes with this even simpler version. I can’t believe I missed this- I was so busy with the idea of converting an instance method to a static method and then back again, I didn’t see that you don’t need to convert it at all!

def threadmethod(func):
    def temp(*args):
        import thread
        print thread.start_new_thread(func, args)
    return temp

class A:
    def do_thing(self, some_val):
        print 'do_thing:', self, some_val
    do_thing = threadmethod(do_thing)

if __name__=='__main__':
    a = A()
    a.do_thing(5)
    while 1:
        pass #To let the thread finish up