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
7deb043e
Commit
7deb043e
authored
Jun 07, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Doing some stylistic cleanup on capa_module.py
parent
a916f0ff
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
74 additions
and
71 deletions
+74
-71
common/lib/xmodule/capa_module.py
+74
-71
No files found.
common/lib/xmodule/capa_module.py
View file @
7deb043e
...
@@ -17,14 +17,16 @@ log = logging.getLogger("mitx.courseware")
...
@@ -17,14 +17,16 @@ log = logging.getLogger("mitx.courseware")
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
TIMEDELTA_REGEX
=
re
.
compile
(
r'^((?P<days>\d+?) day(?:s?))?(\s)?((?P<hours>\d+?) hour(?:s?))?(\s)?((?P<minutes>\d+?) minute(?:s)?)?(\s)?((?P<seconds>\d+?) second(?:s)?)?$'
)
TIMEDELTA_REGEX
=
re
.
compile
(
r'^((?P<days>\d+?) day(?:s?))?(\s)?((?P<hours>\d+?) hour(?:s?))?(\s)?((?P<minutes>\d+?) minute(?:s)?)?(\s)?((?P<seconds>\d+?) second(?:s)?)?$'
)
def
item
(
l
,
default
=
""
,
process
=
lambda
x
:
x
):
if
len
(
l
)
==
0
:
def
item
(
l
,
default
=
""
,
process
=
lambda
x
:
x
):
if
len
(
l
)
==
0
:
return
default
return
default
elif
len
(
l
)
==
1
:
elif
len
(
l
)
==
1
:
return
process
(
l
[
0
])
return
process
(
l
[
0
])
else
:
else
:
raise
Exception
(
'Malformed XML'
)
raise
Exception
(
'Malformed XML'
)
def
parse_timedelta
(
time_str
):
def
parse_timedelta
(
time_str
):
parts
=
TIMEDELTA_REGEX
.
match
(
time_str
)
parts
=
TIMEDELTA_REGEX
.
match
(
time_str
)
if
not
parts
:
if
not
parts
:
...
@@ -36,20 +38,23 @@ def parse_timedelta(time_str):
...
@@ -36,20 +38,23 @@ def parse_timedelta(time_str):
time_params
[
name
]
=
int
(
param
)
time_params
[
name
]
=
int
(
param
)
return
timedelta
(
**
time_params
)
return
timedelta
(
**
time_params
)
class
ComplexEncoder
(
json
.
JSONEncoder
):
class
ComplexEncoder
(
json
.
JSONEncoder
):
def
default
(
self
,
obj
):
def
default
(
self
,
obj
):
if
isinstance
(
obj
,
complex
):
if
isinstance
(
obj
,
complex
):
return
"{real:.7g}{imag:+.7g}*j"
.
format
(
real
=
obj
.
real
,
imag
=
obj
.
imag
)
return
"{real:.7g}{imag:+.7g}*j"
.
format
(
real
=
obj
.
real
,
imag
=
obj
.
imag
)
return
json
.
JSONEncoder
.
default
(
self
,
obj
)
return
json
.
JSONEncoder
.
default
(
self
,
obj
)
class
ModuleDescriptor
(
XModuleDescriptor
):
class
ModuleDescriptor
(
XModuleDescriptor
):
pass
pass
class
Module
(
XModule
):
class
Module
(
XModule
):
''' Interface between capa_problem and x_module. Originally a hack
''' Interface between capa_problem and x_module. Originally a hack
meant to be refactored out, but it seems to be serving a useful
meant to be refactored out, but it seems to be serving a useful
prupose now. We can e.g .destroy and create the capa_problem on a
prupose now. We can e.g .destroy and create the capa_problem on a
reset.
reset.
'''
'''
id_attribute
=
"filename"
id_attribute
=
"filename"
...
@@ -77,31 +82,30 @@ class Module(XModule):
...
@@ -77,31 +82,30 @@ class Module(XModule):
def
get_problem_html
(
self
,
encapsulate
=
True
):
def
get_problem_html
(
self
,
encapsulate
=
True
):
html
=
self
.
lcp
.
get_html
()
html
=
self
.
lcp
.
get_html
()
content
=
{
'name'
:
self
.
name
,
content
=
{
'name'
:
self
.
name
,
'html'
:
html
,
'html'
:
html
,
'weight'
:
self
.
weight
,
'weight'
:
self
.
weight
,
}
}
# We using strings as truthy values, because the terminology of the check button
# We using strings as truthy values, because the terminology of the check button
# is context-specific.
# is context-specific.
check_button
=
"Grade"
if
self
.
max_attempts
else
"Check"
check_button
=
"Grade"
if
self
.
max_attempts
else
"Check"
reset_button
=
True
reset_button
=
True
save_button
=
True
save_button
=
True
# If we're after deadline, or user has exhuasted attempts,
# If we're after deadline, or user has exhuasted attempts,
# question is read-only.
# question is read-only.
if
self
.
closed
():
if
self
.
closed
():
check_button
=
False
check_button
=
False
reset_button
=
False
reset_button
=
False
save_button
=
False
save_button
=
False
# User submitted a problem, and hasn't reset. We don't want
# User submitted a problem, and hasn't reset. We don't want
# more submissions.
# more submissions.
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
check_button
=
False
check_button
=
False
save_button
=
False
save_button
=
False
# Only show the reset button if pressing it will show different values
# Only show the reset button if pressing it will show different values
if
self
.
rerandomize
!=
'always'
:
if
self
.
rerandomize
!=
'always'
:
reset_button
=
False
reset_button
=
False
...
@@ -115,30 +119,30 @@ class Module(XModule):
...
@@ -115,30 +119,30 @@ class Module(XModule):
save_button
=
False
save_button
=
False
# Check if explanation is available, and if so, give a link
# Check if explanation is available, and if so, give a link
explain
=
""
explain
=
""
if
self
.
lcp
.
done
and
self
.
explain_available
==
'attempted'
:
if
self
.
lcp
.
done
and
self
.
explain_available
==
'attempted'
:
explain
=
self
.
explanation
explain
=
self
.
explanation
if
self
.
closed
()
and
self
.
explain_available
==
'closed'
:
if
self
.
closed
()
and
self
.
explain_available
==
'closed'
:
explain
=
self
.
explanation
explain
=
self
.
explanation
if
len
(
explain
)
==
0
:
if
len
(
explain
)
==
0
:
explain
=
False
explain
=
False
context
=
{
'problem'
:
content
,
context
=
{
'problem'
:
content
,
'id'
:
self
.
item_id
,
'id'
:
self
.
item_id
,
'check_button'
:
check_button
,
'check_button'
:
check_button
,
'reset_button'
:
reset_button
,
'reset_button'
:
reset_button
,
'save_button'
:
save_button
,
'save_button'
:
save_button
,
'answer_available'
:
self
.
answer_available
(),
'answer_available'
:
self
.
answer_available
(),
'ajax_url'
:
self
.
ajax_url
,
'ajax_url'
:
self
.
ajax_url
,
'attempts_used'
:
self
.
attempts
,
'attempts_used'
:
self
.
attempts
,
'attempts_allowed'
:
self
.
max_attempts
,
'attempts_allowed'
:
self
.
max_attempts
,
'explain'
:
explain
,
'explain'
:
explain
,
}
}
html
=
self
.
system
.
render_template
(
'problem.html'
,
context
)
html
=
self
.
system
.
render_template
(
'problem.html'
,
context
)
if
encapsulate
:
if
encapsulate
:
html
=
'<div id="problem_{id}" class="problem" data-url="{ajax_url}">'
.
format
(
id
=
self
.
item_id
,
ajax_url
=
self
.
ajax_url
)
+
html
+
"</div>"
html
=
'<div id="problem_{id}" class="problem" data-url="{ajax_url}">'
.
format
(
id
=
self
.
item_id
,
ajax_url
=
self
.
ajax_url
)
+
html
+
"</div>"
return
html
return
html
...
@@ -147,43 +151,42 @@ class Module(XModule):
...
@@ -147,43 +151,42 @@ class Module(XModule):
self
.
attempts
=
0
self
.
attempts
=
0
self
.
max_attempts
=
None
self
.
max_attempts
=
None
dom2
=
etree
.
fromstring
(
xml
)
dom2
=
etree
.
fromstring
(
xml
)
self
.
explanation
=
"problems/"
+
item
(
dom2
.
xpath
(
'/problem/@explain'
),
default
=
"closed"
)
self
.
explanation
=
"problems/"
+
item
(
dom2
.
xpath
(
'/problem/@explain'
),
default
=
"closed"
)
# TODO: Should be converted to: self.explanation=item(dom2.xpath('/problem/@explain'), default="closed")
# TODO: Should be converted to: self.explanation=item(dom2.xpath('/problem/@explain'), default="closed")
self
.
explain_available
=
item
(
dom2
.
xpath
(
'/problem/@explain_available'
))
self
.
explain_available
=
item
(
dom2
.
xpath
(
'/problem/@explain_available'
))
display_due_date_string
=
item
(
dom2
.
xpath
(
'/problem/@due'
))
display_due_date_string
=
item
(
dom2
.
xpath
(
'/problem/@due'
))
if
len
(
display_due_date_string
)
>
0
:
if
len
(
display_due_date_string
)
>
0
:
self
.
display_due_date
=
dateutil
.
parser
.
parse
(
display_due_date_string
)
self
.
display_due_date
=
dateutil
.
parser
.
parse
(
display_due_date_string
)
#log.debug("Parsed " + display_due_date_string + " to " + str(self.display_due_date))
#log.debug("Parsed " + display_due_date_string + " to " + str(self.display_due_date))
else
:
else
:
self
.
display_due_date
=
None
self
.
display_due_date
=
None
grace_period_string
=
item
(
dom2
.
xpath
(
'/problem/@graceperiod'
))
grace_period_string
=
item
(
dom2
.
xpath
(
'/problem/@graceperiod'
))
if
len
(
grace_period_string
)
>
0
and
self
.
display_due_date
:
if
len
(
grace_period_string
)
>
0
and
self
.
display_due_date
:
self
.
grace_period
=
parse_timedelta
(
grace_period_string
)
self
.
grace_period
=
parse_timedelta
(
grace_period_string
)
self
.
close_date
=
self
.
display_due_date
+
self
.
grace_period
self
.
close_date
=
self
.
display_due_date
+
self
.
grace_period
#log.debug("Then parsed " + grace_period_string + " to closing date" + str(self.close_date))
#log.debug("Then parsed " + grace_period_string + " to closing date" + str(self.close_date))
else
:
else
:
self
.
grace_period
=
None
self
.
grace_period
=
None
self
.
close_date
=
self
.
display_due_date
self
.
close_date
=
self
.
display_due_date
self
.
max_attempts
=
item
(
dom2
.
xpath
(
'/problem/@attempts'
))
self
.
max_attempts
=
item
(
dom2
.
xpath
(
'/problem/@attempts'
))
if
len
(
self
.
max_attempts
)
>
0
:
if
len
(
self
.
max_attempts
)
>
0
:
self
.
max_attempts
=
int
(
self
.
max_attempts
)
self
.
max_attempts
=
int
(
self
.
max_attempts
)
else
:
else
:
self
.
max_attempts
=
None
self
.
max_attempts
=
None
self
.
show_answer
=
item
(
dom2
.
xpath
(
'/problem/@showanswer'
))
self
.
show_answer
=
item
(
dom2
.
xpath
(
'/problem/@showanswer'
))
if
self
.
show_answer
==
""
:
if
self
.
show_answer
==
""
:
self
.
show_answer
=
"closed"
self
.
show_answer
=
"closed"
self
.
rerandomize
=
item
(
dom2
.
xpath
(
'/problem/@rerandomize'
))
self
.
rerandomize
=
item
(
dom2
.
xpath
(
'/problem/@rerandomize'
))
if
self
.
rerandomize
==
""
or
self
.
rerandomize
==
"always"
or
self
.
rerandomize
==
"true"
:
if
self
.
rerandomize
==
""
or
self
.
rerandomize
==
"always"
or
self
.
rerandomize
==
"true"
:
self
.
rerandomize
=
"always"
self
.
rerandomize
=
"always"
elif
self
.
rerandomize
==
"false"
or
self
.
rerandomize
==
"per_student"
:
elif
self
.
rerandomize
==
"false"
or
self
.
rerandomize
==
"per_student"
:
self
.
rerandomize
=
"per_student"
self
.
rerandomize
=
"per_student"
...
@@ -197,7 +200,7 @@ class Module(XModule):
...
@@ -197,7 +200,7 @@ class Module(XModule):
if
state
!=
None
and
'attempts'
in
state
:
if
state
!=
None
and
'attempts'
in
state
:
self
.
attempts
=
state
[
'attempts'
]
self
.
attempts
=
state
[
'attempts'
]
# TODO: Should be: self.filename=item(dom2.xpath('/problem/@filename'))
# TODO: Should be: self.filename=item(dom2.xpath('/problem/@filename'))
self
.
filename
=
"problems/"
+
item
(
dom2
.
xpath
(
'/problem/@filename'
))
+
".xml"
self
.
filename
=
"problems/"
+
item
(
dom2
.
xpath
(
'/problem/@filename'
))
+
".xml"
self
.
name
=
item
(
dom2
.
xpath
(
'/problem/@name'
))
self
.
name
=
item
(
dom2
.
xpath
(
'/problem/@name'
))
self
.
weight
=
item
(
dom2
.
xpath
(
'/problem/@weight'
))
self
.
weight
=
item
(
dom2
.
xpath
(
'/problem/@weight'
))
...
@@ -232,13 +235,13 @@ class Module(XModule):
...
@@ -232,13 +235,13 @@ class Module(XModule):
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
get
):
'''
'''
This is called by courseware.module_render, to handle an AJAX call. "get" is request.POST
This is called by courseware.module_render, to handle an AJAX call. "get" is request.POST
'''
'''
if
dispatch
==
'problem_get'
:
if
dispatch
==
'problem_get'
:
response
=
self
.
get_problem
(
get
)
response
=
self
.
get_problem
(
get
)
elif
False
:
#self.close_date >
elif
False
:
#self.close_date >
return
json
.
dumps
({
"error"
:
"Past due date"
})
return
json
.
dumps
({
"error"
:
"Past due date"
})
elif
dispatch
==
'problem_check'
:
elif
dispatch
==
'problem_check'
:
response
=
self
.
check_problem
(
get
)
response
=
self
.
check_problem
(
get
)
elif
dispatch
==
'problem_reset'
:
elif
dispatch
==
'problem_reset'
:
response
=
self
.
reset_problem
(
get
)
response
=
self
.
reset_problem
(
get
)
...
@@ -246,7 +249,7 @@ class Module(XModule):
...
@@ -246,7 +249,7 @@ class Module(XModule):
response
=
self
.
save_problem
(
get
)
response
=
self
.
save_problem
(
get
)
elif
dispatch
==
'problem_show'
:
elif
dispatch
==
'problem_show'
:
response
=
self
.
get_answer
(
get
)
response
=
self
.
get_answer
(
get
)
else
:
else
:
return
"Error"
return
"Error"
return
response
return
response
...
@@ -258,11 +261,11 @@ class Module(XModule):
...
@@ -258,11 +261,11 @@ class Module(XModule):
return
True
return
True
return
False
return
False
def
answer_available
(
self
):
def
answer_available
(
self
):
''' Is the user allowed to see an answer?
''' Is the user allowed to see an answer?
'''
'''
if
self
.
show_answer
==
''
:
if
self
.
show_answer
==
''
:
return
False
return
False
if
self
.
show_answer
==
"never"
:
if
self
.
show_answer
==
"never"
:
...
@@ -291,16 +294,16 @@ class Module(XModule):
...
@@ -291,16 +294,16 @@ class Module(XModule):
'''
'''
if
not
self
.
answer_available
():
if
not
self
.
answer_available
():
raise
self
.
system
.
exception404
raise
self
.
system
.
exception404
else
:
else
:
answers
=
self
.
lcp
.
get_question_answers
()
answers
=
self
.
lcp
.
get_question_answers
()
return
json
.
dumps
(
answers
,
return
json
.
dumps
(
answers
,
cls
=
ComplexEncoder
)
cls
=
ComplexEncoder
)
# Figure out if we should move these to capa_problem?
# Figure out if we should move these to capa_problem?
def
get_problem
(
self
,
get
):
def
get_problem
(
self
,
get
):
''' Same as get_problem_html -- if we want to reconfirm we
''' Same as get_problem_html -- if we want to reconfirm we
have the right thing e.g. after several AJAX calls.'''
have the right thing e.g. after several AJAX calls.'''
return
self
.
get_problem_html
(
encapsulate
=
False
)
return
self
.
get_problem_html
(
encapsulate
=
False
)
def
check_problem
(
self
,
get
):
def
check_problem
(
self
,
get
):
''' Checks whether answers to a problem are correct, and
''' Checks whether answers to a problem are correct, and
...
@@ -322,7 +325,7 @@ class Module(XModule):
...
@@ -322,7 +325,7 @@ class Module(XModule):
event_info
[
'failure'
]
=
'closed'
event_info
[
'failure'
]
=
'closed'
self
.
tracker
(
'save_problem_check_fail'
,
event_info
)
self
.
tracker
(
'save_problem_check_fail'
,
event_info
)
raise
self
.
system
.
exception404
raise
self
.
system
.
exception404
# Problem submitted. Student should reset before checking
# Problem submitted. Student should reset before checking
# again.
# again.
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
...
@@ -334,19 +337,19 @@ class Module(XModule):
...
@@ -334,19 +337,19 @@ class Module(XModule):
old_state
=
self
.
lcp
.
get_state
()
old_state
=
self
.
lcp
.
get_state
()
lcp_id
=
self
.
lcp
.
problem_id
lcp_id
=
self
.
lcp
.
problem_id
correct_map
=
self
.
lcp
.
grade_answers
(
answers
)
correct_map
=
self
.
lcp
.
grade_answers
(
answers
)
except
StudentInputError
as
inst
:
except
StudentInputError
as
inst
:
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
traceback
.
print_exc
()
traceback
.
print_exc
()
return
json
.
dumps
({
'success'
:
inst
.
message
})
return
json
.
dumps
({
'success'
:
inst
.
message
})
except
:
except
:
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
traceback
.
print_exc
()
traceback
.
print_exc
()
raise
Exception
,
"error in capa_module"
raise
Exception
,
"error in capa_module"
return
json
.
dumps
({
'success'
:
'Unknown Error'
})
return
json
.
dumps
({
'success'
:
'Unknown Error'
})
self
.
attempts
=
self
.
attempts
+
1
self
.
attempts
=
self
.
attempts
+
1
self
.
lcp
.
done
=
True
self
.
lcp
.
done
=
True
success
=
'correct'
success
=
'correct'
for
i
in
correct_map
:
for
i
in
correct_map
:
if
correct_map
[
i
]
!=
'correct'
:
if
correct_map
[
i
]
!=
'correct'
:
...
@@ -382,7 +385,7 @@ class Module(XModule):
...
@@ -382,7 +385,7 @@ class Module(XModule):
event_info
[
'failure'
]
=
'closed'
event_info
[
'failure'
]
=
'closed'
self
.
tracker
(
'save_problem_fail'
,
event_info
)
self
.
tracker
(
'save_problem_fail'
,
event_info
)
return
"Problem is closed"
return
"Problem is closed"
# Problem submitted. Student should reset before saving
# Problem submitted. Student should reset before saving
# again.
# again.
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
...
@@ -396,7 +399,7 @@ class Module(XModule):
...
@@ -396,7 +399,7 @@ class Module(XModule):
return
json
.
dumps
({
'success'
:
True
})
return
json
.
dumps
({
'success'
:
True
})
def
reset_problem
(
self
,
get
):
def
reset_problem
(
self
,
get
):
''' Changes problem state to unfinished -- removes student answers,
''' Changes problem state to unfinished -- removes student answers,
and causes problem to rerender itself. '''
and causes problem to rerender itself. '''
event_info
=
dict
()
event_info
=
dict
()
event_info
[
'old_state'
]
=
self
.
lcp
.
get_state
()
event_info
[
'old_state'
]
=
self
.
lcp
.
get_state
()
...
@@ -406,7 +409,7 @@ class Module(XModule):
...
@@ -406,7 +409,7 @@ class Module(XModule):
event_info
[
'failure'
]
=
'closed'
event_info
[
'failure'
]
=
'closed'
self
.
tracker
(
'reset_problem_fail'
,
event_info
)
self
.
tracker
(
'reset_problem_fail'
,
event_info
)
return
"Problem is closed"
return
"Problem is closed"
if
not
self
.
lcp
.
done
:
if
not
self
.
lcp
.
done
:
event_info
[
'failure'
]
=
'not_done'
event_info
[
'failure'
]
=
'not_done'
self
.
tracker
(
'reset_problem_fail'
,
event_info
)
self
.
tracker
(
'reset_problem_fail'
,
event_info
)
...
@@ -420,7 +423,7 @@ class Module(XModule):
...
@@ -420,7 +423,7 @@ class Module(XModule):
if
self
.
rerandomize
==
"always"
:
if
self
.
rerandomize
==
"always"
:
self
.
lcp
.
context
=
dict
()
self
.
lcp
.
context
=
dict
()
self
.
lcp
.
questions
=
dict
()
# Detailed info about questions in problem instance. TODO: Should be by id and not lid.
self
.
lcp
.
questions
=
dict
()
# Detailed info about questions in problem instance. TODO: Should be by id and not lid.
self
.
lcp
.
seed
=
None
self
.
lcp
.
seed
=
None
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
self
.
item_id
,
self
.
lcp
.
get_state
(),
system
=
self
.
system
)
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
self
.
item_id
,
self
.
lcp
.
get_state
(),
system
=
self
.
system
)
...
...
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