view bzapi.py @ 1:f2147b34d6af

Use pymongo instead of pickling
author Atul Varma <varmaa@toolness.com>
date Wed, 23 Dec 2009 02:23:11 -0800
parents 78e4757601ec
children 6a0ad0463a89
line wrap: on
line source

import urllib2
import urllib
from datetime import datetime

import pymongo
import simplejson as json

def datetime_to_iso(dt):
    return "%sZ" % (dt.replace(microsecond=0).isoformat('T'))

def datetime_from_iso(timestamp):
    return datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')

def sanitize(obj):
    if type(obj) == dict:
        bad_names = [name for name in obj
                     if "." in name]
        for name in bad_names:
            new_name = name.replace('.', '_DOT_')
            obj[new_name] = obj[name]
            del obj[name]
        for name in obj:
            sanitize(obj[name])
    elif type(obj) == list:
        for item in obj:
            sanitize(item)

class CachedSearch(object):
    def __init__(self, api, collection, **kwargs):
        self.options = kwargs

        self.bugs = collection
        self.api = api
        self._update_last_update()

    def _update_last_update(self):
        bugs = self.bugs.find().sort("last_change_time",
                                     pymongo.DESCENDING).limit(1)
        if bugs.count() == 0:
            self.last_update = None
        else:
            self.last_update = bugs[0]['last_change_time']

    def update(self):
        params = {}
        params.update(self.options)
        if self.last_update:
            params['changed_after'] = self.last_update
        bugs = self.api.get('/bug', **params)['bugs']
        for bug in bugs:
            for name in ['last_change_time', 'creation_time']:
                bug[name] = datetime_from_iso(bug[name])
            bug['_id'] = bug['id']
            self.bugs.save(bug)
        self._update_last_update()

class BugzillaApi(object):
    def __init__(self, base_url, collection, username=None, password=None):
        self.base_url = base_url
        self.username = username
        self.password = password
        config = collection.find_one()
        if not config:
            config = self.get('/configuration')
            sanitize(config)
            collection.insert(config)
        self.config = config

    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] = datetime_to_iso(value)

        params = {}
        if self.username and self.password:
            params.update({'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())