Skip to content

Instantly share code, notes, and snippets.

@dsuch
Created September 4, 2013 17:52
Show Gist options
  • Save dsuch/6440366 to your computer and use it in GitHub Desktop.
Save dsuch/6440366 to your computer and use it in GitHub Desktop.
Services accompanying an LJ article
# -*- coding: utf-8 -*-
# stdlib
from datetime import datetime
# dateutil
from dateutil.parser import parse
# lxml
from lxml import etree
# Zato
from zato.common.util import grouper
from zato.server.service import Service
# Interesting namespaces treasury.gov uses for rates
NAMESPACES = {
'd':'http://schemas.microsoft.com/ado/2007/08/dataservices',
'm':'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'
}
# Pattern for a Redis key to store the data under
REDIS_KEY_PATTERN = 'linuxjournal:rates:{}:{}:{}'
def get_date(input):
now = datetime.utcnow()
year = input.get('year') or now.year
month = input.get('month') or now.month
day = input.get('day') or now.day
return year, month, day
# ##############################################################################
class UpdateCache(Service):
""" Fetches complex XML from treasury.gov and updates the application's Redis cache.
"""
class SimpleIO:
input_optional = ('year', 'month')
def handle(self):
# Grab month and year from user-provided input or use defaults, i.e. current date,
# note that day is not needed so it's discarded
year, month, _ = get_date(self.request.input)
# Fetch connection by its name
out = self.outgoing.plain_http.get('treasury.gov')
# Build a query string the backend data source expects
query_string = {
'$filter': 'month(QUOTE_DATE) eq {} and year(QUOTE_DATE) eq {}'.format(month, year)
}
# Invoke the backend with query string, fetch the response as a UTF-8 string
# and turn it into an XML object
response = out.conn.get(self.cid, query_string)
response = response.text.encode('utf-8')
xml = etree.fromstring(response)
# Look up all XML elements needed (date and rate) using XPath
elements = xml.xpath('//m:properties/d:*/text()', namespaces=NAMESPACES)
# elements is a flat list that needs to be turned into pairs using the 'grouper'
# function before iterating over
elements = grouper(2, elements)
for date, rate in elements:
# Create a date object out of string
date = parse(date)
# Build a key for Redis and store the data under it
key = REDIS_KEY_PATTERN.format(date.year, str(date.month).zfill(2), str(date.day).zfill(2))
self.kvdb.conn.set(key, rate)
# Leave a trace of our activity
self.logger.info('Key %s set to %s', key, rate)
# ##############################################################################
class GetRate(Service):
""" Returns the real long-term rate for a given date (defaults to today if no date is given).
"""
class SimpleIO:
input_optional = ('year', 'month', 'day')
output_optional = ('rate',)
def handle(self):
# Get date needed either from input or current day
year, month, day = get_date(self.request.input)
# Build the key the data is cached under
key = REDIS_KEY_PATTERN.format(year, month, day)
# Assign the result from cache directly to response
self.response.payload.rate = self.kvdb.conn.get(key)
# ##############################################################################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment