Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xblock-vectordraw
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
xblock-vectordraw
Commits
273232bc
Commit
273232bc
authored
Nov 02, 2015
by
Tim Krones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix PEP8 and pylint issues.
parent
a8382565
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
181 additions
and
28 deletions
+181
-28
vectordraw/__init__.py
+5
-0
vectordraw/grader.py
+132
-12
vectordraw/vectordraw.py
+44
-16
No files found.
vectordraw/__init__.py
View file @
273232bc
"""
Top-level package for Vector Drawing XBlock.
See vectordraw.vectordraw for more information.
"""
from
.vectordraw
import
VectorDrawXBlock
from
.vectordraw
import
VectorDrawXBlock
vectordraw/grader.py
View file @
273232bc
"""
This module contains grading logic for Vector Drawing exercises.
"""
# pylint: disable=invalid-name
import
inspect
import
inspect
import
json
import
logging
import
logging
import
math
import
math
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
# pylint: disable=invalid-name
#
#
Built-in check functions
# Built-in check functions
def
_errmsg
(
default_message
,
check
,
vectors
):
def
_errmsg
(
default_message
,
check
,
vectors
):
"""
Return error message for `check` targeting a vector from `vectors`.
If `check` does not define a custom error message, fall back on `default_message`.
"""
template
=
check
.
get
(
'errmsg'
,
default_message
)
template
=
check
.
get
(
'errmsg'
,
default_message
)
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
return
template
.
format
(
name
=
vec
.
name
,
return
template
.
format
(
name
=
vec
.
name
,
tail_x
=
vec
.
tail
.
x
,
tail_x
=
vec
.
tail
.
x
,
tail_y
=
vec
.
tail
.
y
,
tail_y
=
vec
.
tail
.
y
,
tip_x
=
vec
.
tip
.
x
,
tip_x
=
vec
.
tip
.
x
,
tip_y
=
vec
.
tip
.
y
,
tip_y
=
vec
.
tip
.
y
,
length
=
vec
.
length
,
length
=
vec
.
length
,
angle
=
vec
.
angle
)
angle
=
vec
.
angle
)
def
_errmsg_point
(
default_message
,
check
,
point
):
def
_errmsg_point
(
default_message
,
check
,
point
):
"""
Return error message for `check` targeting `point`.
If `check` does not define a custom error message, fall back on `default_message`.
"""
template
=
check
.
get
(
'errmsg'
,
default_message
)
template
=
check
.
get
(
'errmsg'
,
default_message
)
return
template
.
format
(
name
=
check
[
'point'
],
x
=
point
.
x
,
y
=
point
.
y
)
return
template
.
format
(
name
=
check
[
'point'
],
x
=
point
.
x
,
y
=
point
.
y
)
def
check_presence
(
check
,
vectors
):
def
check_presence
(
check
,
vectors
):
"""
Check if `vectors` contains vector targeted by `check`.
"""
if
check
[
'vector'
]
not
in
vectors
:
if
check
[
'vector'
]
not
in
vectors
:
errmsg
=
check
.
get
(
'errmsg'
,
'You need to use the {name} vector.'
)
errmsg
=
check
.
get
(
'errmsg'
,
'You need to use the {name} vector.'
)
return
errmsg
.
format
(
name
=
check
[
'vector'
])
return
errmsg
.
format
(
name
=
check
[
'vector'
])
def
check_tail
(
check
,
vectors
):
def
check_tail
(
check
,
vectors
):
"""
Check if tail of vector targeted by `check` is in correct position.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
expected
=
check
[
'expected'
]
expected
=
check
[
'expected'
]
...
@@ -37,7 +63,11 @@ def check_tail(check, vectors):
...
@@ -37,7 +63,11 @@ def check_tail(check, vectors):
if
dist
>
tolerance
:
if
dist
>
tolerance
:
return
_errmsg
(
'Vector {name} does not start at correct point.'
,
check
,
vectors
)
return
_errmsg
(
'Vector {name} does not start at correct point.'
,
check
,
vectors
)
def
check_tip
(
check
,
vectors
):
def
check_tip
(
check
,
vectors
):
"""
Check if tip of vector targeted by `check` is in correct position.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
expected
=
check
[
'expected'
]
expected
=
check
[
'expected'
]
...
@@ -45,38 +75,66 @@ def check_tip(check, vectors):
...
@@ -45,38 +75,66 @@ def check_tip(check, vectors):
if
dist
>
tolerance
:
if
dist
>
tolerance
:
return
_errmsg
(
'Vector {name} does not end at correct point.'
,
check
,
vectors
)
return
_errmsg
(
'Vector {name} does not end at correct point.'
,
check
,
vectors
)
def
_check_coordinate
(
check
,
coord
):
def
_check_coordinate
(
check
,
coord
):
"""
Check `coord` against expected value.
"""
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
expected
=
check
[
'expected'
]
expected
=
check
[
'expected'
]
return
abs
(
expected
-
coord
)
>
tolerance
return
abs
(
expected
-
coord
)
>
tolerance
def
check_tail_x
(
check
,
vectors
):
def
check_tail_x
(
check
,
vectors
):
"""
Check if x position of tail of vector targeted by `check` is correct.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
if
_check_coordinate
(
check
,
vec
.
tail
.
x
):
if
_check_coordinate
(
check
,
vec
.
tail
.
x
):
return
_errmsg
(
'Vector {name} does not start at correct point.'
,
check
,
vectors
)
return
_errmsg
(
'Vector {name} does not start at correct point.'
,
check
,
vectors
)
def
check_tail_y
(
check
,
vectors
):
def
check_tail_y
(
check
,
vectors
):
"""
Check if y position of tail of vector targeted by `check` is correct.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
if
_check_coordinate
(
check
,
vec
.
tail
.
y
):
if
_check_coordinate
(
check
,
vec
.
tail
.
y
):
return
_errmsg
(
'Vector {name} does not start at correct point.'
,
check
,
vectors
)
return
_errmsg
(
'Vector {name} does not start at correct point.'
,
check
,
vectors
)
def
check_tip_x
(
check
,
vectors
):
def
check_tip_x
(
check
,
vectors
):
"""
Check if x position of tip of vector targeted by `check` is correct.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
if
_check_coordinate
(
check
,
vec
.
tip
.
x
):
if
_check_coordinate
(
check
,
vec
.
tip
.
x
):
return
_errmsg
(
'Vector {name} does not end at correct point.'
,
check
,
vectors
)
return
_errmsg
(
'Vector {name} does not end at correct point.'
,
check
,
vectors
)
def
check_tip_y
(
check
,
vectors
):
def
check_tip_y
(
check
,
vectors
):
"""
Check if y position of tip of vector targeted by `check` is correct.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
if
_check_coordinate
(
check
,
vec
.
tip
.
y
):
if
_check_coordinate
(
check
,
vec
.
tip
.
y
):
return
_errmsg
(
'Vector {name} does not end at correct point.'
,
check
,
vectors
)
return
_errmsg
(
'Vector {name} does not end at correct point.'
,
check
,
vectors
)
def
_coord_delta
(
expected
,
actual
):
def
_coord_delta
(
expected
,
actual
):
"""
Return distance between `expected` and `actual` coordinates.
"""
if
expected
==
'_'
:
if
expected
==
'_'
:
return
0
return
0
else
:
else
:
return
expected
-
actual
return
expected
-
actual
def
_coords_within_tolerance
(
vec
,
expected
,
tolerance
):
def
_coords_within_tolerance
(
vec
,
expected
,
tolerance
):
"""
Check if distance between coordinates of `vec` and `expected` coordinates is within `tolerance`.
"""
for
expected_coords
,
vec_coords
in
([
expected
[
0
],
vec
.
tail
],
[
expected
[
1
],
vec
.
tip
]):
for
expected_coords
,
vec_coords
in
([
expected
[
0
],
vec
.
tail
],
[
expected
[
1
],
vec
.
tip
]):
delta_x
=
_coord_delta
(
expected_coords
[
0
],
vec_coords
.
x
)
delta_x
=
_coord_delta
(
expected_coords
[
0
],
vec_coords
.
x
)
delta_y
=
_coord_delta
(
expected_coords
[
1
],
vec_coords
.
y
)
delta_y
=
_coord_delta
(
expected_coords
[
1
],
vec_coords
.
y
)
...
@@ -84,14 +142,22 @@ def _coords_within_tolerance(vec, expected, tolerance):
...
@@ -84,14 +142,22 @@ def _coords_within_tolerance(vec, expected, tolerance):
return
False
return
False
return
True
return
True
def
check_coords
(
check
,
vectors
):
def
check_coords
(
check
,
vectors
):
"""
Check if coordinates of vector targeted by `check` are in correct position.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
expected
=
check
[
'expected'
]
expected
=
check
[
'expected'
]
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
if
not
_coords_within_tolerance
(
vec
,
expected
,
tolerance
):
if
not
_coords_within_tolerance
(
vec
,
expected
,
tolerance
):
return
_errmsg
(
'Vector {name} coordinates are not correct.'
,
check
,
vectors
)
return
_errmsg
(
'Vector {name} coordinates are not correct.'
,
check
,
vectors
)
def
check_segment_coords
(
check
,
vectors
):
def
check_segment_coords
(
check
,
vectors
):
"""
Check if coordinates of segment targeted by `check` are in correct position.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
expected
=
check
[
'expected'
]
expected
=
check
[
'expected'
]
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
...
@@ -99,13 +165,23 @@ def check_segment_coords(check, vectors):
...
@@ -99,13 +165,23 @@ def check_segment_coords(check, vectors):
_coords_within_tolerance
(
vec
.
opposite
(),
expected
,
tolerance
)):
_coords_within_tolerance
(
vec
.
opposite
(),
expected
,
tolerance
)):
return
_errmsg
(
'Segment {name} coordinates are not correct.'
,
check
,
vectors
)
return
_errmsg
(
'Segment {name} coordinates are not correct.'
,
check
,
vectors
)
def
check_length
(
check
,
vectors
):
def
check_length
(
check
,
vectors
):
"""
Check if length of vector targeted by `check` is correct.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
if
abs
(
vec
.
length
-
check
[
'expected'
])
>
tolerance
:
if
abs
(
vec
.
length
-
check
[
'expected'
])
>
tolerance
:
return
_errmsg
(
'The length of {name} is incorrect. Your length: {length:.1f}'
,
check
,
vectors
)
return
_errmsg
(
'The length of {name} is incorrect. Your length: {length:.1f}'
,
check
,
vectors
)
def
_angle_within_tolerance
(
vec
,
expected
,
tolerance
):
def
_angle_within_tolerance
(
vec
,
expected
,
tolerance
):
"""
Check if difference between angle of `vec` and `expected` angle is within `tolerance`.
"""
# Calculate angle between vec and identity vector with expected angle
# Calculate angle between vec and identity vector with expected angle
# using the formula:
# using the formula:
# angle = acos((A . B) / len(A)*len(B))
# angle = acos((A . B) / len(A)*len(B))
...
@@ -115,14 +191,22 @@ def _angle_within_tolerance(vec, expected, tolerance):
...
@@ -115,14 +191,22 @@ def _angle_within_tolerance(vec, expected, tolerance):
angle
=
math
.
degrees
(
math
.
acos
(
dot_product
/
vec
.
length
))
angle
=
math
.
degrees
(
math
.
acos
(
dot_product
/
vec
.
length
))
return
abs
(
angle
)
<=
tolerance
return
abs
(
angle
)
<=
tolerance
def
check_angle
(
check
,
vectors
):
def
check_angle
(
check
,
vectors
):
"""
Check if angle of vector targeted by `check` is correct.
"""
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
tolerance
=
check
.
get
(
'tolerance'
,
2.0
)
tolerance
=
check
.
get
(
'tolerance'
,
2.0
)
expected
=
math
.
radians
(
check
[
'expected'
])
expected
=
math
.
radians
(
check
[
'expected'
])
if
not
_angle_within_tolerance
(
vec
,
expected
,
tolerance
):
if
not
_angle_within_tolerance
(
vec
,
expected
,
tolerance
):
return
_errmsg
(
'The angle of {name} is incorrect. Your angle: {angle:.1f}'
,
check
,
vectors
)
return
_errmsg
(
'The angle of {name} is incorrect. Your angle: {angle:.1f}'
,
check
,
vectors
)
def
check_segment_angle
(
check
,
vectors
):
def
check_segment_angle
(
check
,
vectors
):
"""
Check if angle of segment targeted by `check` is correct.
"""
# Segments are not directed, so we must check the angle between the segment and
# Segments are not directed, so we must check the angle between the segment and
# the vector that represents it, as well as its opposite vector.
# the vector that represents it, as well as its opposite vector.
vec
=
vectors
[
check
[
'vector'
]]
vec
=
vectors
[
check
[
'vector'
]]
...
@@ -132,24 +216,38 @@ def check_segment_angle(check, vectors):
...
@@ -132,24 +216,38 @@ def check_segment_angle(check, vectors):
_angle_within_tolerance
(
vec
.
opposite
(),
expected
,
tolerance
)):
_angle_within_tolerance
(
vec
.
opposite
(),
expected
,
tolerance
)):
return
_errmsg
(
'The angle of {name} is incorrect. Your angle: {angle:.1f}'
,
check
,
vectors
)
return
_errmsg
(
'The angle of {name} is incorrect. Your angle: {angle:.1f}'
,
check
,
vectors
)
def
_dist_line_point
(
line
,
point
):
def
_dist_line_point
(
line
,
point
):
# Return the distance between the given line and point. The line is passed in as a Vector
"""
# instance, the point as a Point instance.
Return distance between `line` and `point`.
The line is passed in as a Vector instance, the point as a Point instance.
"""
direction_x
=
line
.
tip
.
x
-
line
.
tail
.
x
direction_x
=
line
.
tip
.
x
-
line
.
tail
.
x
direction_y
=
line
.
tip
.
y
-
line
.
tail
.
y
direction_y
=
line
.
tip
.
y
-
line
.
tail
.
y
determinant
=
(
point
.
x
-
line
.
tail
.
x
)
*
direction_y
-
(
point
.
y
-
line
.
tail
.
y
)
*
direction_x
determinant
=
(
point
.
x
-
line
.
tail
.
x
)
*
direction_y
-
(
point
.
y
-
line
.
tail
.
y
)
*
direction_x
return
abs
(
determinant
)
/
math
.
hypot
(
direction_x
,
direction_y
)
return
abs
(
determinant
)
/
math
.
hypot
(
direction_x
,
direction_y
)
def
check_points_on_line
(
check
,
vectors
):
def
check_points_on_line
(
check
,
vectors
):
"""
Check if line targeted by `check` passes through correct points.
"""
line
=
vectors
[
check
[
'vector'
]]
line
=
vectors
[
check
[
'vector'
]]
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
points
=
check
.
get
(
'expected'
)
points
=
check
.
get
(
'expected'
)
for
point
in
points
:
for
point
in
points
:
point
=
Point
(
point
[
0
],
point
[
1
])
point
=
Point
(
point
[
0
],
point
[
1
])
if
_dist_line_point
(
line
,
point
)
>
tolerance
:
if
_dist_line_point
(
line
,
point
)
>
tolerance
:
return
_errmsg
(
'The line {name} does not pass through the correct points.'
,
check
,
vectors
)
return
_errmsg
(
'The line {name} does not pass through the correct points.'
,
check
,
vectors
)
def
check_point_coords
(
check
,
points
):
def
check_point_coords
(
check
,
points
):
"""
Check if coordinates of point targeted by `check` are correct.
"""
point
=
points
[
check
[
'point'
]]
point
=
points
[
check
[
'point'
]]
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
tolerance
=
check
.
get
(
'tolerance'
,
1.0
)
expected
=
check
.
get
(
'expected'
)
expected
=
check
.
get
(
'expected'
)
...
@@ -157,13 +255,17 @@ def check_point_coords(check, points):
...
@@ -157,13 +255,17 @@ def check_point_coords(check, points):
if
dist
>
tolerance
:
if
dist
>
tolerance
:
return
_errmsg_point
(
'Point {name} is not at the correct location.'
,
check
,
point
)
return
_errmsg_point
(
'Point {name} is not at the correct location.'
,
check
,
point
)
class
Point
(
object
):
class
Point
(
object
):
""" Represents a single point on the vector drawing board. """
def
__init__
(
self
,
x
,
y
):
def
__init__
(
self
,
x
,
y
):
self
.
x
=
x
self
.
x
=
x
self
.
y
=
y
self
.
y
=
y
class
Vector
(
object
):
class
Vector
(
object
):
def
__init__
(
self
,
name
,
x1
,
y1
,
x2
,
y2
):
""" Represents a single vector on the vector drawing board. """
def
__init__
(
self
,
name
,
x1
,
y1
,
x2
,
y2
):
# pylint: disable=too-many-arguments
self
.
name
=
name
self
.
name
=
name
self
.
tail
=
Point
(
x1
,
y1
)
self
.
tail
=
Point
(
x1
,
y1
)
self
.
tip
=
Point
(
x2
,
y2
)
self
.
tip
=
Point
(
x2
,
y2
)
...
@@ -174,9 +276,16 @@ class Vector(object):
...
@@ -174,9 +276,16 @@ class Vector(object):
self
.
angle
=
angle
self
.
angle
=
angle
def
opposite
(
self
):
def
opposite
(
self
):
"""
Return new vector with tip and tail swapped.
"""
return
Vector
(
self
.
name
,
self
.
tip
.
x
,
self
.
tip
.
y
,
self
.
tail
.
x
,
self
.
tail
.
y
)
return
Vector
(
self
.
name
,
self
.
tip
.
x
,
self
.
tip
.
y
,
self
.
tail
.
x
,
self
.
tail
.
y
)
class
Grader
(
object
):
class
Grader
(
object
):
"""
Implements grading logic for student answers to Vector Drawing exercises.
"""
check_registry
=
{
check_registry
=
{
'presence'
:
check_presence
,
'presence'
:
check_presence
,
'tail'
:
check_tail
,
'tail'
:
check_tail
,
...
@@ -200,6 +309,11 @@ class Grader(object):
...
@@ -200,6 +309,11 @@ class Grader(object):
self
.
check_registry
.
update
(
custom_checks
)
self
.
check_registry
.
update
(
custom_checks
)
def
grade
(
self
,
answer
):
def
grade
(
self
,
answer
):
"""
Check correctness of `answer` by running checks defined for it one by one.
Short-circuit as soon as a single check fails.
"""
check_data
=
dict
(
check_data
=
dict
(
vectors
=
self
.
_get_vectors
(
answer
),
vectors
=
self
.
_get_vectors
(
answer
),
points
=
self
.
_get_points
(
answer
),
points
=
self
.
_get_points
(
answer
),
...
@@ -213,7 +327,10 @@ class Grader(object):
...
@@ -213,7 +327,10 @@ class Grader(object):
return
{
'ok'
:
False
,
'msg'
:
result
}
return
{
'ok'
:
False
,
'msg'
:
result
}
return
{
'ok'
:
True
,
'msg'
:
self
.
success_message
}
return
{
'ok'
:
True
,
'msg'
:
self
.
success_message
}
def
_get_vectors
(
self
,
answer
):
def
_get_vectors
(
self
,
answer
):
# pylint: disable=no-self-use
"""
Turn vector info in `answer` into a dictionary of Vector objects.
"""
vectors
=
{}
vectors
=
{}
for
name
,
props
in
answer
[
'vectors'
]
.
iteritems
():
for
name
,
props
in
answer
[
'vectors'
]
.
iteritems
():
tail
=
props
[
'tail'
]
tail
=
props
[
'tail'
]
...
@@ -221,5 +338,8 @@ class Grader(object):
...
@@ -221,5 +338,8 @@ class Grader(object):
vectors
[
name
]
=
Vector
(
name
,
tail
[
0
],
tail
[
1
],
tip
[
0
],
tip
[
1
])
vectors
[
name
]
=
Vector
(
name
,
tail
[
0
],
tail
[
1
],
tip
[
0
],
tip
[
1
])
return
vectors
return
vectors
def
_get_points
(
self
,
answer
):
def
_get_points
(
self
,
answer
):
# pylint: disable=no-self-use
"""
Turn point info in `answer` into a dictionary of Point objects.
"""
return
{
name
:
Point
(
*
coords
)
for
name
,
coords
in
answer
[
'points'
]
.
iteritems
()}
return
{
name
:
Point
(
*
coords
)
for
name
,
coords
in
answer
[
'points'
]
.
iteritems
()}
vectordraw/vectordraw.py
View file @
273232bc
...
@@ -13,9 +13,9 @@ from xblockutils.studio_editable import StudioEditableXBlockMixin
...
@@ -13,9 +13,9 @@ from xblockutils.studio_editable import StudioEditableXBlockMixin
from
.grader
import
Grader
from
.grader
import
Grader
loader
=
ResourceLoader
(
__name__
)
loader
=
ResourceLoader
(
__name__
)
# pylint: disable=invalid-name
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
# pylint: disable=invalid-name
class
VectorDrawXBlock
(
StudioEditableXBlockMixin
,
XBlock
):
class
VectorDrawXBlock
(
StudioEditableXBlockMixin
,
XBlock
):
...
@@ -131,7 +131,8 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -131,7 +131,8 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
display_name
=
"Vectors"
,
display_name
=
"Vectors"
,
help
=
(
help
=
(
"List of vectors to use for the exercise. "
"List of vectors to use for the exercise. "
"You must specify it as an array of entries where each entry represents an individual vector."
"You must specify it as an array of entries "
"where each entry represents an individual vector."
),
),
default
=
"[]"
,
default
=
"[]"
,
multiline_editor
=
True
,
multiline_editor
=
True
,
...
@@ -143,7 +144,8 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -143,7 +144,8 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
display_name
=
"Points"
,
display_name
=
"Points"
,
help
=
(
help
=
(
"List of points to be drawn on the board for reference, or to be placed by the student."
"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."
"You must specify it as an array of entries "
"where each entry represents an individual point."
),
),
default
=
"[]"
,
default
=
"[]"
,
multiline_editor
=
True
,
multiline_editor
=
True
,
...
@@ -167,7 +169,8 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -167,7 +169,8 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
display_name
=
"Custom checks"
,
display_name
=
"Custom checks"
,
help
=
(
help
=
(
'List of custom checks to use for grading. '
'List of custom checks to use for grading. '
'This is needed when grading is more complex and cannot be defined in terms of "Expected results" only.'
'This is needed when grading is more complex '
'and cannot be defined in terms of "Expected results" only.'
),
),
default
=
"[]"
,
default
=
"[]"
,
multiline_editor
=
True
,
multiline_editor
=
True
,
...
@@ -216,6 +219,9 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -216,6 +219,9 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
@property
@property
def
settings
(
self
):
def
settings
(
self
):
"""
Return settings for this exercise.
"""
return
{
return
{
'width'
:
self
.
width
,
'width'
:
self
.
width
,
'height'
:
self
.
height
,
'height'
:
self
.
height
,
...
@@ -227,13 +233,16 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -227,13 +233,16 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
'add_vector_label'
:
self
.
add_vector_label
,
'add_vector_label'
:
self
.
add_vector_label
,
'vector_properties_label'
:
self
.
vector_properties_label
,
'vector_properties_label'
:
self
.
vector_properties_label
,
'background'
:
self
.
background
,
'background'
:
self
.
background
,
'vectors'
:
self
.
vectors_json
,
'vectors'
:
self
.
get_vectors
,
'points'
:
self
.
points_json
,
'points'
:
self
.
get_points
,
'expected_result'
:
self
.
expected_result_json
'expected_result'
:
self
.
get_expected_result
}
}
@property
@property
def
user_state
(
self
):
def
user_state
(
self
):
"""
Return user state, which is a combination of most recent answer and result.
"""
user_state
=
self
.
answer
user_state
=
self
.
answer
if
self
.
result
:
if
self
.
result
:
user_state
[
'result'
]
=
self
.
result
user_state
[
'result'
]
=
self
.
result
...
@@ -241,6 +250,9 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -241,6 +250,9 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
@property
@property
def
background
(
self
):
def
background
(
self
):
"""
Return information about background to draw for this exercise.
"""
return
{
return
{
'src'
:
self
.
background_url
,
'src'
:
self
.
background_url
,
'width'
:
self
.
background_width
,
'width'
:
self
.
background_width
,
...
@@ -248,15 +260,25 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -248,15 +260,25 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
}
}
@property
@property
def
vectors_json
(
self
):
def
get_vectors
(
self
):
"""
Load info about vectors for this exercise from JSON string specified by course author.
"""
return
json
.
loads
(
self
.
vectors
)
return
json
.
loads
(
self
.
vectors
)
@property
@property
def
points_json
(
self
):
def
get_points
(
self
):
"""
Load info about points for this exercise from JSON string specified by course author.
"""
return
json
.
loads
(
self
.
points
)
return
json
.
loads
(
self
.
points
)
@property
@property
def
expected_result_json
(
self
):
def
get_expected_result
(
self
):
"""
Load info about expected result for this exercise
from JSON string specified by course author.
"""
return
json
.
loads
(
self
.
expected_result
)
return
json
.
loads
(
self
.
expected_result
)
def
student_view
(
self
,
context
=
None
):
def
student_view
(
self
,
context
=
None
):
...
@@ -267,14 +289,20 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -267,14 +289,20 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
context
[
'self'
]
=
self
context
[
'self'
]
=
self
fragment
=
Fragment
()
fragment
=
Fragment
()
fragment
.
add_content
(
loader
.
render_template
(
'static/html/vectordraw.html'
,
context
))
fragment
.
add_content
(
loader
.
render_template
(
'static/html/vectordraw.html'
,
context
))
fragment
.
add_css_url
(
"//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css"
)
fragment
.
add_css_url
(
"//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css"
)
fragment
.
add_css
(
loader
.
load_unicode
(
'static/css/vectordraw.css'
))
fragment
.
add_css
(
loader
.
load_unicode
(
'static/css/vectordraw.css'
))
fragment
.
add_javascript_url
(
"//cdnjs.cloudflare.com/ajax/libs/jsxgraph/0.98/jsxgraphcore.js"
)
fragment
.
add_javascript_url
(
"//cdnjs.cloudflare.com/ajax/libs/jsxgraph/0.98/jsxgraphcore.js"
)
fragment
.
add_javascript
(
loader
.
load_unicode
(
"static/js/src/vectordraw.js"
))
fragment
.
add_javascript
(
loader
.
load_unicode
(
"static/js/src/vectordraw.js"
))
fragment
.
initialize_js
(
'VectorDrawXBlock'
,
{
"settings"
:
self
.
settings
,
"user_state"
:
self
.
user_state
})
fragment
.
initialize_js
(
'VectorDrawXBlock'
,
{
"settings"
:
self
.
settings
,
"user_state"
:
self
.
user_state
}
)
return
fragment
return
fragment
def
is_valid
(
self
,
data
):
def
is_valid
(
self
,
data
):
# pylint: disable=no-self-use
"""
"""
Validate answer data submitted by user.
Validate answer data submitted by user.
"""
"""
...
@@ -308,7 +336,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
...
@@ -308,7 +336,7 @@ class VectorDrawXBlock(StudioEditableXBlockMixin, XBlock):
return
'checks'
in
data
return
'checks'
in
data
@XBlock.json_handler
@XBlock.json_handler
def
check_answer
(
self
,
data
,
suffix
=
''
):
def
check_answer
(
self
,
data
,
suffix
=
''
):
# pylint: disable=unused-argument
"""
"""
Check and persist student's answer to this vector drawing problem.
Check and persist student's answer to this vector drawing problem.
"""
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment