# HG changeset patch # User Atul Varma # Date 1261546825 28800 # Node ID 78e4757601ec00661040b8cb0e06dd8a0f817821 origination diff -r 000000000000 -r 78e4757601ec .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Dec 22 21:40:25 2009 -0800 @@ -0,0 +1,2 @@ +syntax: glob +*.pickle diff -r 000000000000 -r 78e4757601ec bzapi.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bzapi.py Tue Dec 22 21:40:25 2009 -0800 @@ -0,0 +1,76 @@ +import urllib2 +import urllib +from datetime import datetime + +import simplejson as json + +def datetime_from_iso(timestamp): + return datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ') + +class CachedSearch(object): + def __init__(self, api, **kwargs): + self.options = kwargs + self.last_update = None + self.bugs = {} + self.update(api) + + def update(self, api): + params = {} + params.update(self.options) + if self.last_update: + params['changed_after'] = self.last_update + bugs = api.get('/bug', **params)['bugs'] + latest_time = None + for bug in bugs: + last_change_time = datetime_from_iso(bug['last_change_time']) + if not latest_time or last_change_time > latest_time: + latest_time = last_change_time + self.bugs[bug['id']] = bug + self.last_update = last_change_time + +class BugzillaApi(object): + def __init__(self, base_url, username=None, password=None): + self.base_url = base_url + self.username = username + self.password = password + self.config = self.get('/configuration') + + def _validate_component(self, product, component=None): + products = self.config['product'] + if product not in products: + msg = 'product %s not in configuration' % repr(product) + raise ValueError(msg) + if component and component not in products[product]['component']: + msg = 'component %s of product %s not in configuration' % ( + repr(component), + repr(product) + ) + raise ValueError(msg) + + def get(self, url, **kwargs): + for name, value in kwargs.items(): + if isinstance(value, datetime): + kwargs[name] = "%sZ" % ( + value.replace(microsecond=0).isoformat('T') + ) + + if self.username and self.password: + params = dict(username = self.username, + password = self.password) + params.update(kwargs) + + if 'product' in params: + self._validate_component(params['product'], + params.get('component')) + + full_url = "%s%s?%s" % (self.base_url, + url, + urllib.urlencode(params)) + + request = urllib2.Request(full_url) + request.add_header('Accept', 'application/json') + request.add_header('Content-Type', 'application/json') + + response = urllib2.urlopen(request) + + return json.loads(response.read()) diff -r 000000000000 -r 78e4757601ec example.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/example.py Tue Dec 22 21:40:25 2009 -0800 @@ -0,0 +1,60 @@ +import os +from datetime import datetime, timedelta +import cPickle as pickle + +import bzapi + +class Picklable(object): + def __init__(self, filename, constructor, **kwargs): + self.__filename = filename + + if not os.path.exists(filename): + self.__obj = constructor(**kwargs) + self.save() + else: + obj_file = open(filename, 'r') + self.__obj = pickle.load(obj_file) + obj_file.close() + + def save(self): + obj_file = open(self.__filename, 'w') + pickle.dump(self.__obj, obj_file) + obj_file.close() + + def __getattr__(self, attr): + if not attr.startswith('_Picklable_'): + return getattr(self.__obj, attr) + else: + return self.__dict__[attr] + + def __setattr__(self, attr, value): + if not attr.startswith('_Picklable_'): + setattr(self.__obj, attr, value) + else: + self.__dict__[attr] = value + +api = Picklable( + 'example.api.pickle', + bzapi.BugzillaApi, + base_url = 'https://api-dev.bugzilla.mozilla.org/latest' + ) + +search = Picklable( + 'example.cached-search.pickle', + bzapi.CachedSearch, + api = api, + product='Mozilla Labs', + component='Jetpack' + ) + +#search.update(api) + +#print len([bug for bug in search.bugs.itervalues()]) + +#print search.bugs.values()[12]['summary'] + +#print api.get('/bug/510339/history') + +#print api.get('/bug', +# product='Mozilla Labs', component='Jetpack', +# changed_after=now-timedelta(minutes=60))