view globalneighbors/web.py @ 7:254195d0bac2

partial implementation of autocomplete using jqueryui; easyautocomplete.com may be more what we want
author Jeff Hammel <k0scist@gmail.com>
date Sun, 25 Jun 2017 09:13:48 -0700
parents 316e1d54ffd4
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()