Mercurial > hg > GlobalNeighbors
comparison globalneighbors/web.py @ 0:5dba84370182
initial commit; half-working prototype
author | Jeff Hammel <k0scist@gmail.com> |
---|---|
date | Sat, 24 Jun 2017 12:03:39 -0700 |
parents | |
children | 1b94f3bf97e5 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:5dba84370182 |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 """ | |
4 web handler for GlobalNeighbors | |
5 """ | |
6 | |
7 # imports | |
8 import argparse | |
9 import json | |
10 import sys | |
11 import time | |
12 from webob import Request, Response, exc | |
13 from wsgiref import simple_server | |
14 from .locations import locations | |
15 from .locations import city_dict | |
16 from .read import read_cities | |
17 from .read import read_city_list | |
18 from .schema import fields | |
19 from .schema import name | |
20 | |
21 | |
22 class Handler(object): | |
23 """base class for HTTP handler""" | |
24 | |
25 def __call__(self, environ, start_response): | |
26 request = Request(environ) | |
27 method = getattr(self, request.method, None) | |
28 response = None | |
29 if method is not None: | |
30 response = method(request) | |
31 if response is None: | |
32 response = exc.HTTPNotFound() | |
33 return response(environ, start_response) | |
34 | |
35 | |
36 class CitiesHandler(Handler): | |
37 """cities ReST API""" | |
38 | |
39 content_type = 'application/json' | |
40 | |
41 def __init__(self, locations, cities): | |
42 self.locations = locations | |
43 self._cities = cities | |
44 | |
45 | |
46 def cities(self, startswith=None): | |
47 """return list of cities""" | |
48 | |
49 if startswith: | |
50 return sorted([i[name] for i in self._cities | |
51 if i[name].startswith(startswith)]) | |
52 else: | |
53 return sorted([i[name] for i in self._cities]) | |
54 | |
55 def GET(self, request): | |
56 return Response(content_type=self.content_type, | |
57 body=json.dumps(self.cities( | |
58 startswith=request.GET.get('q')))) | |
59 | |
60 | |
61 class GlobalHandler(Handler): | |
62 """WSGI HTTP Handler""" | |
63 | |
64 content_type = 'text/plain' | |
65 | |
66 def __init__(self, datafile): | |
67 self.datafile = datafile | |
68 | |
69 # parse data | |
70 self.cities = read_city_list(self.datafile, | |
71 fields=fields) | |
72 self.locations = locations(self.cities) | |
73 | |
74 # TODO: declare handlers | |
75 self.handlers = {'/cities': | |
76 CitiesHandler(self.locations, | |
77 self.cities)} | |
78 | |
79 | |
80 def GET(self, request): | |
81 if request.path_info in ('', '/'): | |
82 # Landing page | |
83 return Response(content_type=self.content_type, | |
84 body="""Global Neighbors | |
85 Serving {} cities""".format(len(self.cities))) | |
86 else: | |
87 handler = self.handlers.get(request.path_info) | |
88 if handler: | |
89 return request.get_response(handler) | |
90 | |
91 | |
92 | |
93 def main(args=sys.argv[1:]): | |
94 """CLI""" | |
95 | |
96 # parse command line | |
97 parser = argparse.ArgumentParser(description=__doc__) | |
98 parser.add_argument('cities', | |
99 help="cities1000 data file") | |
100 parser.add_argument('-p', '--port', dest='port', | |
101 type=int, default=8080, | |
102 help="port to serve on") | |
103 parser.add_argument('--hostname', dest='hostname', | |
104 default='localhost', | |
105 help="host name [DEFAULT: %(default)]") | |
106 options = parser.parse_args(args) | |
107 | |
108 # instantiate WSGI handler | |
109 app = GlobalHandler(datafile=options.cities) | |
110 | |
111 # serve it (Warning! Single threaded!) | |
112 server = simple_server.make_server(host='0.0.0.0', | |
113 port=options.port, | |
114 app=app) | |
115 try: | |
116 print ("Serving on http://{hostname}:{port}/".format(**options.__dict__)) | |
117 server.serve_forever() | |
118 except KeyboardInterrupt: | |
119 pass | |
120 | |
121 | |
122 if __name__ == '__main__': | |
123 main() | |
124 |