Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
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
edx-platform
Commits
1d214731
Commit
1d214731
authored
Oct 26, 2012
by
Александр
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-alex-vsepr-mitx'
parents
638d0653
9558629e
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
255 additions
and
5 deletions
+255
-5
common/lib/capa/capa/capa_problem.py
+6
-2
common/lib/capa/capa/chem/chemtools.py
+136
-0
common/lib/capa/capa/inputtypes.py
+53
-2
common/lib/capa/capa/responsetypes.py
+2
-1
common/lib/capa/capa/templates/vsepr_input.html
+58
-0
No files found.
common/lib/capa/capa/capa_problem.py
View file @
1d214731
...
@@ -32,6 +32,8 @@ from xml.sax.saxutils import unescape
...
@@ -32,6 +32,8 @@ from xml.sax.saxutils import unescape
import
chem
import
chem
import
chem.chemcalc
import
chem.chemcalc
import
chem.chemtools
import
calc
import
calc
from
correctmap
import
CorrectMap
from
correctmap
import
CorrectMap
import
eia
import
eia
...
@@ -57,7 +59,8 @@ entry_types = ['textline',
...
@@ -57,7 +59,8 @@ entry_types = ['textline',
'filesubmission'
,
'filesubmission'
,
'javascriptinput'
,
'javascriptinput'
,
'crystallography'
,
'crystallography'
,
'chemicalequationinput'
,]
'chemicalequationinput'
,
'vsepr_input'
]
# extra things displayed after "show answers" is pressed
# extra things displayed after "show answers" is pressed
solution_types
=
[
'solution'
]
solution_types
=
[
'solution'
]
...
@@ -77,7 +80,8 @@ global_context = {'random': random,
...
@@ -77,7 +80,8 @@ global_context = {'random': random,
'scipy'
:
scipy
,
'scipy'
:
scipy
,
'calc'
:
calc
,
'calc'
:
calc
,
'eia'
:
eia
,
'eia'
:
eia
,
'chemcalc'
:
chem
.
chemcalc
}
'chemcalc'
:
chem
.
chemcalc
,
'chemtools'
:
chem
.
chemtools
}
# These should be removed from HTML output, including all subelements
# These should be removed from HTML output, including all subelements
html_problem_semantics
=
[
"codeparam"
,
"responseparam"
,
"answer"
,
"script"
,
"hintgroup"
]
html_problem_semantics
=
[
"codeparam"
,
"responseparam"
,
"answer"
,
"script"
,
"hintgroup"
]
...
...
common/lib/capa/capa/chem/chemtools.py
0 → 100644
View file @
1d214731
from
collections
import
OrderedDict
import
json
import
unittest
def
vsepr_parse_user_answer
(
user_input
):
d
=
OrderedDict
(
json
.
loads
(
user_input
))
d
[
'atoms'
]
=
OrderedDict
(
sorted
(
d
[
'atoms'
]
.
items
()))
return
d
def
vsepr_build_correct_answer
(
geometry
,
atoms
):
correct_answer
=
OrderedDict
()
correct_answer
[
'geometry'
]
=
geometry
correct_answer
[
'atoms'
]
=
OrderedDict
(
sorted
(
atoms
.
items
()))
return
correct_answer
def
vsepr_grade
(
user_input
,
correct_answer
,
ignore_p_order
=
False
,
ignore_a_order
=
False
,
ignore_e_order
=
False
):
""" Flags ignore_(a,p,e)_order are for checking order in axial, perepherial or equatorial positions.
Allowed cases:
c0, a, e
c0, p
Not implemented and not tested cases when p with a or e (no need for now)
"""
# print user_input, type(user_input)
# print correct_answer, type(correct_answer)
if
user_input
[
'geometry'
]
!=
correct_answer
[
'geometry'
]:
return
False
if
user_input
[
'atoms'
][
'c0'
]
!=
correct_answer
[
'atoms'
][
'c0'
]:
return
False
# not order-aware comparisons
for
ignore
in
[(
ignore_p_order
,
'p'
),
(
ignore_e_order
,
'e'
),
(
ignore_a_order
,
'a'
)]:
if
ignore
[
0
]:
# collecting atoms:
a_user
=
[
v
for
k
,
v
in
user_input
[
'atoms'
]
.
items
()
if
k
.
startswith
(
ignore
[
1
])]
a_correct
=
[
v
for
k
,
v
in
correct_answer
[
'atoms'
]
.
items
()
if
k
.
startswith
(
ignore
[
1
])]
# print ignore[0], ignore[1], a_user, a_correct
if
len
(
a_user
)
!=
len
(
a_correct
):
return
False
if
sorted
(
a_user
)
!=
sorted
(
a_correct
):
return
False
# order-aware comparisons
for
ignore
in
[(
ignore_p_order
,
'p'
),
(
ignore_e_order
,
'e'
),
(
ignore_a_order
,
'a'
)]:
if
not
ignore
[
0
]:
# collecting atoms:
a_user
=
[
v
for
k
,
v
in
user_input
[
'atoms'
]
.
items
()
if
k
.
startswith
(
ignore
[
1
])]
a_correct
=
[
v
for
k
,
v
in
correct_answer
[
'atoms'
]
.
items
()
if
k
.
startswith
(
ignore
[
1
])]
# print '2nd', ignore[0], ignore[1], a_user, a_correct
if
len
(
a_user
)
!=
len
(
a_correct
):
return
False
if
len
(
a_correct
)
==
0
:
continue
if
a_user
!=
a_correct
:
return
False
return
True
class
Test_Grade
(
unittest
.
TestCase
):
''' test grade function '''
def
test_incorrect_geometry
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX4E0"
,
atoms
=
{
"c0"
:
"N"
,
"p0"
:
"H"
,
"p1"
:
"(ep)"
,
"p2"
:
"H"
,
"p3"
:
"H"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX3E0","atoms":{"c0":"B","p0":"F","p1":"B","p2":"F"}}'
)
self
.
assertFalse
(
vsepr_grade
(
user_answer
,
correct_answer
))
def
test_incorrect_positions
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX4E0"
,
atoms
=
{
"c0"
:
"N"
,
"p0"
:
"H"
,
"p1"
:
"(ep)"
,
"p2"
:
"H"
,
"p3"
:
"H"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX4E0","atoms":{"c0":"B","p0":"F","p1":"B","p2":"F"}}'
)
self
.
assertFalse
(
vsepr_grade
(
user_answer
,
correct_answer
))
def
test_correct_answer
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX4E0"
,
atoms
=
{
"c0"
:
"N"
,
"p0"
:
"H"
,
"p1"
:
"(ep)"
,
"p2"
:
"H"
,
"p3"
:
"H"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX4E0","atoms":{"c0":"N","p0":"H","p1":"(ep)","p2":"H", "p3":"H"}}'
)
self
.
assertTrue
(
vsepr_grade
(
user_answer
,
correct_answer
))
def
test_incorrect_position_order_p
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX4E0"
,
atoms
=
{
"c0"
:
"N"
,
"p0"
:
"H"
,
"p1"
:
"(ep)"
,
"p2"
:
"H"
,
"p3"
:
"H"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX4E0","atoms":{"c0":"N","p0":"H","p1":"H","p2":"(ep)", "p3":"H"}}'
)
self
.
assertFalse
(
vsepr_grade
(
user_answer
,
correct_answer
))
def
test_correct_position_order_with_ignore_p_order
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX4E0"
,
atoms
=
{
"c0"
:
"N"
,
"p0"
:
"H"
,
"p1"
:
"(ep)"
,
"p2"
:
"H"
,
"p3"
:
"H"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX4E0","atoms":{"c0":"N","p0":"H","p1":"H","p2":"(ep)", "p3":"H"}}'
)
self
.
assertTrue
(
vsepr_grade
(
user_answer
,
correct_answer
,
ignore_p_order
=
True
))
def
test_incorrect_position_order_ae
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX6E0"
,
atoms
=
{
"c0"
:
"Br"
,
"a0"
:
"test"
,
"a1"
:
"(ep)"
,
"e0"
:
"H"
,
"e1"
:
"H"
,
"e2"
:
"(ep)"
,
"e3"
:
"(ep)"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX6E0","atoms":{"c0":"Br","a0":"test","a1":"(ep)","e0":"H","e1":"(ep)","e2":"(ep)","e3":"(ep)"}}'
)
self
.
assertFalse
(
vsepr_grade
(
user_answer
,
correct_answer
))
def
test_correct_position_order_with_ignore_a_order_not_e
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX6E0"
,
atoms
=
{
"c0"
:
"Br"
,
"a0"
:
"(ep)"
,
"a1"
:
"test"
,
"e0"
:
"H"
,
"e1"
:
"H"
,
"e2"
:
"(ep)"
,
"e3"
:
"(ep)"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX6E0","atoms":{"c0":"Br","a0":"test","a1":"(ep)","e0":"H","e1":"H","e2":"(ep)","e3":"(ep)"}}'
)
self
.
assertTrue
(
vsepr_grade
(
user_answer
,
correct_answer
,
ignore_a_order
=
True
))
def
test_incorrect_position_order_with_ignore_a_order_not_e
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX6E0"
,
atoms
=
{
"c0"
:
"Br"
,
"a0"
:
"(ep)"
,
"a1"
:
"test"
,
"e0"
:
"H"
,
"e1"
:
"H"
,
"e2"
:
"H"
,
"e3"
:
"(ep)"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX6E0","atoms":{"c0":"Br","a0":"test","a1":"(ep)","e0":"H","e1":"H","e2":"(ep)","e3":"H"}}'
)
self
.
assertFalse
(
vsepr_grade
(
user_answer
,
correct_answer
,
ignore_a_order
=
True
))
def
test_correct_position_order_with_ignore_e_order_not_a
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX6E0"
,
atoms
=
{
"c0"
:
"Br"
,
"a0"
:
"(ep)"
,
"a1"
:
"test"
,
"e0"
:
"H"
,
"e1"
:
"H"
,
"e2"
:
"H"
,
"e3"
:
"(ep)"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX6E0","atoms":{"c0":"Br","a0":"(ep)","a1":"test","e0":"H","e1":"H","e2":"(ep)","e3":"H"}}'
)
self
.
assertTrue
(
vsepr_grade
(
user_answer
,
correct_answer
,
ignore_e_order
=
True
))
def
test_incorrect_position_order_with_ignore_e_order__not_a
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX6E0"
,
atoms
=
{
"c0"
:
"Br"
,
"a0"
:
"(ep)"
,
"a1"
:
"test"
,
"e0"
:
"H"
,
"e1"
:
"H"
,
"e2"
:
"H"
,
"e3"
:
"(ep)"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX6E0","atoms":{"c0":"Br","a0":"test","a1":"(ep)","e0":"H","e1":"H","e2":"(ep)","e3":"H"}}'
)
self
.
assertFalse
(
vsepr_grade
(
user_answer
,
correct_answer
,
ignore_e_order
=
True
))
def
test_correct_position_order_with_ignore_ae_order
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX6E0"
,
atoms
=
{
"c0"
:
"Br"
,
"a0"
:
"(ep)"
,
"a1"
:
"test"
,
"e0"
:
"H"
,
"e1"
:
"H"
,
"e2"
:
"H"
,
"e3"
:
"(ep)"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX6E0","atoms":{"c0":"Br","a0":"test","a1":"(ep)","e0":"H","e1":"H","e2":"(ep)","e3":"H"}}'
)
self
.
assertTrue
(
vsepr_grade
(
user_answer
,
correct_answer
,
ignore_e_order
=
True
,
ignore_a_order
=
True
))
def
test_incorrect_c0
(
self
):
correct_answer
=
vsepr_build_correct_answer
(
geometry
=
"AX6E0"
,
atoms
=
{
"c0"
:
"Br"
,
"a0"
:
"(ep)"
,
"a1"
:
"test"
,
"e0"
:
"H"
,
"e1"
:
"H"
,
"e2"
:
"H"
,
"e3"
:
"(ep)"
})
user_answer
=
vsepr_parse_user_answer
(
u'{"geometry":"AX6E0","atoms":{"c0":"H","a0":"test","a1":"(ep)","e0":"H","e1":"H","e2":"(ep)","e3":"H"}}'
)
self
.
assertFalse
(
vsepr_grade
(
user_answer
,
correct_answer
,
ignore_e_order
=
True
,
ignore_a_order
=
True
))
def
suite
():
testcases
=
[
Test_Grade
]
suites
=
[]
for
testcase
in
testcases
:
suites
.
append
(
unittest
.
TestLoader
()
.
loadTestsFromTestCase
(
testcase
))
return
unittest
.
TestSuite
(
suites
)
if
__name__
==
"__main__"
:
unittest
.
TextTestRunner
(
verbosity
=
2
)
.
run
(
suite
())
common/lib/capa/capa/inputtypes.py
View file @
1d214731
...
@@ -707,7 +707,7 @@ def imageinput(element, value, status, render_template, msg=''):
...
@@ -707,7 +707,7 @@ def imageinput(element, value, status, render_template, msg=''):
_reg
(
imageinput
)
_reg
(
imageinput
)
#-----------------------------------------------------------------------------
def
crystallography
(
element
,
value
,
status
,
render_template
,
msg
=
''
):
def
crystallography
(
element
,
value
,
status
,
render_template
,
msg
=
''
):
eid
=
element
.
get
(
'id'
)
eid
=
element
.
get
(
'id'
)
if
eid
is
None
:
if
eid
is
None
:
...
@@ -740,18 +740,69 @@ def crystallography(element, value, status, render_template, msg=''):
...
@@ -740,18 +740,69 @@ def crystallography(element, value, status, render_template, msg=''):
}
}
html
=
render_template
(
"crystallography.html"
,
context
)
html
=
render_template
(
"crystallography.html"
,
context
)
try
:
try
:
xhtml
=
etree
.
XML
(
html
)
xhtml
=
etree
.
XML
(
html
)
except
Exception
as
err
:
except
Exception
as
err
:
# TODO: needs to be self.system.DEBUG - but can't access system
# TODO: needs to be self.system.DEBUG - but can't access system
if
True
:
if
True
:
log
.
debug
(
'[inputtypes.
textline
] failed to parse XML for:
\n
%
s'
%
html
)
log
.
debug
(
'[inputtypes.
crystallography
] failed to parse XML for:
\n
%
s'
%
html
)
raise
raise
return
xhtml
return
xhtml
_reg
(
crystallography
)
_reg
(
crystallography
)
def
vsepr_input
(
element
,
value
,
status
,
render_template
,
msg
=
''
):
eid
=
element
.
get
(
'id'
)
if
eid
is
None
:
msg
=
'cryst has no id: it probably appears outside of a known response type'
msg
+=
"
\n
See problem XML source line
%
s"
%
getattr
(
element
,
'sourceline'
,
'<unavailable>'
)
raise
Exception
(
msg
)
height
=
element
.
get
(
'height'
)
width
=
element
.
get
(
'width'
)
display_file
=
element
.
get
(
'display_file'
)
count
=
int
(
eid
.
split
(
'_'
)[
-
2
])
-
1
# HACK
size
=
element
.
get
(
'size'
)
# if specified, then textline is hidden and id is stored in div of name given by hidden
hidden
=
element
.
get
(
'hidden'
,
''
)
# Escape answers with quotes, so they don't crash the system!
escapedict
=
{
'"'
:
'"'
}
value
=
saxutils
.
escape
(
value
,
escapedict
)
molecules
=
element
.
get
(
'molecules'
)
geometries
=
element
.
get
(
'geometries'
)
context
=
{
'id'
:
eid
,
'value'
:
value
,
'state'
:
status
,
'count'
:
count
,
'size'
:
size
,
'msg'
:
msg
,
'hidden'
:
hidden
,
'inline'
:
element
.
get
(
'inline'
,
''
),
'width'
:
width
,
'height'
:
height
,
'display_file'
:
display_file
,
'molecules'
:
molecules
,
'geometries'
:
geometries
,
}
html
=
render_template
(
"vsepr_input.html"
,
context
)
try
:
xhtml
=
etree
.
XML
(
html
)
except
Exception
as
err
:
# TODO: needs to be self.system.DEBUG - but can't access system
if
True
:
log
.
debug
(
'[inputtypes.vsepr_input] failed to parse XML for:
\n
%
s'
%
html
)
raise
return
xhtml
_reg
(
vsepr_input
)
#--------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
...
...
common/lib/capa/capa/responsetypes.py
View file @
1d214731
...
@@ -867,7 +867,8 @@ def sympy_check2():
...
@@ -867,7 +867,8 @@ def sympy_check2():
</customresponse>"""
}]
</customresponse>"""
}]
response_tag
=
'customresponse'
response_tag
=
'customresponse'
allowed_inputfields
=
[
'textline'
,
'textbox'
,
'crystallography'
,
'chemicalequationinput'
]
allowed_inputfields
=
[
'textline'
,
'textbox'
,
'crystallography'
,
'chemicalequationinput'
,
'vsepr_input'
]
def
setup_response
(
self
):
def
setup_response
(
self
):
xml
=
self
.
xml
xml
=
self
.
xml
...
...
common/lib/capa/capa/templates/vsepr_input.html
0 → 100644
View file @
1d214731
<
%
doinline =
"inline"
if
inline
else
""
%
>
<section
id=
"textinput_${id}"
class=
"textinput ${doinline}"
>
<table><tr><td
height=
'600'
>
<div
id=
"vsepr_div_${id}"
style=
"position:relative;"
data-molecules=
"${molecules}"
data-geometries=
"${geometries}"
>
<canvas
id=
"vsepr_canvas_${id}"
width=
"${width}"
height=
"${height}"
>
</canvas>
</div>
</td><td
valign =
'top'
>
<select
class=
"molecule_select"
id=
"molecule_select_${id}"
size=
"18"
>
</select>
</td></tr></table>
<div
class=
"script_placeholder"
data-src=
"/static/js/vsepr/vsepr.js"
></div>
% if state == 'unsubmitted':
<div
class=
"unanswered ${doinline}"
id=
"status_${id}"
>
% elif state == 'correct':
<div
class=
"correct ${doinline}"
id=
"status_${id}"
>
% elif state == 'incorrect':
<div
class=
"incorrect ${doinline}"
id=
"status_${id}"
>
% elif state == 'incomplete':
<div
class=
"incorrect ${doinline}"
id=
"status_${id}"
>
% endif
% if hidden:
<div
style=
"display:none;"
name=
"${hidden}"
inputid=
"input_${id}"
/>
% endif
<input
type=
"text"
name=
"input_${id}"
id=
"input_${id}"
value=
"${value}"
%
if
size:
size=
"${size}"
%
endif
%
if
hidden:
style=
"display:none;"
%
endif
/>
<p
class=
"status"
>
% if state == 'unsubmitted':
unanswered
% elif state == 'correct':
correct
% elif state == 'incorrect':
incorrect
% elif state == 'incomplete':
incomplete
% endif
</p>
<p
id=
"answer_${id}"
class=
"answer"
></p>
% if msg:
<span
class=
"message"
>
${msg|n}
</span>
% endif
% if state in ['unsubmitted', 'correct', 'incorrect', 'incomplete'] or hidden:
</div>
% endif
</section>
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