Skip to content

Commit 316517a

Browse files
Created images.py and moved image generation code to that file
Added more validation for width and height keys in validate_results_request. Fixed a small code issue in validate_results_request.
1 parent c85040a commit 316517a

3 files changed

Lines changed: 99 additions & 71 deletions

File tree

codespeed/images.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import cStringIO
2+
from matplotlib.figure import Figure
3+
from matplotlib.ticker import FormatStrFormatter
4+
from matplotlib.backends.backend_agg import FigureCanvasAgg
5+
6+
DEF_CHART_W = 600
7+
DEF_CHART_H = 500
8+
9+
MIN_CHART_W = 400
10+
MIN_CHART_H = 300
11+
12+
13+
def gen_image_from_results(result_data, width, height):
14+
canvas_width = width if width is not None else DEF_CHART_W
15+
canvas_height = height if height is not None else DEF_CHART_H
16+
17+
canvas_width = max(canvas_width, MIN_CHART_W)
18+
canvas_height = max(canvas_height, MIN_CHART_H)
19+
20+
values = [element.value for element in result_data['results']]
21+
22+
max_value = max(values)
23+
min_value = min(values)
24+
value_range = max_value - min_value
25+
range_increment = 0.05 * abs(value_range)
26+
27+
fig = Figure(figsize=(canvas_width / 100, canvas_height / 100), dpi=100)
28+
ax = fig.add_axes([.1, .15, .85, .75])
29+
ax.set_ylim(min_value - range_increment, max_value + range_increment)
30+
31+
xax = range(0, len(values))
32+
yax = values
33+
34+
ax.set_xticks(xax)
35+
ax.set_xticklabels([element.date.strftime('%d %b') for element in
36+
result_data['results']], rotation=75)
37+
ax.set_title(result_data['benchmark'].name)
38+
39+
if result_data['relative']:
40+
ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f%%'))
41+
42+
font_sizes = [16, 16]
43+
dimensions = [canvas_width, canvas_height]
44+
45+
for idx, value in enumerate(dimensions):
46+
if value < 500:
47+
font_sizes[idx] = 8
48+
elif value < 1000:
49+
font_sizes[idx] = 12
50+
51+
if result_data['relative']:
52+
font_sizes[0] -= 2
53+
54+
for item in ax.get_yticklabels():
55+
item.set_fontsize(font_sizes[0])
56+
57+
for item in ax.get_xticklabels():
58+
item.set_fontsize(font_sizes[1])
59+
60+
ax.title.set_fontsize(font_sizes[1] + 4)
61+
62+
ax.scatter(xax, yax)
63+
ax.plot(xax, yax)
64+
65+
canvas = FigureCanvasAgg(fig)
66+
buf = cStringIO.StringIO()
67+
canvas.print_png(buf)
68+
buf_data = buf.getvalue()
69+
70+
return buf_data

codespeed/validators.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def validate_results_request(data):
66
Validates that a result request dictionary has all needed parameters
77
and their type is correct.
88
9-
Throws ValidationError on error
9+
Throws ValidationError on error.
1010
"""
1111
mandatory_data = [
1212
'env',
@@ -24,12 +24,23 @@ def validate_results_request(data):
2424
raise ValidationError('Value for key "' + key +
2525
'" empty in GET request!')
2626

27-
# Check that 'revs' is the correct format (if it exists)
28-
if 'revs' in data:
29-
try:
30-
rev_value = int(data['revs'])
31-
except ValueError:
32-
raise ValidationError('Value for key "revs" is not an integer!')
33-
if rev_value <= 0:
34-
raise ValidationError('Value for key "revs" should be a'
35-
' strictly positive integer!', True)
27+
integer_data = [
28+
'revs',
29+
'width',
30+
'height'
31+
]
32+
33+
"""
34+
Check that the items in integer_data are the correct format,
35+
if they exist
36+
"""
37+
for key in integer_data:
38+
if key in data:
39+
try:
40+
rev_value = int(data[key])
41+
except ValueError:
42+
raise ValidationError('Value for "' + key +
43+
'" is not an integer!')
44+
if rev_value <= 0:
45+
raise ValidationError('Value for "' + key + '" should be a'
46+
' strictly positive integer!')

codespeed/views.py

Lines changed: 8 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@
2323
from .results import save_result, create_report_if_enough_data
2424
from . import commits
2525
from .validators import validate_results_request
26-
27-
import cStringIO
28-
from matplotlib.figure import Figure
29-
from matplotlib.ticker import FormatStrFormatter
30-
from matplotlib.backends.backend_agg import FigureCanvasAgg
31-
26+
from .images import gen_image_from_results
3227

3328
logger = logging.getLogger(__name__)
3429

@@ -763,65 +758,17 @@ def makeimage(request):
763758
except ObjectDoesNotExist as err:
764759
return HttpResponseNotFound(str(err))
765760

766-
canvas_width = int(data['width']) if 'width' in data else 600
767-
canvas_height = int(data['height']) if 'height' in data else 500
768-
769-
canvas_width = max(canvas_width, 400)
770-
canvas_height = max(canvas_height, 300)
771-
772-
values = [element.value for element in result_data['results']]
773-
774-
max_value = max(values)
775-
min_value = min(values)
776-
value_range = max_value - min_value
777-
range_increment = 0.05 * abs(value_range)
778-
779-
fig = Figure(figsize=(canvas_width / 100, canvas_height / 100), dpi=100)
780-
ax = fig.add_axes([.1, .15, .85, .75])
781-
ax.set_ylim(min_value - range_increment, max_value + range_increment)
782-
783-
xax = range(0, len(values))
784-
yax = values
785-
786-
ax.set_xticks(xax)
787-
ax.set_xticklabels([element.date.strftime('%d %b') for element in
788-
result_data['results']], rotation=75)
789-
ax.set_title(result_data['benchmark'].name)
790-
791-
if result_data['relative']:
792-
ax.yaxis.set_major_formatter(FormatStrFormatter('%.3f%%'))
793-
794-
font_sizes = [16, 16]
795-
dimensions = [canvas_width, canvas_height]
796-
797-
for idx, value in enumerate(dimensions):
798-
if value < 500:
799-
font_sizes[idx] = 8
800-
elif value < 1000:
801-
font_sizes[idx] = 12
802-
803-
for item in ax.get_yticklabels():
804-
item.set_fontsize(font_sizes[0])
805-
806-
for item in ax.get_xticklabels():
807-
item.set_fontsize(font_sizes[1])
808-
809-
ax.title.set_fontsize(font_sizes[1] + 4)
810-
811-
ax.scatter(xax, yax)
812-
ax.plot(xax, yax)
813-
814-
canvas = FigureCanvasAgg(fig)
815-
buf = cStringIO.StringIO()
816-
canvas.print_png(buf)
817-
buf_data = buf.getvalue()
761+
image_data = gen_image_from_results(
762+
result_data,
763+
int(data['width']) if 'width' in data else None,
764+
int(data['height']) if 'height' in data else None)
818765

819766
if django_has_content_type():
820-
response = HttpResponse(content=buf_data, content_type='image/png')
767+
response = HttpResponse(content=image_data, content_type='image/png')
821768
else:
822-
response = HttpResponse(content=buf_data, mimetype='image/png')
769+
response = HttpResponse(content=image_data, mimetype='image/png')
823770

824-
response['Content-Length'] = len(buf_data)
771+
response['Content-Length'] = len(image_data)
825772
response['Content-Disposition'] = 'attachment; filename=image.png'
826773

827774
return response

0 commit comments

Comments
 (0)