Mercurial > hg > GlobalNeighbors
view globalneighbors/web.py @ 9:638fad06e556
use bisect function; it has been tested faster
author | Jeff Hammel <k0scist@gmail.com> |
---|---|
date | Sun, 25 Jun 2017 11:37:52 -0700 |
parents | 254195d0bac2 |
children | 21ed15391e8a |
line wrap: on
line source
#!/usr/bin/env python """ web handler for GlobalNeighbors """ # imports import argparse import json import os import sys import time from webob import Request, Response, exc from wsgiref import simple_server from .locations import locations from .locations import city_dict from .read import read_cities from .read import read_city_list from .schema import fields from .schema import name from .template import template_dir from .template import TemplateLoader def autocomplete(cities, startswith=None, limit=None): """autocomplete function for city names""" ### TODO: # - sort once, ahead of time # - return most populous cities if startswith: retval = [] for i in cities: if i[name].startswith(startswith): retval.append(i[name]) return sorted(retval)[:limit] else: return sorted([i[name] for i in cities])[:limit] class Handler(object): """base class for HTTP handler""" def __call__(self, environ, start_response): request = Request(environ) method = getattr(self, request.method, None) response = None if method is not None: response = method(request) if response is None: response = exc.HTTPNotFound() return response(environ, start_response) class CitiesHandler(Handler): """cities ReST API""" content_type = 'application/json' def __init__(self, locations, cities): self.locations = locations self._cities = cities def cities(self, startswith=None): """return list of cities""" return autocomplete(self._cities, startswith=startswith) def GET(self, request): return Response(content_type=self.content_type, body=json.dumps(self.cities( startswith=request.GET.get('term')))) class GlobalHandler(Handler): """WSGI HTTP Handler""" content_type = 'text/html' def __init__(self, datafile, template_dir=template_dir): # parse data self.datafile = datafile self.cities = read_city_list(self.datafile, fields=fields) self.locations = locations(self.cities) # declare handlers self.handlers = {'/cities': CitiesHandler(self.locations, self.cities)} # template loader self.loader = TemplateLoader(template_dir) self.index = self.loader.load('index.html') def GET(self, request): if request.path_info in ('', '/'): # Landing page return Response(content_type=self.content_type, body=self.index.render(n_cities=len(self.cities))) else: handler = self.handlers.get(request.path_info) if handler: return request.get_response(handler) def main(args=sys.argv[1:]): """CLI""" # parse command line parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('cities', help="cities1000 data file") parser.add_argument('-p', '--port', dest='port', type=int, default=8080, help="port to serve on") parser.add_argument('--hostname', dest='hostname', default='localhost', help="host name [DEFAULT: %(default)s]") options = parser.parse_args(args) # instantiate WSGI handler app = GlobalHandler(datafile=options.cities) # serve it (Warning! Single threaded!) server = simple_server.make_server(host='0.0.0.0', port=options.port, app=app) try: print ("Serving on http://{hostname}:{port}/".format(**options.__dict__)) server.serve_forever() except KeyboardInterrupt: pass if __name__ == '__main__': main()