# HG changeset patch
# User Santeri Piippo
# Date 1517402063 -7200
# Node ID 75f44d3063da27c1e6cfe5b8aab63ab0893e28aa
# Parent 02e7e1d73ebbe04ceed70ed734bee52cb3f72c1c
Reworked web front, problems are now sorted by category as well as line number
diff -r 02e7e1d73ebb -r 75f44d3063da ldcheck.py
--- a/ldcheck.py Wed Jan 24 23:14:01 2018 +0200
+++ b/ldcheck.py Wed Jan 31 14:34:23 2018 +0200
@@ -44,10 +44,6 @@
if (library_path / path).is_file()
]
-def hairline_score(smallest_angle):
- from math import log10
- return max(0, -log10(smallest_angle))
-
class Model:
def __init__(self, body):
self.body = body
diff -r 02e7e1d73ebb -r 75f44d3063da static/error.svg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/static/error.svg Wed Jan 31 14:34:23 2018 +0200
@@ -0,0 +1,74 @@
+
+
+
diff -r 02e7e1d73ebb -r 75f44d3063da static/favicon.ico
Binary file static/favicon.ico has changed
diff -r 02e7e1d73ebb -r 75f44d3063da static/notice.svg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/static/notice.svg Wed Jan 31 14:34:23 2018 +0200
@@ -0,0 +1,58 @@
+
+
+
diff -r 02e7e1d73ebb -r 75f44d3063da static/style.css
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/static/style.css Wed Jan 31 14:34:23 2018 +0200
@@ -0,0 +1,81 @@
+
+body
+{
+ font-family: sans-serif;
+ margin: 0;
+}
+
+.ldraw-code
+{
+ font-family: monospace;
+}
+
+.problems-list
+{
+ list-style: none;
+}
+
+.problems-list li
+{
+ padding: 5px;
+ border: 1px solid black;
+ border-radius: 10px;
+ margin-bottom: 3px;
+}
+
+.problems-list li.problem-error
+{
+ background-color: #b44;
+ border-color: red;
+ color: white;
+}
+
+.problems-list li.problem-warning
+{
+ background-color: #fc6;
+ border-color: #830;
+ color: black;
+}
+
+.problems-list li.problem-notice
+{
+ background-color: #def;
+ border-color: #024;
+ color: black;
+}
+
+.problem-icon
+{
+ float: left;
+ margin-right: 10px;
+}
+
+.top-form
+{
+ background: white;
+ background: linear-gradient(
+ to bottom,
+ #cceecf 0%,
+ #cceecf 85%,
+ #163 100%
+ );
+ padding-bottom: 2vh;
+ padding-top: 2vh;
+ padding-left: 5%;
+ padding-right: 5%;
+ text-align: center;
+}
+
+.report-container
+{
+ background: linear-gradient(
+ to bottom,
+ #ccc 0,
+ #fff 1vh,
+ #fff 100%
+ );
+ min-height: 10vh;
+ padding-left: 5%;
+ padding-right: 5%;
+ padding-top: 2vh;
+}
diff -r 02e7e1d73ebb -r 75f44d3063da static/warning.svg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/static/warning.svg Wed Jan 31 14:34:23 2018 +0200
@@ -0,0 +1,103 @@
+
+
diff -r 02e7e1d73ebb -r 75f44d3063da templates/webfront.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/webfront.html Wed Jan 31 14:34:23 2018 +0200
@@ -0,0 +1,40 @@
+
+
+
+
+
+ LDraw part verification tool
+
+
+
+
Check your part here
+
+
+
+
+{% if report %}
+
+ {% for problem in report['problems'] %}
+ -
+
+ Line {{problem['line-number']}}: {{problem['message']}}
+
+ {{problem['ldraw-code']}}
+
+ {% endfor %}
+
+{% endif %}
+{% if report and not report['problems'] %}
+No problems whatsoever.
+{% endif %}
+
+
+
+
diff -r 02e7e1d73ebb -r 75f44d3063da tests/quadrilaterals.py
--- a/tests/quadrilaterals.py Wed Jan 24 23:14:01 2018 +0200
+++ b/tests/quadrilaterals.py Wed Jan 31 14:34:23 2018 +0200
@@ -1,5 +1,5 @@
from math import radians
-from testsuite import warning, error
+from testsuite import warning, error, notice
from geometry import *
def sign_consistency(container):
@@ -58,12 +58,26 @@
if cross_product(b - a, c - a).length() < 1e-5:
yield error(element, 'collinearity-error')
+def hairline_score(smallest_angle):
+ from math import log10
+ return max(0, -log10(smallest_angle))
+
+def hairline_test(model):
+ for element in model.body:
+ if hasattr(element, 'geometry') and len(element.geometry.vertices) >= 3:
+ smallest_angle = element.geometry.smallest_angle
+ if smallest_angle < radians(0.5):
+ yield notice(element, 'hairline-warning',
+ smallest_angle = smallest_angle,
+ )
+
manifest = {
'tests': {
'skew': skew_test,
'concave': concave_test,
'bowtie': bowtie_test,
'collinearity': collinear_test,
+ 'hairline': hairline_test,
},
'messages': {
'skew-error': lambda skew_angle:
@@ -77,5 +91,9 @@
'concave-error': 'concave quadrilateral',
'self-intersecting': 'bowtie quadrilateral',
'collinearity-error': 'collinear polygon',
+ 'hairline-warning': lambda smallest_angle:
+ str.format('hairline polygon (smallest angle {})',
+ degree_rep(smallest_angle),
+ ),
},
}
diff -r 02e7e1d73ebb -r 75f44d3063da testsuite.py
--- a/testsuite.py Wed Jan 24 23:14:01 2018 +0200
+++ b/testsuite.py Wed Jan 31 14:34:23 2018 +0200
@@ -14,6 +14,9 @@
def error(bad_object, error_name, **args):
return report_element(bad_object, 'error', error_name, args)
+def notice(bad_object, error_name, **args):
+ return report_element(bad_object, 'notice', error_name, args)
+
def test_discovery():
'''
Finds all test modules and yields their names.
@@ -67,22 +70,31 @@
warn(str.format('Module {} does not have a manifest', module_name))
return test_suite
+def problem_key(problem):
+ problem_hierarchy = ['error', 'warning', 'notice']
+ return (problem_hierarchy.index(problem['type']), problem['line-number'])
+
def check_model(model, test_suite = None):
if not test_suite:
test_suite = load_tests()
- report = []
+ problems = []
line_numbers = {
element: (i, i + 1 + model.body_offset)
for i, element in enumerate(model.body)
}
for test_name, test_function in test_suite['tests'].items():
- problems = test_function(model)
- for problem in problems:
+ for problem in test_function(model):
problem['body-index'], problem['line-number'] \
= line_numbers[problem['object']]
del problem['object']
- report.append(problem)
- return report
+ problems.append(problem)
+ return {
+ 'passed': not any(
+ problem['type'] == 'error'
+ for problem in problems
+ ),
+ 'problems': sorted(problems, key = problem_key),
+ }
def problem_text(problem, test_suite):
message = test_suite['messages'][problem['name']]
@@ -91,8 +103,8 @@
return message
def format_report_html(report, model, test_suite):
- result = []
- for problem in report:
+ messages = []
+ for problem in report['problems']:
ldraw_code = model.body[problem['body-index']].textual_representation()
message = str.format(
'{model_name}:{line_number}:'
@@ -103,21 +115,20 @@
message = problem_text(problem, test_suite),
ldraw_code = ldraw_code,
)
- result.append((problem['line-number'], message))
- return '\n'.join(
- problem[1]
- for problem in sorted(result)
- )
+ messages.append(message)
+ return '\n'.join(messages)
def format_report(report, model, test_suite):
import colorama
colorama.init()
- result = []
- for problem in report:
+ messages = []
+ for problem in report['problems']:
if problem['type'] == 'error':
text_colour = colorama.Fore.LIGHTRED_EX
elif problem['type'] == 'warning':
text_colour = colorama.Fore.LIGHTYELLOW_EX
+ elif problem['type'] == 'notice':
+ text_colour = colorama.Fore.LIGHTBLUE_EX
else:
text_colour = ''
ldraw_code = model.body[problem['body-index']].textual_representation()
@@ -132,11 +143,8 @@
colour_reset = colorama.Fore.RESET,
ldraw_code = ldraw_code,
)
- result.append((problem['line-number'], message))
- return '\n'.join(
- problem[1]
- for problem in sorted(result)
- )
+ messages.append(message)
+ return '\n'.join(messages)
if __name__ == '__main__':
from pprint import pprint
diff -r 02e7e1d73ebb -r 75f44d3063da webfront.py
--- a/webfront.py Wed Jan 24 23:14:01 2018 +0200
+++ b/webfront.py Wed Jan 31 14:34:23 2018 +0200
@@ -1,7 +1,8 @@
+#!/usr/bin/env python3
from flask import Flask, render_template, redirect, request
from ldcheck import load_config, load_colours, find_ldconfig_ldr_paths
from ldcheck import read_ldraw
-from testsuite import load_tests, check_model, format_report_html
+from testsuite import load_tests, check_model, problem_text
app = Flask('LDCheck')
@@ -12,7 +13,6 @@
if 'file' not in request.files or not request.files['file'].filename:
return redirect(request.url)
file = request.files['file']
- print(type(file))
config = load_config('ldcheck.cfg')
for ldconfig_ldr_path in find_ldconfig_ldr_paths(config):
with ldconfig_ldr_path.open() as ldconfig_ldr:
@@ -24,18 +24,28 @@
)
test_suite = load_tests()
report = check_model(model, test_suite)
- return str.format(
- '',
- report = format_report_html(report, model, test_suite)
- )
- return '''
-
- Upload new File
- Upload new File
-
- '''
+
+ # Amend human-readable messages into the report
+ for problem in report['problems']:
+ object = model.body[problem['body-index']]
+ problem['message'] = problem_text(problem, test_suite)
+ problem['ldraw-code'] = object.textual_representation()
+ else:
+ report = None
+ return render_template('webfront.html',
+ report = report,
+ )
-app.run()
+@app.route('/static/')
+def static_file(path):
+ from flask import send_from_directory
+ from os import path
+ return send_from_directory(path.join('static', path))
+
+if __name__ == '__main__':
+ from argparse import ArgumentParser
+ parser = ArgumentParser()
+ parser.add_argument('-p', '--port', type = int, default = 5000)
+ parser.add_argument('-d', '--debug', action = 'store_true')
+ args = parser.parse_args()
+ app.run(port = args.port, debug = args.debug)