# HG changeset patch # User Thinker K.F. Li # Date 1225546191 -28800 # Node ID 7551342718b6f286edede14b24382be835599f4b # Parent e2956846ee98474c2aaf36411620b52ce7b82607 Refactory pyikriam with patterns. - Use dyna_prog, a dynamic programming decorator, to cache city objects. - fake_moz to emulate a mozilla browser. diff -r e2956846ee98 -r 7551342718b6 pyikriam/__init__.py --- a/pyikriam/__init__.py Sat Nov 01 16:38:56 2008 +0800 +++ b/pyikriam/__init__.py Sat Nov 01 21:29:51 2008 +0800 @@ -4,23 +4,44 @@ import os import urllib2 import urllib +from utils import dyna_prog, decorator + +class fake_moz(object): + __metaclass__ = decorator + + def __init__(self): + super(fake_moz, self).__init__() + cookie_jar = cookielib.LWPCookieJar() + cookie_proc = urllib2.HTTPCookieProcessor(cookie_jar) + opener = urllib2.build_opener(cookie_proc) + opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.8.1.12pre) Gecko/20071220 BonEcho/2.0.0.12pre')] + fake_moz.set_backend(self, opener) + self.cookie_jar = cookie_jar + pass + pass + + class Ikariam: cities = {} + COOKIEFILE = '/tmp/ikariam.lwp' def __init__(self): - self.COOKIEFILE = '/tmp/ikariam.lwp' + browser = fake_moz() + self.browser = browser + self._cookie_jar = browser.cookie_jar + + if os.path.isfile(self.COOKIEFILE): + self._cookie_jar.load(self.COOKIEFILE) + pass + + urllib2.install_opener(browser) + self.confdata=LoadConfigfile().cd self.baseurl='http://'+self.confdata['server'] - self.cj = cookielib.LWPCookieJar() - if os.path.isfile(self.COOKIEFILE): - self.cj.load(self.COOKIEFILE) - - opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj)) - opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.8.1.12pre) Gecko/20071220 BonEcho/2.0.0.12pre')] - urllib2.install_opener(opener) self.login() + pass def login(self): print "login to %s...." % self.confdata['server'] @@ -28,16 +49,23 @@ "name":self.confdata['user'], \ "password":self.confdata['pass']} ret = c(self.baseurl+'/index.php?action=loginAvatar&function=login').get(params).get_content() - self.cj.save(self.COOKIEFILE) - + self._cookie_jar.save(self.COOKIEFILE) + pass + def logout(self): print "logut from %s...." % self.confdata['server'] c(self.baseurl+'/index.php?action=loginAvatar&function=logout') os.remove(self.COOKIEFILE) - + pass + + ## + # \note We can cache data with decorator 'dynamic programming'. + # + @dyna_prog def city(self, id): - return self.cities.get(id, IkariamCity(id=id, core=self) ) - + return IkariamCity(id=id, core=self) + pass + class IkariamCity: def __init__(self, id, core ): diff -r e2956846ee98 -r 7551342718b6 pyikriam/example.py --- a/pyikriam/example.py Sat Nov 01 16:38:56 2008 +0800 +++ b/pyikriam/example.py Sat Nov 01 21:29:51 2008 +0800 @@ -3,4 +3,5 @@ i = Ikariam() city = i.city(117261) city.sync() -print 'gold is'+city.gold +print 'gold is ' + city.gold + diff -r e2956846ee98 -r 7551342718b6 pyikriam/utils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyikriam/utils.py Sat Nov 01 21:29:51 2008 +0800 @@ -0,0 +1,80 @@ +## \brief decorator is a class decorate another of another object. +# +# Access of attributes/methods that can not be found in an instance +# of a class of this meta-class, decorator, are delegated to the backend +# of the instance. +# +# A backend object always passed as first parameter when +# instantiate an instance of a class with decorator as meta-class. +# For example, +# \code +# class foo(object): +# __metaclass__ = decorator +# +# backend.data = 3 +# obj = foo(backend) +# print obj.data +# backend.data = 4 +# print obj.data +# \endcode +# it print out 3 and 4 respectively. +# +class decorator(type): + def __init__(clz, name, base, dict): + super(decorator, clz).__init__(name, base, dict) + clz.__getattr__ = decorator.__dele_getattr + pass + + @staticmethod + def set_backend(obj, backend): + obj.__backend = backend + pass + + @staticmethod + def __dele_getattr(obj, name): + return getattr(obj.__backend, name) + pass + + +## \brief Decorator to make functions or methods dynamic programming. +# +# dyna_prog result of functions or methods with their arguments as key. +# It supposes result of a function always the same if the same arguments +# are passed. It cache result of cached function to avoid really calling +# function every time. +class dyna_prog(object): + class functor(object): + def __init__(self, instance, method): + self._method = method + self._instance = instance + self._cache = {} + pass + + def __call__(self, *args): + try: + return self._cache[args] + except KeyError: + pass + instance = self._instance + result = self._method(instance, *args) + return self._cache.setdefault(args, result) + + def clear(self): + self._cache.clear() + pass + + def __init__(self, method): + super(dyna_prog, self).__init__() + self._method = method + self._functors = {} + pass + + def __get__(self, instance, owner): + try: + return self._functors[instance] + except KeyError: + pass + functor_o = dyna_prog.functor(instance, self._method) + return self._functors.setdefault(instance, functor_o) + pass +