-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathfls.py
168 lines (150 loc) · 5.46 KB
/
fls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# -*- coding: utf-8 -*-
import os
from random import randint
from flask import Flask, send_file, request, render_template, jsonify, make_response, url_for
from functools import wraps
from hexagram import Hexagram, Trigram
app = Flask(__name__)
with app.app_context():
app.config["SERVER_NAME"] = os.environ.get("SERVER_NAME")
def json_resp():
return {
"hexagram": "/hexagram/nnnnnn.png, where n is 1 (solid bar) or 0 (broken bar). Hexagrams are built bottom to top.",
"trigram": "/trigram/nnn.png, where n is 1 (solid bar) or 0 (broken bar). Trigrams are built bottom to top.",
"random": "call /trigram/random or /hexagram/random to get a random image",
"digit_order": "Hexagrams and Trigrams are built using digits read from left to right.",
"links": "See the Link header for full paths.",
"copyright": "Stephan Hügel, 2016"
}
def link_dict(func, ep, *args, **kwargs):
""" Build "Link" headers from a list of passed values
kwargs only contains one key: it's passed to the url builder func
we replace its value with the first, last, and next values, then build
the url, and append as string
"""
links = []
with app.app_context():
for idx, arg in enumerate(['first', 'last', 'next']):
# kwargs only contains a single key (hexagram or trigram)
# its value is replaced by the first, next, and last digit sequences
# args contains values for first, last next
for k in kwargs.keys():
kwargs[k] = args[idx]
kwargs['_external'] = True
url = func(ep, **kwargs)
links.append('<%s>; rel="%s"' % (url, arg))
return ', '.join(links)
def add_response_headers(headers={}):
""" This decorator adds the headers passed in to the response"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
resp = make_response(f(*args, **kwargs))
h = resp.headers
for header, value in headers.items():
h[header] = value
return resp
return decorated_function
return decorator
def step_calculation(num, _max):
""" Calculate next hexagram or trigram binary representation
Overflows to smallest
"""
if _max == 63:
first = '000000'
zf = 6
else:
first = '000'
zf = 3
# reverse input, and convert to int
rev = int(num[::-1], 2)
if rev >= _max:
out = first
else:
rev += 1
# reverse again, and pad
out = bin(rev)[2:].zfill(zf)[::-1]
return out
def link_next(kind, num):
links = {}
kwargs = {}
# if it's a hexagram call
if kind == "hexagram":
first = '000000'
last = '11111'
kwargs['hexagram'] = 'dummy'
_next = step_calculation(num, 63)
# must be a trigram call
else:
first = '000'
last = '111'
kwargs['trigram'] = 'dummy'
_next = step_calculation(num, 7)
# first, next, previous, last
links["Link"] = '%s' % (
link_dict(url_for, request.endpoint, first, last, _next, **kwargs),
)
return links
def request_wants_json():
best = request.accept_mimetypes \
.best_match(['application/json', 'text/html'])
return best == 'application/json' and \
request.accept_mimetypes[best] > \
request.accept_mimetypes['text/html']
def link_first():
with app.app_context():
return {"Link": '<%s>; rel="first"' % url_for(
'hex_out',
hexagram='000000',
_external=True)
}
def firstlink(f):
""" Return the link to the simplest hexagram with a response """
@wraps(f)
@add_response_headers(link_first())
def decorated_function(*args, **kwargs):
return f(*args, **kwargs)
return decorated_function
def image_response(gen, kind, ideogram):
""" Build a response for specified and random tri– and hexagrams """
response = make_response(send_file(gen.dump_image(), mimetype='image/png'))
for k, v in link_next(kind, ideogram).items():
response.headers[k] = v
return response
@app.route('/hexagram/<hexagram>.png')
def hex_out(hexagram):
generated = Hexagram([int(elem) for elem in hexagram])
return image_response(generated, "hexagram", hexagram)
@app.route('/hexagram/random')
def hex_random():
random = "{0:b}".format(randint(0, 63)).zfill(6)
generated = Hexagram([int(elem) for elem in random])
return image_response(generated, "hexagram", random)
@app.route('/trigram/<trigram>.png')
def tri_out(trigram):
generated = Trigram([int(elem) for elem in trigram])
return image_response(generated, "trigram", trigram)
@app.route('/trigram/random')
def tri_random():
random = "{0:b}".format(randint(0, 7)).zfill(3)
generated = Trigram([int(elem) for elem in random])
return image_response(generated, "trigram", random)
@app.route('/')
@firstlink
def index():
if request_wants_json():
msg = json_resp()
return jsonify(items=[msg])
return render_template('index.html'), 200
@app.errorhandler(404)
def page_not_found(error):
if request_wants_json():
return make_response(jsonify(items=["Not Found"]), 404)
return make_response(render_template('index.html'), 404)
@app.errorhandler(500)
def app_error(error):
if request_wants_json():
return jsonify(items=["Internal Server Error"]), 500
return render_template('index.html'), 500
if __name__ == '__main__':
app.run()