< October 2005 >
SuMoTuWeThFrSa
       1
2 3 4 5 6 7 8
9101112131415
16171819202122
23242526272829
3031     
Wed, 12 Oct 2005:

More python magic stuff I ran into today. It's the most convoluted use of argument names to be amazingly flexible. It's a trick on how you can just flow down your init args down a set of factories and whatever. This is how the initial code looked.

class Worker(object):
	def __init__(self, name="", key=""):
		self.name = name
		self.key = key

	def __repr__(self):
		return "working %s <%s>" % (self.name, self.key)

class Driver:
	def __init__(self, worker = Worker, **kw):
		self.worker = worker(**kw)

	def __repr__(self):
		return "drive a %s, mad" % (self.worker)
	
class Master:
	def __init__(self, **kw):
		self.driver = Driver(**kw)

	def __repr__(self):
		return "I pay to %s" % (self.driver)

print Master(name="Gopal", key="t3")
I get the obvious output from the program: I pay to drive a working Gopal <t3>, mad.

So far, so good. But from now on, I need to grade my workers on the basis of the hardness of their work. So in a totally different module, I start writing the following code:

class GradedWorker(Worker):
	def __init__(self, hardness="very", name="", key=""):
		self.hardness = hardness
		self.name = name
		self.key = key
	
	def __repr__(self):
		return "%s working %s <%s>" % (self.hardness, self.name, self.key)

print Master(worker=GradedWorker, name="Gopal", key="t3", hardness="very very")

Voila, you have Master invoking the right worker with the right args (hardness) with no change in the original codebase at all. Tell me, how many of you knew you could do something like this with python ?. Now let me explain why I ended up writing this code - or in what codebase I started writing this. I have this WSDL file full of some cool methods, but the methods are accessible only If the HTTP call contains a particular cookie. So I started looking around the internet for a solution.

Activestate aspn didn't have an answer - python lists didn't have answer, sourceforge had a pending patch - which wasn't there in the release. Finally after giving up all hope, I hit the #python irc channel in the hope of some help.

-ChanServ- [#python] Welcome to #python, a support channel for Python programmers! If you're new, please see http://twistedmatrix.com/wiki/python/WelcomeToPoundPython.

Oct 12 01:27:30 *t3rmin4t0r is banging his head on soappy all night
Oct 12 01:27:35 t3rmin4t0r anyone know of any sane python SOAP libs ?
Oct 12 01:29:20 t3rmin4t0r does anyone know of any python SOAP libs ?
Oct 12 01:29:28 t3rmin4t0r or I'm going back to doing it in javascript hell
Oct 12 01:29:58 Erwin          t3rmin4t0r: t3rmin4t0r, meet Google. Google, meet t3rmin4t0r.
Oct 12 01:30:28 t3rmin4t0r none of them support cookies in their SOAP lib
Oct 12 01:30:59 t3rmin4t0r Erwin: it's not like I don't know how to search :)
Oct 12 01:30:33 t3rmin4t0r cannot use ClientCookie or something ...
Oct 12 01:31:25 * t3rmin4t0r realizes he didn't have to come here to hear RTFM ...
Oct 12 01:31:33 * You have left channel #python ("I feel insulted and violated ....")

So here's the solution for the problem ... I couldn't sleep till I figured it out.

import sys, os, string
from SOAPpy import WSDL,HTTPTransport,Config,SOAPAddress
import ClientCookie
import urllib2

Config.cookieJar = ClientCookie.MozillaCookieJar()
# Config.cookieJar.load("cookies.txt")

class CookieTransport(HTTPTransport):
  def call(self, addr, data, namespace, soapaction = None, encoding = None,
    http_proxy = None, config = Config):

    if not isinstance(addr, SOAPAddress):
      addr = SOAPAddress(addr, config)
    
    cookie_cutter = ClientCookie.HTTPCookieProcessor(config.cookieJar)
    hh = ClientCookie.HTTPHandler()
    hh.set_http_debuglevel(1)

    # TODO proxy support
    opener = ClientCookie.build_opener(cookie_cutter, hh)

    t = 'text/xml';
    if encoding != None:
      t += '; charset="%s"' % encoding
    opener.addheaders = [("Content-Type", t),
              ("Cookie", "Username=foobar"),
              ("SOAPAction" , "%s" % (soapaction))]
              
    response = opener.open(addr.proto + "://" + addr.host + addr.path, data)
    data = response.read()

    # get the new namespace
    if namespace is None:
      new_ns = None
    else:
      new_ns = self.getNS(namespace, data)

    print '\n' * 4 , '-'*50
    # return response payload
    return data, new_ns

# From xmethods.net

wsdlURL = "http://www.doughughes.net/WebServices/fortune/fortune.cfc?wsdl"

proxy = WSDL.Proxy(wsdlURL, transport = CookieTransport)

print proxy.getFortune()

Sometimes, people just piss me off... But hopefully this should help someone somewhere use SOAPpy with cookie support.

posted at: 03:59 | path: /hacks | permalink | Tags: