Commit d2a9f6e2 by Tim Krones

Address upstream review comments.

parent 792d4ba5
django>=1.4, <1.5
pyyaml
-e git+https://github.com/edx/XBlock.git@tag-master-2015-05-22#egg=XBlock
-e git+https://github.com/edx/xblock-utils.git@b4f9b51146c7fafa12f41d54af752b8f1516dffd#egg=xblock-utils
......
django>=1.4, <1.5
-r requirements.txt
-e git+https://github.com/edx/xblock-sdk.git@629650ed6fc1b77d1a5287debeace0b29db7c0fd#egg=xblock-sdk
ddt
......
"""
This module contains grading logic for Vector Drawing exercises.
It uses the following data structures:
- `vectors`: A dictionary of Vector objects.
Keys are vector names and values represent individual vectors that were present
on the drawing board when the student submitted an answer by clicking the 'Check' button.
- `points`: A dictionary of Point objects.
Keys are point names and values represent individual points that were present
on the drawing board when the student submitted an answer by clicking the 'Check' button.
- `check`: A dictionary representing a specific check.
Contains the name of the check itself (e.g., 'presence', 'coords', 'angle'),
the name of the element on which to perform the check, as well as
the expected value of the property being checked.
Optionally contains information about tolerance to apply when performing the check,
and/or a custom error message to present to the user if the check fails.
- `answer`: A dictionary representing a specific answer submitted by a student.
Contains three entries: vectors, points, and checks. The first two (vectors, points)
provide information about vectors and points present on the drawing board
when the answer was submitted. The third one (checks) specifies the checks
to perform for individual vectors and points.
"""
# pylint: disable=invalid-name
......@@ -52,28 +80,36 @@ def check_presence(check, vectors):
return errmsg.format(name=check['vector'])
def check_tail(check, vectors):
def _check_vector_endpoint(check, vectors, endpoint):
"""
Check if tail of vector targeted by `check` is in correct position.
Check if `endpoint` (tail or tip) of vector targeted by `check` is in correct position.
"""
vec = vectors[check['vector']]
tolerance = check.get('tolerance', 1.0)
expected = check['expected']
dist = math.hypot(expected[0] - vec.tail.x, expected[1] - vec.tail.y)
verb = 'start' if endpoint == 'tail' else 'end'
endpoint = getattr(vec, endpoint)
dist = math.hypot(expected[0] - endpoint.x, expected[1] - endpoint.y)
if dist > tolerance:
return _errmsg('Vector {name} does not start at correct point.', check, vectors)
return _errmsg(
'Vector {name} does not {verb} at correct point.'.format(name='{name}', verb=verb),
check,
vectors
)
def check_tail(check, vectors):
"""
Check if tail of vector targeted by `check` is in correct position.
"""
return _check_vector_endpoint(check, vectors, endpoint='tail')
def check_tip(check, vectors):
"""
Check if tip of vector targeted by `check` is in correct position.
"""
vec = vectors[check['vector']]
tolerance = check.get('tolerance', 1.0)
expected = check['expected']
dist = math.hypot(expected[0] - vec.tip.x, expected[1] - vec.tip.y)
if dist > tolerance:
return _errmsg('Vector {name} does not end at correct point.', check, vectors)
return _check_vector_endpoint(check, vectors, endpoint='tip')
def _check_coordinate(check, coord):
......@@ -235,7 +271,7 @@ def check_points_on_line(check, vectors):
"""
line = vectors[check['vector']]
tolerance = check.get('tolerance', 1.0)
points = check.get('expected')
points = check['expected']
for point in points:
point = Point(point[0], point[1])
if _dist_line_point(line, point) > tolerance:
......@@ -250,7 +286,7 @@ def check_point_coords(check, points):
"""
point = points[check['point']]
tolerance = check.get('tolerance', 1.0)
expected = check.get('expected')
expected = check['expected']
dist = math.hypot(expected[0] - point.x, expected[1] - point.y)
if dist > tolerance:
return _errmsg_point('Point {name} is not at the correct location.', check, point)
......
......@@ -43,7 +43,7 @@
aria-describedby="{{field.name}}-help"
rows=10 cols=70>{{field.value}}</textarea>
{% else %}
Unsupported field type. This setting cannot be edited.
{% trans "Unsupported field type. This setting cannot be edited." %}
{% endif %}
{% if field.allow_reset %}
......@@ -57,7 +57,7 @@
{% endif %}
</div>
{% if field.help %}
<span id="{{field.name}}-help" class="tip setting-help"> {{ field.help }} </span>
<span id="{{field.name}}-help" class="tip setting-help"> {{ field.help|safe }} </span>
{% endif %}
</li>
{% endfor %}
......
"""
This module contains utility functions for the Vector Drawing XBlock.
"""
def get_doc_link(section, link_text="here"):
"""
Return link to specific `section` of README for Vector Drawing exercises.
"""
return (
'<a href="https://github.com/open-craft/jsinput-vectordraw#{section}" target="_blank">'
'{link_text}'
'</a>'
).format(section=section, link_text=link_text)
......@@ -18,6 +18,7 @@ except ImportError:
WorkbenchRuntime = False # pylint: disable=invalid-name
from .grader import Grader
from .utils import get_doc_link
loader = ResourceLoader(__name__) # pylint: disable=invalid-name
......@@ -151,10 +152,11 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
"List of vectors to use for the exercise. "
"You must specify it as an array of entries "
"where each entry represents an individual vector. "
"See {doc_link} for more information. "
"Note that you can also use the WYSIWYG editor below to create or modify vectors. "
"If you do, any changes you make here will be overwritten by vector data "
"from the WYSIWYG editor when saving."
),
).format(doc_link=get_doc_link('vectors')),
default="[]",
multiline_editor=True,
resettable_editor=False,
......@@ -166,8 +168,9 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
help=(
"List of points to be drawn on the board for reference, or to be placed by the student."
"You must specify it as an array of entries "
"where each entry represents an individual point."
),
"where each entry represents an individual point. "
"See {doc_link} for more information."
).format(doc_link=get_doc_link('points')),
default="[]",
multiline_editor=True,
resettable_editor=False,
......@@ -178,12 +181,16 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
display_name="Expected result",
help=(
"Defines vector properties for grading. "
"You must specify it as a JSON object where each key is the name of an existing vector "
"and each value is a JSON object containing information about checks to perform "
"and expected values. "
"See {doc_link} for more information. "
"Vectors omitted from this setting are ignored when grading. "
"Note that you can also use the WYSIWYG editor below to opt in and out of checks "
"for individual vectors. "
"If you use the WYSIWYG editor at all, any changes you make here "
"will be overwritten when saving."
),
).format(doc_link=get_doc_link('expected_result')),
default="{}",
multiline_editor=True,
resettable_editor=False,
......@@ -328,9 +335,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
for vector in json.loads(self.vectors):
default_vector = self._get_default_vector()
default_vector_style = default_vector['style']
if 'style' in vector:
default_vector_style.update(vector['style'])
del vector['style']
default_vector_style.update(vector.pop('style', {}))
default_vector.update(vector)
vectors.append(default_vector)
return vectors
......@@ -362,9 +367,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
for point in json.loads(self.points):
default_point = self._get_default_point()
default_point_style = default_point['style']
if 'style' in point:
default_point_style.update(point['style'])
del point['style']
default_point_style.update(point.pop('style', {}))
default_point.update(point)
default_point_style['name'] = default_point['name']
default_point_style['fixed'] = default_point['fixed']
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment