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
8ba41635
Commit
8ba41635
authored
Dec 07, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP. Data loads, but not all of it
parent
3d6cbf47
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
297 additions
and
382 deletions
+297
-382
cms/djangoapps/contentstore/views.py
+1
-1
common/lib/capa/capa/capa_problem.py
+7
-11
common/lib/xmodule/xmodule/abtest_module.py
+2
-31
common/lib/xmodule/xmodule/capa_module.py
+59
-95
common/lib/xmodule/xmodule/course_module.py
+45
-37
common/lib/xmodule/xmodule/error_module.py
+3
-4
common/lib/xmodule/xmodule/mako_module.py
+4
-5
common/lib/xmodule/xmodule/model.py
+79
-0
common/lib/xmodule/xmodule/modulestore/xml.py
+13
-12
common/lib/xmodule/xmodule/template_module.py
+0
-4
common/lib/xmodule/xmodule/x_module.py
+53
-169
common/lib/xmodule/xmodule/xml_module.py
+10
-7
jenkins/base.sh
+13
-0
lms/djangoapps/courseware/courses.py
+5
-3
lms/djangoapps/courseware/module_render.py
+2
-2
rakefile
+1
-1
No files found.
cms/djangoapps/contentstore/views.py
View file @
8ba41635
...
@@ -499,7 +499,7 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_
...
@@ -499,7 +499,7 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_
"""
"""
system
=
preview_module_system
(
request
,
preview_id
,
descriptor
)
system
=
preview_module_system
(
request
,
preview_id
,
descriptor
)
try
:
try
:
module
=
descriptor
.
xmodule
_constructor
(
system
)(
instance_state
,
shared_state
)
module
=
descriptor
.
xmodule
(
system
)
except
:
except
:
module
=
ErrorDescriptor
.
from_descriptor
(
module
=
ErrorDescriptor
.
from_descriptor
(
descriptor
,
descriptor
,
...
...
common/lib/capa/capa/capa_problem.py
View file @
8ba41635
...
@@ -83,7 +83,7 @@ class LoncapaProblem(object):
...
@@ -83,7 +83,7 @@ class LoncapaProblem(object):
Main class for capa Problems.
Main class for capa Problems.
'''
'''
def
__init__
(
self
,
problem_text
,
id
,
stat
e
=
None
,
seed
=
None
,
system
=
None
):
def
__init__
(
self
,
problem_text
,
id
,
correct_map
=
None
,
don
e
=
None
,
seed
=
None
,
system
=
None
):
'''
'''
Initializes capa Problem.
Initializes capa Problem.
...
@@ -91,7 +91,8 @@ class LoncapaProblem(object):
...
@@ -91,7 +91,8 @@ class LoncapaProblem(object):
- problem_text (string): xml defining the problem
- problem_text (string): xml defining the problem
- id (string): identifier for this problem; often a filename (no spaces)
- id (string): identifier for this problem; often a filename (no spaces)
- state (dict): student state
- correct_map (dict): data specifying whether the student has completed the problem
- done (bool): Whether the student has answered the problem
- seed (int): random number generator seed (int)
- seed (int): random number generator seed (int)
- system (ModuleSystem): ModuleSystem instance which provides OS,
- system (ModuleSystem): ModuleSystem instance which provides OS,
rendering, and user context
rendering, and user context
...
@@ -103,16 +104,11 @@ class LoncapaProblem(object):
...
@@ -103,16 +104,11 @@ class LoncapaProblem(object):
self
.
problem_id
=
id
self
.
problem_id
=
id
self
.
system
=
system
self
.
system
=
system
self
.
seed
=
seed
self
.
seed
=
seed
self
.
done
=
done
self
.
correct_map
=
CorrectMap
()
if
state
:
if
correct_map
is
not
None
:
if
'seed'
in
state
:
self
.
correct_map
.
set_dict
(
correct_map
)
self
.
seed
=
state
[
'seed'
]
if
'student_answers'
in
state
:
self
.
student_answers
=
state
[
'student_answers'
]
if
'correct_map'
in
state
:
self
.
correct_map
.
set_dict
(
state
[
'correct_map'
])
if
'done'
in
state
:
self
.
done
=
state
[
'done'
]
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
if
not
self
.
seed
:
if
not
self
.
seed
:
...
...
common/lib/xmodule/xmodule/abtest_module.py
View file @
8ba41635
...
@@ -7,6 +7,7 @@ from xmodule.x_module import XModule
...
@@ -7,6 +7,7 @@ from xmodule.x_module import XModule
from
xmodule.raw_module
import
RawDescriptor
from
xmodule.raw_module
import
RawDescriptor
from
xmodule.xml_module
import
XmlDescriptor
from
xmodule.xml_module
import
XmlDescriptor
from
xmodule.exceptions
import
InvalidDefinitionError
from
xmodule.exceptions
import
InvalidDefinitionError
from
.model
import
String
,
Scope
DEFAULT
=
"_DEFAULT_GROUP"
DEFAULT
=
"_DEFAULT_GROUP"
...
@@ -68,37 +69,7 @@ class ABTestDescriptor(RawDescriptor, XmlDescriptor):
...
@@ -68,37 +69,7 @@ class ABTestDescriptor(RawDescriptor, XmlDescriptor):
template_dir_name
=
"abtest"
template_dir_name
=
"abtest"
def
__init__
(
self
,
system
,
definition
=
None
,
**
kwargs
):
experiment
=
String
(
help
=
"Experiment that this A/B test belongs to"
,
scope
=
Scope
.
content
)
"""
definition is a dictionary with the following layout:
{'data': {
'experiment': 'the name of the experiment',
'group_portions': {
'group_a': 0.1,
'group_b': 0.2
},
'group_contents': {
'group_a': [
'url://for/content/module/1',
'url://for/content/module/2',
],
'group_b': [
'url://for/content/module/3',
],
DEFAULT: [
'url://for/default/content/1'
]
}
},
'children': [
'url://for/content/module/1',
'url://for/content/module/2',
'url://for/content/module/3',
'url://for/default/content/1',
]}
"""
kwargs
[
'shared_state_key'
]
=
definition
[
'data'
][
'experiment'
]
RawDescriptor
.
__init__
(
self
,
system
,
definition
,
**
kwargs
)
@classmethod
@classmethod
def
definition_from_xml
(
cls
,
xml_object
,
system
):
def
definition_from_xml
(
cls
,
xml_object
,
system
):
...
...
common/lib/xmodule/xmodule/capa_module.py
View file @
8ba41635
...
@@ -19,6 +19,9 @@ from progress import Progress
...
@@ -19,6 +19,9 @@ from progress import Progress
from
xmodule.x_module
import
XModule
from
xmodule.x_module
import
XModule
from
xmodule.raw_module
import
RawDescriptor
from
xmodule.raw_module
import
RawDescriptor
from
xmodule.exceptions
import
NotFoundError
from
xmodule.exceptions
import
NotFoundError
from
.model
import
Int
,
Scope
,
ModuleScope
,
ModelType
,
String
,
Boolean
,
Object
,
Float
Date
=
Timedelta
=
ModelType
log
=
logging
.
getLogger
(
"mitx.courseware"
)
log
=
logging
.
getLogger
(
"mitx.courseware"
)
...
@@ -77,6 +80,17 @@ class CapaModule(XModule):
...
@@ -77,6 +80,17 @@ class CapaModule(XModule):
'''
'''
icon_class
=
'problem'
icon_class
=
'problem'
attempts
=
Int
(
help
=
"Number of attempts taken by the student on this problem"
,
default
=
0
,
scope
=
Scope
.
student_state
)
max_attempts
=
Int
(
help
=
"Maximum number of attempts that a student is allowed"
,
scope
=
Scope
.
settings
)
due
=
Date
(
help
=
"Date that this problem is due by"
,
scope
=
Scope
.
settings
)
graceperiod
=
Timedelta
(
help
=
"Amount of time after the due date that submissions will be accepted"
,
scope
=
Scope
.
settings
)
show_answer
=
String
(
help
=
"When to show the problem answer to the student"
,
scope
=
Scope
.
settings
,
default
=
"closed"
)
force_save_button
=
Boolean
(
help
=
"Whether to force the save button to appear on the page"
,
scope
=
Scope
.
settings
)
rerandomize
=
String
(
help
=
"When to rerandomize the problem"
,
default
=
"always"
)
data
=
String
(
help
=
"XML data for the problem"
,
scope
=
Scope
.
content
)
correct_map
=
Object
(
help
=
"Dictionary with the correctness of current student answers"
,
scope
=
Scope
.
student_state
)
done
=
Boolean
(
help
=
"Whether the student has answered the problem"
,
scope
=
Scope
.
student_state
)
js
=
{
'coffee'
:
[
resource_string
(
__name__
,
'js/src/capa/display.coffee'
),
js
=
{
'coffee'
:
[
resource_string
(
__name__
,
'js/src/capa/display.coffee'
),
resource_string
(
__name__
,
'js/src/collapsible.coffee'
),
resource_string
(
__name__
,
'js/src/collapsible.coffee'
),
resource_string
(
__name__
,
'js/src/javascript_loader.coffee'
),
resource_string
(
__name__
,
'js/src/javascript_loader.coffee'
),
...
@@ -87,51 +101,15 @@ class CapaModule(XModule):
...
@@ -87,51 +101,15 @@ class CapaModule(XModule):
js_module_name
=
"Problem"
js_module_name
=
"Problem"
css
=
{
'scss'
:
[
resource_string
(
__name__
,
'css/capa/display.scss'
)]}
css
=
{
'scss'
:
[
resource_string
(
__name__
,
'css/capa/display.scss'
)]}
def
__init__
(
self
,
system
,
location
,
definition
,
descriptor
,
instance_state
=
None
,
def
__init__
(
self
,
system
,
location
,
descriptor
,
model_data
):
shared_state
=
None
,
**
kwargs
):
XModule
.
__init__
(
self
,
system
,
location
,
descriptor
,
model_data
)
XModule
.
__init__
(
self
,
system
,
location
,
definition
,
descriptor
,
instance_state
,
shared_state
,
**
kwargs
)
self
.
attempts
=
0
self
.
max_attempts
=
None
dom2
=
etree
.
fromstring
(
definition
[
'data'
])
display_due_date_string
=
self
.
metadata
.
get
(
'due'
,
None
)
if
display_due_date_string
is
not
None
:
self
.
display_due_date
=
dateutil
.
parser
.
parse
(
display_due_date_string
)
#log.debug("Parsed " + display_due_date_string +
# " to " + str(self.display_due_date))
else
:
self
.
display_due_date
=
None
grace_period_string
=
self
.
metadata
.
get
(
'graceperiod'
,
None
)
if
self
.
graceperiod
is
not
None
and
self
.
due
:
if
grace_period_string
is
not
None
and
self
.
display_due_date
:
self
.
close_date
=
self
.
due
+
self
.
graceperiod
self
.
grace_period
=
parse_timedelta
(
grace_period_string
)
self
.
close_date
=
self
.
display_due_date
+
self
.
grace_period
#log.debug("Then parsed " + grace_period_string +
#log.debug("Then parsed " + grace_period_string +
# " to closing date" + str(self.close_date))
# " to closing date" + str(self.close_date))
else
:
else
:
self
.
grace_period
=
None
self
.
close_date
=
self
.
due
self
.
close_date
=
self
.
display_due_date
self
.
max_attempts
=
self
.
metadata
.
get
(
'attempts'
,
None
)
if
self
.
max_attempts
is
not
None
:
self
.
max_attempts
=
int
(
self
.
max_attempts
)
self
.
show_answer
=
self
.
metadata
.
get
(
'showanswer'
,
'closed'
)
self
.
force_save_button
=
self
.
metadata
.
get
(
'force_save_button'
,
'false'
)
if
self
.
show_answer
==
""
:
self
.
show_answer
=
"closed"
if
instance_state
is
not
None
:
instance_state
=
json
.
loads
(
instance_state
)
if
instance_state
is
not
None
and
'attempts'
in
instance_state
:
self
.
attempts
=
instance_state
[
'attempts'
]
self
.
name
=
only_one
(
dom2
.
xpath
(
'/problem/@name'
))
if
self
.
rerandomize
==
'never'
:
if
self
.
rerandomize
==
'never'
:
self
.
seed
=
1
self
.
seed
=
1
...
@@ -148,8 +126,8 @@ class CapaModule(XModule):
...
@@ -148,8 +126,8 @@ class CapaModule(XModule):
try
:
try
:
# TODO (vshnayder): move as much as possible of this work and error
# TODO (vshnayder): move as much as possible of this work and error
# checking to descriptor load time
# checking to descriptor load time
self
.
lcp
=
LoncapaProblem
(
self
.
d
efinition
[
'data'
]
,
self
.
location
.
html_id
(),
self
.
lcp
=
LoncapaProblem
(
self
.
d
ata
,
self
.
location
.
html_id
(),
instance_state
,
seed
=
self
.
seed
,
system
=
self
.
system
)
self
.
correct_map
,
self
.
done
,
self
.
seed
,
self
.
system
)
except
Exception
as
err
:
except
Exception
as
err
:
msg
=
'cannot create LoncapaProblem {loc}: {err}'
.
format
(
msg
=
'cannot create LoncapaProblem {loc}: {err}'
.
format
(
loc
=
self
.
location
.
url
(),
err
=
err
)
loc
=
self
.
location
.
url
(),
err
=
err
)
...
@@ -168,33 +146,21 @@ class CapaModule(XModule):
...
@@ -168,33 +146,21 @@ class CapaModule(XModule):
(
self
.
location
.
url
(),
msg
))
(
self
.
location
.
url
(),
msg
))
self
.
lcp
=
LoncapaProblem
(
self
.
lcp
=
LoncapaProblem
(
problem_text
,
self
.
location
.
html_id
(),
problem_text
,
self
.
location
.
html_id
(),
instance_state
,
seed
=
self
.
seed
,
system
=
self
.
system
)
self
.
correct_map
,
self
.
done
,
self
.
seed
,
self
.
system
)
else
:
else
:
# add extra info and raise
# add extra info and raise
raise
Exception
(
msg
),
None
,
sys
.
exc_info
()[
2
]
raise
Exception
(
msg
),
None
,
sys
.
exc_info
()[
2
]
@property
if
self
.
rerandomize
in
(
""
,
"true"
):
def
rerandomize
(
self
):
self
.
rerandomize
=
"always"
"""
elif
self
.
rerandomize
==
"false"
:
Property accessor that returns self.metadata['rerandomize'] in a
self
.
rerandomize
=
"per_student"
canonical form
"""
rerandomize
=
self
.
metadata
.
get
(
'rerandomize'
,
'always'
)
if
rerandomize
in
(
""
,
"always"
,
"true"
):
return
"always"
elif
rerandomize
in
(
"false"
,
"per_student"
):
return
"per_student"
elif
rerandomize
==
"never"
:
return
"never"
elif
rerandomize
==
"onreset"
:
return
"onreset"
else
:
raise
Exception
(
"Invalid rerandomize attribute "
+
rerandomize
)
def
get_instance_state
(
self
):
def
sync_lcp_state
(
self
):
state
=
self
.
lcp
.
get_state
()
lcp_state
=
self
.
lcp
.
get_state
()
state
[
'attempts'
]
=
self
.
attempts
self
.
done
=
lcp_state
[
'done'
]
return
json
.
dumps
(
state
)
self
.
correct_map
=
lcp_state
[
'correct_map'
]
self
.
seed
=
lcp_state
[
'seed'
]
def
get_score
(
self
):
def
get_score
(
self
):
return
self
.
lcp
.
get_score
()
return
self
.
lcp
.
get_score
()
...
@@ -211,7 +177,7 @@ class CapaModule(XModule):
...
@@ -211,7 +177,7 @@ class CapaModule(XModule):
if
total
>
0
:
if
total
>
0
:
try
:
try
:
return
Progress
(
score
,
total
)
return
Progress
(
score
,
total
)
except
Exception
as
err
:
except
Exception
:
log
.
exception
(
"Got bad progress"
)
log
.
exception
(
"Got bad progress"
)
return
None
return
None
return
None
return
None
...
@@ -261,8 +227,8 @@ class CapaModule(XModule):
...
@@ -261,8 +227,8 @@ class CapaModule(XModule):
# Next, generate a fresh LoncapaProblem
# Next, generate a fresh LoncapaProblem
self
.
lcp
=
LoncapaProblem
(
self
.
definition
[
'data'
],
self
.
location
.
html_id
(),
self
.
lcp
=
LoncapaProblem
(
self
.
definition
[
'data'
],
self
.
location
.
html_id
(),
state
=
None
,
# Tabula rasa
seed
=
self
.
seed
,
system
=
self
.
system
)
seed
=
self
.
seed
,
system
=
self
.
system
)
self
.
sync_lcp_state
()
# Prepend a scary warning to the student
# Prepend a scary warning to the student
warning
=
'<div class="capa_reset">'
\
warning
=
'<div class="capa_reset">'
\
...
@@ -280,8 +246,8 @@ class CapaModule(XModule):
...
@@ -280,8 +246,8 @@ class CapaModule(XModule):
html
=
warning
html
=
warning
try
:
try
:
html
+=
self
.
lcp
.
get_html
()
html
+=
self
.
lcp
.
get_html
()
except
Exception
,
err
:
# Couldn't do it. Give up
except
Exception
:
# Couldn't do it. Give up
log
.
exception
(
err
)
log
.
exception
(
"Unable to generate html from LoncapaProblem"
)
raise
raise
content
=
{
'name'
:
self
.
display_name
,
content
=
{
'name'
:
self
.
display_name
,
...
@@ -311,7 +277,7 @@ class CapaModule(XModule):
...
@@ -311,7 +277,7 @@ class CapaModule(XModule):
# 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
.
done
and
self
.
rerandomize
==
"always"
:
check_button
=
False
check_button
=
False
save_button
=
False
save_button
=
False
...
@@ -320,7 +286,7 @@ class CapaModule(XModule):
...
@@ -320,7 +286,7 @@ class CapaModule(XModule):
reset_button
=
False
reset_button
=
False
# User hasn't submitted an answer yet -- we don't want resets
# User hasn't submitted an answer yet -- we don't want resets
if
not
self
.
lcp
.
done
:
if
not
self
.
done
:
reset_button
=
False
reset_button
=
False
# We may not need a "save" button if infinite number of attempts and
# We may not need a "save" button if infinite number of attempts and
...
@@ -406,7 +372,7 @@ class CapaModule(XModule):
...
@@ -406,7 +372,7 @@ class CapaModule(XModule):
return
self
.
attempts
>
0
return
self
.
attempts
>
0
if
self
.
show_answer
==
'answered'
:
if
self
.
show_answer
==
'answered'
:
return
self
.
lcp
.
done
return
self
.
done
if
self
.
show_answer
==
'closed'
:
if
self
.
show_answer
==
'closed'
:
return
self
.
closed
()
return
self
.
closed
()
...
@@ -429,6 +395,7 @@ class CapaModule(XModule):
...
@@ -429,6 +395,7 @@ class CapaModule(XModule):
queuekey
=
get
[
'queuekey'
]
queuekey
=
get
[
'queuekey'
]
score_msg
=
get
[
'xqueue_body'
]
score_msg
=
get
[
'xqueue_body'
]
self
.
lcp
.
update_score
(
score_msg
,
queuekey
)
self
.
lcp
.
update_score
(
score_msg
,
queuekey
)
self
.
sync_lcp_state
()
return
dict
()
# No AJAX return is needed
return
dict
()
# No AJAX return is needed
...
@@ -445,8 +412,9 @@ class CapaModule(XModule):
...
@@ -445,8 +412,9 @@ class CapaModule(XModule):
raise
NotFoundError
(
'Answer is not available'
)
raise
NotFoundError
(
'Answer is not available'
)
else
:
else
:
answers
=
self
.
lcp
.
get_question_answers
()
answers
=
self
.
lcp
.
get_question_answers
()
self
.
sync_lcp_state
()
# answers (eg <solution>) may have embedded images
# answers (eg <solution>) may have embedded images
# but be careful, some problems are using non-string answer dicts
# but be careful, some problems are using non-string answer dicts
new_answers
=
dict
()
new_answers
=
dict
()
for
answer_id
in
answers
:
for
answer_id
in
answers
:
...
@@ -512,7 +480,7 @@ class CapaModule(XModule):
...
@@ -512,7 +480,7 @@ class CapaModule(XModule):
raise
NotFoundError
(
'Problem is closed'
)
raise
NotFoundError
(
'Problem is closed'
)
# Problem submitted. Student should reset before checking again
# Problem submitted. Student should reset before checking again
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
if
self
.
done
and
self
.
rerandomize
==
"always"
:
event_info
[
'failure'
]
=
'unreset'
event_info
[
'failure'
]
=
'unreset'
self
.
system
.
track_function
(
'save_problem_check_fail'
,
event_info
)
self
.
system
.
track_function
(
'save_problem_check_fail'
,
event_info
)
raise
NotFoundError
(
'Problem must be reset before it can be checked again'
)
raise
NotFoundError
(
'Problem must be reset before it can be checked again'
)
...
@@ -522,14 +490,13 @@ class CapaModule(XModule):
...
@@ -522,14 +490,13 @@ class CapaModule(XModule):
current_time
=
datetime
.
datetime
.
now
()
current_time
=
datetime
.
datetime
.
now
()
prev_submit_time
=
self
.
lcp
.
get_recentmost_queuetime
()
prev_submit_time
=
self
.
lcp
.
get_recentmost_queuetime
()
waittime_between_requests
=
self
.
system
.
xqueue
[
'waittime'
]
waittime_between_requests
=
self
.
system
.
xqueue
[
'waittime'
]
if
(
current_time
-
prev_submit_time
)
.
total_seconds
()
<
waittime_between_requests
:
if
(
current_time
-
prev_submit_time
)
.
total_seconds
()
<
waittime_between_requests
:
msg
=
'You must wait at least
%
d seconds between submissions'
%
waittime_between_requests
msg
=
'You must wait at least
%
d seconds between submissions'
%
waittime_between_requests
return
{
'success'
:
msg
,
'html'
:
''
}
# Prompts a modal dialog in ajax callback
return
{
'success'
:
msg
,
'html'
:
''
}
# Prompts a modal dialog in ajax callback
try
:
try
:
old_state
=
self
.
lcp
.
get_state
()
lcp_id
=
self
.
lcp
.
problem_id
correct_map
=
self
.
lcp
.
grade_answers
(
answers
)
correct_map
=
self
.
lcp
.
grade_answers
(
answers
)
self
.
sync_lcp_state
()
except
StudentInputError
as
inst
:
except
StudentInputError
as
inst
:
log
.
exception
(
"StudentInputError in capa_module:problem_check"
)
log
.
exception
(
"StudentInputError in capa_module:problem_check"
)
return
{
'success'
:
inst
.
message
}
return
{
'success'
:
inst
.
message
}
...
@@ -554,11 +521,11 @@ class CapaModule(XModule):
...
@@ -554,11 +521,11 @@ class CapaModule(XModule):
# 'success' will always be incorrect
# 'success' will always be incorrect
event_info
[
'correct_map'
]
=
correct_map
.
get_dict
()
event_info
[
'correct_map'
]
=
correct_map
.
get_dict
()
event_info
[
'success'
]
=
success
event_info
[
'success'
]
=
success
event_info
[
'attempts'
]
=
self
.
attempts
event_info
[
'attempts'
]
=
self
.
attempts
self
.
system
.
track_function
(
'save_problem_check'
,
event_info
)
self
.
system
.
track_function
(
'save_problem_check'
,
event_info
)
if
hasattr
(
self
.
system
,
'psychometrics_handler'
):
# update PsychometricsData using callback
if
hasattr
(
self
.
system
,
'psychometrics_handler'
):
# update PsychometricsData using callback
self
.
system
.
psychometrics_handler
(
self
.
get_instance_state
())
self
.
system
.
psychometrics_handler
(
self
.
get_instance_state
())
# render problem into HTML
# render problem into HTML
html
=
self
.
get_problem_html
(
encapsulate
=
False
)
html
=
self
.
get_problem_html
(
encapsulate
=
False
)
...
@@ -589,7 +556,7 @@ class CapaModule(XModule):
...
@@ -589,7 +556,7 @@ class CapaModule(XModule):
# 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
.
done
and
self
.
rerandomize
==
"always"
:
event_info
[
'failure'
]
=
'done'
event_info
[
'failure'
]
=
'done'
self
.
system
.
track_function
(
'save_problem_fail'
,
event_info
)
self
.
system
.
track_function
(
'save_problem_fail'
,
event_info
)
return
{
'success'
:
False
,
return
{
'success'
:
False
,
...
@@ -617,7 +584,7 @@ class CapaModule(XModule):
...
@@ -617,7 +584,7 @@ class CapaModule(XModule):
return
{
'success'
:
False
,
return
{
'success'
:
False
,
'error'
:
"Problem is closed"
}
'error'
:
"Problem is closed"
}
if
not
self
.
lcp
.
done
:
if
not
self
.
done
:
event_info
[
'failure'
]
=
'not_done'
event_info
[
'failure'
]
=
'not_done'
self
.
system
.
track_function
(
'reset_problem_fail'
,
event_info
)
self
.
system
.
track_function
(
'reset_problem_fail'
,
event_info
)
return
{
'success'
:
False
,
return
{
'success'
:
False
,
...
@@ -629,9 +596,13 @@ class CapaModule(XModule):
...
@@ -629,9 +596,13 @@ class CapaModule(XModule):
# in next line)
# in next line)
self
.
lcp
.
seed
=
None
self
.
lcp
.
seed
=
None
self
.
lcp
=
LoncapaProblem
(
self
.
definition
[
'data'
],
self
.
lcp
=
LoncapaProblem
(
self
.
data
,
self
.
location
.
html_id
(),
self
.
lcp
.
get_state
(),
self
.
location
.
html_id
(),
system
=
self
.
system
)
self
.
lcp
.
correct_map
,
self
.
lcp
.
done
,
self
.
lcp
.
seed
,
self
.
system
)
self
.
sync_lcp_state
()
event_info
[
'new_state'
]
=
self
.
lcp
.
get_state
()
event_info
[
'new_state'
]
=
self
.
lcp
.
get_state
()
self
.
system
.
track_function
(
'reset_problem'
,
event_info
)
self
.
system
.
track_function
(
'reset_problem'
,
event_info
)
...
@@ -647,6 +618,8 @@ class CapaDescriptor(RawDescriptor):
...
@@ -647,6 +618,8 @@ class CapaDescriptor(RawDescriptor):
module_class
=
CapaModule
module_class
=
CapaModule
weight
=
Float
(
help
=
"How much to weight this problem by"
,
scope
=
Scope
.
settings
)
stores_state
=
True
stores_state
=
True
has_score
=
True
has_score
=
True
template_dir_name
=
'problem'
template_dir_name
=
'problem'
...
@@ -665,12 +638,3 @@ class CapaDescriptor(RawDescriptor):
...
@@ -665,12 +638,3 @@ class CapaDescriptor(RawDescriptor):
'problems/'
+
path
[
8
:],
'problems/'
+
path
[
8
:],
path
[
8
:],
path
[
8
:],
]
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
CapaDescriptor
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
weight_string
=
self
.
metadata
.
get
(
'weight'
,
None
)
if
weight_string
:
self
.
weight
=
float
(
weight_string
)
else
:
self
.
weight
=
None
common/lib/xmodule/xmodule/course_module.py
View file @
8ba41635
...
@@ -12,6 +12,9 @@ import requests
...
@@ -12,6 +12,9 @@ import requests
import
time
import
time
import
copy
import
copy
from
.model
import
Scope
,
ModelType
,
List
,
String
,
Object
,
Boolean
Date
=
ModelType
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -21,6 +24,39 @@ edx_xml_parser = etree.XMLParser(dtd_validation=False, load_dtd=False,
...
@@ -21,6 +24,39 @@ edx_xml_parser = etree.XMLParser(dtd_validation=False, load_dtd=False,
class
CourseDescriptor
(
SequenceDescriptor
):
class
CourseDescriptor
(
SequenceDescriptor
):
module_class
=
SequenceModule
module_class
=
SequenceModule
textbooks
=
List
(
help
=
"List of pairs of (title, url) for textbooks used in this course"
,
default
=
[],
scope
=
Scope
.
content
)
wiki_slug
=
String
(
help
=
"Slug that points to the wiki for this course"
,
scope
=
Scope
.
content
)
enrollment_start
=
Date
(
help
=
"Date that enrollment for this class is opened"
,
scope
=
Scope
.
settings
)
enrollment_end
=
Date
(
help
=
"Date that enrollment for this class is closed"
,
scope
=
Scope
.
settings
)
end
=
Date
(
help
=
"Date that this class ends"
,
scope
=
Scope
.
settings
)
advertised_start
=
Date
(
help
=
"Date that this course is advertised to start"
,
scope
=
Scope
.
settings
)
grading_policy
=
Object
(
help
=
"Grading policy definition for this class"
,
scope
=
Scope
.
content
)
info_sidebar_name
=
String
(
scope
=
Scope
.
settings
,
default
=
'Course Handouts'
)
# An extra property is used rather than the wiki_slug/number because
# there are courses that change the number for different runs. This allows
# courses to share the same css_class across runs even if they have
# different numbers.
#
# TODO get rid of this as soon as possible or potentially build in a robust
# way to add in course-specific styling. There needs to be a discussion
# about the right way to do this, but arjun will address this ASAP. Also
# note that the courseware template needs to change when this is removed.
css_class
=
String
(
help
=
"DO NOT USE THIS"
,
scope
=
Scope
.
settings
)
# TODO: This is a quick kludge to allow CS50 (and other courses) to
# specify their own discussion forums as external links by specifying a
# "discussion_link" in their policy JSON file. This should later get
# folded in with Syllabus, Course Info, and additional Custom tabs in a
# more sensible framework later.
discussion_link
=
String
(
help
=
"DO NOT USE THIS"
,
scope
=
Scope
.
settings
)
# TODO: same as above, intended to let internal CS50 hide the progress tab
# until we get grade integration set up.
# Explicit comparison to True because we always want to return a bool.
hide_progress_tab
=
Boolean
(
help
=
"DO NOT USE THIS"
,
scope
=
Scope
.
settings
)
template_dir_name
=
'course'
template_dir_name
=
'course'
class
Textbook
:
class
Textbook
:
...
@@ -69,10 +105,11 @@ class CourseDescriptor(SequenceDescriptor):
...
@@ -69,10 +105,11 @@ class CourseDescriptor(SequenceDescriptor):
return
table_of_contents
return
table_of_contents
def
__init__
(
self
,
system
,
definition
=
None
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
CourseDescriptor
,
self
)
.
__init__
(
system
,
definition
,
**
kwargs
)
super
(
CourseDescriptor
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
textbooks
=
[]
self
.
textbooks
=
[]
for
title
,
book_url
in
self
.
definition
[
'data'
][
'textbooks'
]
:
for
title
,
book_url
in
self
.
textbooks
:
try
:
try
:
self
.
textbooks
.
append
(
self
.
Textbook
(
title
,
book_url
))
self
.
textbooks
.
append
(
self
.
Textbook
(
title
,
book_url
))
except
:
except
:
...
@@ -81,7 +118,8 @@ class CourseDescriptor(SequenceDescriptor):
...
@@ -81,7 +118,8 @@ class CourseDescriptor(SequenceDescriptor):
log
.
exception
(
"Couldn't load textbook ({0}, {1})"
.
format
(
title
,
book_url
))
log
.
exception
(
"Couldn't load textbook ({0}, {1})"
.
format
(
title
,
book_url
))
continue
continue
self
.
wiki_slug
=
self
.
definition
[
'data'
][
'wiki_slug'
]
or
self
.
location
.
course
if
self
.
wiki_slug
is
None
:
self
.
wiki_slug
=
self
.
location
.
course
msg
=
None
msg
=
None
if
self
.
start
is
None
:
if
self
.
start
is
None
:
...
@@ -98,7 +136,7 @@ class CourseDescriptor(SequenceDescriptor):
...
@@ -98,7 +136,7 @@ class CourseDescriptor(SequenceDescriptor):
# disable the syllabus content for courses that do not provide a syllabus
# disable the syllabus content for courses that do not provide a syllabus
self
.
syllabus_present
=
self
.
system
.
resources_fs
.
exists
(
path
(
'syllabus'
))
self
.
syllabus_present
=
self
.
system
.
resources_fs
.
exists
(
path
(
'syllabus'
))
self
.
set_grading_policy
(
self
.
definition
[
'data'
]
.
get
(
'grading_policy'
,
None
)
)
self
.
set_grading_policy
(
self
.
grading_policy
)
def
defaut_grading_policy
(
self
):
def
defaut_grading_policy
(
self
):
"""
"""
...
@@ -203,7 +241,7 @@ class CourseDescriptor(SequenceDescriptor):
...
@@ -203,7 +241,7 @@ class CourseDescriptor(SequenceDescriptor):
# cdodge: import the grading policy information that is on disk and put into the
# cdodge: import the grading policy information that is on disk and put into the
# descriptor 'definition' bucket as a dictionary so that it is persisted in the DB
# descriptor 'definition' bucket as a dictionary so that it is persisted in the DB
instance
.
definition
[
'data'
][
'grading_policy'
]
=
policy
instance
.
grading_policy
=
policy
# now set the current instance. set_grading_policy() will apply some inheritance rules
# now set the current instance. set_grading_policy() will apply some inheritance rules
instance
.
set_grading_policy
(
policy
)
instance
.
set_grading_policy
(
policy
)
...
@@ -395,38 +433,14 @@ class CourseDescriptor(SequenceDescriptor):
...
@@ -395,38 +433,14 @@ class CourseDescriptor(SequenceDescriptor):
@property
@property
def
start_date_text
(
self
):
def
start_date_text
(
self
):
displayed_start
=
self
.
_try_parse_time
(
'advertised_start'
)
or
self
.
start
return
time
.
strftime
(
"
%
b
%
d,
%
Y"
,
self
.
advertised_start
or
self
.
start
)
return
time
.
strftime
(
"
%
b
%
d,
%
Y"
,
displayed_start
)
@property
@property
def
end_date_text
(
self
):
def
end_date_text
(
self
):
return
time
.
strftime
(
"
%
b
%
d,
%
Y"
,
self
.
end
)
return
time
.
strftime
(
"
%
b
%
d,
%
Y"
,
self
.
end
)
# An extra property is used rather than the wiki_slug/number because
# there are courses that change the number for different runs. This allows
# courses to share the same css_class across runs even if they have
# different numbers.
#
# TODO get rid of this as soon as possible or potentially build in a robust
# way to add in course-specific styling. There needs to be a discussion
# about the right way to do this, but arjun will address this ASAP. Also
# note that the courseware template needs to change when this is removed.
@property
def
css_class
(
self
):
return
self
.
metadata
.
get
(
'css_class'
,
''
)
@property
def
info_sidebar_name
(
self
):
return
self
.
metadata
.
get
(
'info_sidebar_name'
,
'Course Handouts'
)
@property
def
discussion_link
(
self
):
"""TODO: This is a quick kludge to allow CS50 (and other courses) to
specify their own discussion forums as external links by specifying a
"discussion_link" in their policy JSON file. This should later get
folded in with Syllabus, Course Info, and additional Custom tabs in a
more sensible framework later."""
return
self
.
metadata
.
get
(
'discussion_link'
,
None
)
@property
@property
def
forum_posts_allowed
(
self
):
def
forum_posts_allowed
(
self
):
...
@@ -443,12 +457,6 @@ class CourseDescriptor(SequenceDescriptor):
...
@@ -443,12 +457,6 @@ class CourseDescriptor(SequenceDescriptor):
return
True
return
True
@property
def
hide_progress_tab
(
self
):
"""TODO: same as above, intended to let internal CS50 hide the progress tab
until we get grade integration set up."""
# Explicit comparison to True because we always want to return a bool.
return
self
.
metadata
.
get
(
'hide_progress_tab'
)
==
True
@property
@property
def
end_of_course_survey_url
(
self
):
def
end_of_course_survey_url
(
self
):
...
...
common/lib/xmodule/xmodule/error_module.py
View file @
8ba41635
...
@@ -74,12 +74,11 @@ class ErrorDescriptor(JSONEditingDescriptor):
...
@@ -74,12 +74,11 @@ class ErrorDescriptor(JSONEditingDescriptor):
}
}
# real metadata stays in the content, but add a display name
# real metadata stays in the content, but add a display name
m
eta
data
=
{
'display_name'
:
'Error: '
+
location
.
name
}
m
odel_
data
=
{
'display_name'
:
'Error: '
+
location
.
name
}
return
ErrorDescriptor
(
return
ErrorDescriptor
(
system
,
system
,
definition
,
location
,
location
=
location
,
model_data
,
metadata
=
metadata
)
)
def
get_context
(
self
):
def
get_context
(
self
):
...
...
common/lib/xmodule/xmodule/mako_module.py
View file @
8ba41635
...
@@ -21,20 +21,19 @@ class MakoModuleDescriptor(XModuleDescriptor):
...
@@ -21,20 +21,19 @@ class MakoModuleDescriptor(XModuleDescriptor):
the descriptor as the `module` parameter to that template
the descriptor as the `module` parameter to that template
"""
"""
def
__init__
(
self
,
system
,
definition
=
None
,
**
kwargs
):
def
__init__
(
self
,
system
,
location
,
model_data
):
if
getattr
(
system
,
'render_template'
,
None
)
is
None
:
if
getattr
(
system
,
'render_template'
,
None
)
is
None
:
raise
TypeError
(
'{system} must have a render_template function'
raise
TypeError
(
'{system} must have a render_template function'
' in order to use a MakoDescriptor'
.
format
(
' in order to use a MakoDescriptor'
.
format
(
system
=
system
))
system
=
system
))
super
(
MakoModuleDescriptor
,
self
)
.
__init__
(
system
,
definition
,
**
kwargs
)
super
(
MakoModuleDescriptor
,
self
)
.
__init__
(
system
,
location
,
model_data
)
def
get_context
(
self
):
def
get_context
(
self
):
"""
"""
Return the context to render the mako template with
Return the context to render the mako template with
"""
"""
return
{
'module'
:
self
,
return
{
'module'
:
self
,
'metadata'
:
self
.
metadata
,
'editable_metadata_fields'
:
self
.
editable_fields
'editable_metadata_fields'
:
self
.
editable_metadata_fields
}
}
def
get_html
(
self
):
def
get_html
(
self
):
...
@@ -44,6 +43,6 @@ class MakoModuleDescriptor(XModuleDescriptor):
...
@@ -44,6 +43,6 @@ class MakoModuleDescriptor(XModuleDescriptor):
# cdodge: encapsulate a means to expose "editable" metadata fields (i.e. not internal system metadata)
# cdodge: encapsulate a means to expose "editable" metadata fields (i.e. not internal system metadata)
@property
@property
def
editable_metadata_fields
(
self
):
def
editable_metadata_fields
(
self
):
subset
=
[
name
for
name
in
self
.
metadata
.
keys
()
if
name
not
in
self
.
system_metadata_fields
]
subset
=
[
field
.
name
for
field
in
self
.
fields
if
field
.
name
not
in
self
.
system_metadata_fields
]
return
subset
return
subset
common/lib/xmodule/xmodule/model.py
0 → 100644
View file @
8ba41635
from
collections
import
namedtuple
class
ModuleScope
(
object
):
USAGE
,
DEFINITION
,
TYPE
,
ALL
=
xrange
(
4
)
class
Scope
(
namedtuple
(
'ScopeBase'
,
'student module'
)):
pass
Scope
.
content
=
Scope
(
student
=
False
,
module
=
ModuleScope
.
DEFINITION
)
Scope
.
student_state
=
Scope
(
student
=
True
,
module
=
ModuleScope
.
USAGE
)
Scope
.
settings
=
Scope
(
student
=
True
,
module
=
ModuleScope
.
USAGE
)
Scope
.
student_preferences
=
Scope
(
student
=
True
,
module
=
ModuleScope
.
TYPE
)
Scope
.
student_info
=
Scope
(
student
=
True
,
module
=
ModuleScope
.
ALL
)
class
ModelType
(
object
):
sequence
=
0
def
__init__
(
self
,
help
=
None
,
default
=
None
,
scope
=
Scope
.
content
):
self
.
_seq
=
self
.
sequence
self
.
_name
=
"unknown"
self
.
help
=
help
self
.
default
=
default
self
.
scope
=
scope
ModelType
.
sequence
+=
1
@property
def
name
(
self
):
return
self
.
_name
def
__get__
(
self
,
instance
,
owner
):
if
instance
is
None
:
return
self
return
instance
.
_model_data
.
get
(
self
.
name
,
self
.
default
)
def
__set__
(
self
,
instance
,
value
):
instance
.
_model_data
[
self
.
name
]
=
value
def
__delete__
(
self
,
instance
):
del
instance
.
_model_data
[
self
.
name
]
def
__repr__
(
self
):
return
"<{0.__class__.__name} {0.__name__}>"
.
format
(
self
)
def
__lt__
(
self
,
other
):
return
self
.
_seq
<
other
.
_seq
Int
=
Float
=
Boolean
=
Object
=
List
=
String
=
Any
=
ModelType
class
ModelMetaclass
(
type
):
def
__new__
(
cls
,
name
,
bases
,
attrs
):
# Find registered methods
reg_methods
=
{}
for
value
in
attrs
.
itervalues
():
for
reg_type
,
names
in
getattr
(
value
,
"_method_registrations"
,
{})
.
iteritems
():
for
n
in
names
:
reg_methods
[
reg_type
+
n
]
=
value
attrs
[
'registered_methods'
]
=
reg_methods
if
attrs
.
get
(
'has_children'
,
False
):
attrs
[
'children'
]
=
ModelType
(
help
=
'The children of this XModule'
,
default
=
[],
scope
=
None
)
@property
def
child_map
(
self
):
return
dict
((
child
.
name
,
child
)
for
child
in
self
.
children
)
attrs
[
'child_map'
]
=
child_map
fields
=
[]
for
n
,
v
in
attrs
.
items
():
if
isinstance
(
v
,
ModelType
):
v
.
_name
=
n
fields
.
append
(
v
)
fields
.
sort
()
attrs
[
'fields'
]
=
fields
return
super
(
ModelMetaclass
,
cls
)
.
__new__
(
cls
,
name
,
bases
,
attrs
)
common/lib/xmodule/xmodule/modulestore/xml.py
View file @
8ba41635
...
@@ -187,12 +187,13 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
...
@@ -187,12 +187,13 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
err_msg
err_msg
)
)
descriptor
.
metadata
[
'data_dir'
]
=
course_dir
setattr
(
descriptor
,
'data_dir'
,
course_dir
)
xmlstore
.
modules
[
course_id
][
descriptor
.
location
]
=
descriptor
xmlstore
.
modules
[
course_id
][
descriptor
.
location
]
=
descriptor
for
child
in
descriptor
.
get_children
():
if
hasattr
(
descriptor
,
'children'
):
parent_tracker
.
add_parent
(
child
.
location
,
descriptor
.
location
)
for
child
in
descriptor
.
children
:
parent_tracker
.
add_parent
(
child
.
location
,
descriptor
.
location
)
return
descriptor
return
descriptor
render_template
=
lambda
:
''
render_template
=
lambda
:
''
...
@@ -425,14 +426,14 @@ class XMLModuleStore(ModuleStoreBase):
...
@@ -425,14 +426,14 @@ class XMLModuleStore(ModuleStoreBase):
# breaks metadata inheritance via get_children(). Instead
# breaks metadata inheritance via get_children(). Instead
# (actually, in addition to, for now), we do a final inheritance pass
# (actually, in addition to, for now), we do a final inheritance pass
# after we have the course descriptor.
# after we have the course descriptor.
XModuleDescriptor
.
compute_inherited_metadata
(
course_descriptor
)
#
XModuleDescriptor.compute_inherited_metadata(course_descriptor)
# now import all pieces of course_info which is expected to be stored
# now import all pieces of course_info which is expected to be stored
# in <content_dir>/info or <content_dir>/info/<url_name>
# in <content_dir>/info or <content_dir>/info/<url_name>
self
.
load_extra_content
(
system
,
course_descriptor
,
'course_info'
,
self
.
data_dir
/
course_dir
/
'info'
,
course_dir
,
url_name
)
self
.
load_extra_content
(
system
,
course_descriptor
,
'course_info'
,
self
.
data_dir
/
course_dir
/
'info'
,
course_dir
,
url_name
)
# now import all static tabs which are expected to be stored in
# now import all static tabs which are expected to be stored in
# in <content_dir>/tabs or <content_dir>/tabs/<url_name>
# in <content_dir>/tabs or <content_dir>/tabs/<url_name>
self
.
load_extra_content
(
system
,
course_descriptor
,
'static_tab'
,
self
.
data_dir
/
course_dir
/
'tabs'
,
course_dir
,
url_name
)
self
.
load_extra_content
(
system
,
course_descriptor
,
'static_tab'
,
self
.
data_dir
/
course_dir
/
'tabs'
,
course_dir
,
url_name
)
self
.
load_extra_content
(
system
,
course_descriptor
,
'custom_tag_template'
,
self
.
data_dir
/
course_dir
/
'custom_tags'
,
course_dir
,
url_name
)
self
.
load_extra_content
(
system
,
course_descriptor
,
'custom_tag_template'
,
self
.
data_dir
/
course_dir
/
'custom_tags'
,
course_dir
,
url_name
)
...
@@ -444,30 +445,30 @@ class XMLModuleStore(ModuleStoreBase):
...
@@ -444,30 +445,30 @@ class XMLModuleStore(ModuleStoreBase):
def
load_extra_content
(
self
,
system
,
course_descriptor
,
category
,
base_dir
,
course_dir
,
url_name
):
def
load_extra_content
(
self
,
system
,
course_descriptor
,
category
,
base_dir
,
course_dir
,
url_name
):
if
url_name
:
if
url_name
:
path
=
base_dir
/
url_name
path
=
base_dir
/
url_name
if
not
os
.
path
.
exists
(
path
):
if
not
os
.
path
.
exists
(
path
):
path
=
base_dir
path
=
base_dir
for
filepath
in
glob
.
glob
(
path
/
'*'
):
for
filepath
in
glob
.
glob
(
path
/
'*'
):
with
open
(
filepath
)
as
f
:
with
open
(
filepath
)
as
f
:
try
:
try
:
html
=
f
.
read
()
.
decode
(
'utf-8'
)
html
=
f
.
read
()
.
decode
(
'utf-8'
)
# tabs are referenced in policy.json through a 'slug' which is just the filename without the .html suffix
# tabs are referenced in policy.json through a 'slug' which is just the filename without the .html suffix
slug
=
os
.
path
.
splitext
(
os
.
path
.
basename
(
filepath
))[
0
]
slug
=
os
.
path
.
splitext
(
os
.
path
.
basename
(
filepath
))[
0
]
loc
=
Location
(
'i4x'
,
course_descriptor
.
location
.
org
,
course_descriptor
.
location
.
course
,
category
,
slug
)
loc
=
Location
(
'i4x'
,
course_descriptor
.
location
.
org
,
course_descriptor
.
location
.
course
,
category
,
slug
)
module
=
HtmlDescriptor
(
system
,
definition
=
{
'data'
:
html
},
**
{
'location'
:
loc
})
module
=
HtmlDescriptor
(
system
,
loc
,
{
'data'
:
html
})
# VS[compat]:
# VS[compat]:
# Hack because we need to pull in the 'display_name' for static tabs (because we need to edit them)
# Hack because we need to pull in the 'display_name' for static tabs (because we need to edit them)
# from the course policy
# from the course policy
if
category
==
"static_tab"
:
if
category
==
"static_tab"
:
for
tab
in
course_descriptor
.
tabs
or
[]:
for
tab
in
course_descriptor
.
tabs
or
[]:
if
tab
.
get
(
'url_slug'
)
==
slug
:
if
tab
.
get
(
'url_slug'
)
==
slug
:
module
.
metadata
[
'display_name'
]
=
tab
[
'name'
]
module
.
display_name
=
tab
[
'name'
]
module
.
metadata
[
'data_dir'
]
=
course_dir
module
.
data_dir
=
course_dir
self
.
modules
[
course_descriptor
.
id
][
module
.
location
]
=
module
self
.
modules
[
course_descriptor
.
id
][
module
.
location
]
=
module
except
Exception
,
e
:
except
Exception
,
e
:
logging
.
exception
(
"Failed to load {0}. Skipping... Exception: {1}"
.
format
(
filepath
,
str
(
e
)))
logging
.
exception
(
"Failed to load {0}. Skipping... Exception: {1}"
.
format
(
filepath
,
str
(
e
)))
system
.
error_tracker
(
"ERROR: "
+
str
(
e
))
system
.
error_tracker
(
"ERROR: "
+
str
(
e
))
def
get_instance
(
self
,
course_id
,
location
,
depth
=
0
):
def
get_instance
(
self
,
course_id
,
location
,
depth
=
0
):
...
...
common/lib/xmodule/xmodule/template_module.py
View file @
8ba41635
...
@@ -67,10 +67,6 @@ class CustomTagDescriptor(RawDescriptor):
...
@@ -67,10 +67,6 @@ class CustomTagDescriptor(RawDescriptor):
return
template
.
render
(
**
params
)
return
template
.
render
(
**
params
)
def
__init__
(
self
,
system
,
definition
,
**
kwargs
):
'''Render and save the template for this descriptor instance'''
super
(
CustomTagDescriptor
,
self
)
.
__init__
(
system
,
definition
,
**
kwargs
)
@property
@property
def
rendered_html
(
self
):
def
rendered_html
(
self
):
return
self
.
render_template
(
self
.
system
,
self
.
definition
[
'data'
])
return
self
.
render_template
(
self
.
system
,
self
.
definition
[
'data'
])
...
...
common/lib/xmodule/xmodule/x_module.py
View file @
8ba41635
...
@@ -2,19 +2,41 @@ import logging
...
@@ -2,19 +2,41 @@ import logging
import
pkg_resources
import
pkg_resources
import
yaml
import
yaml
import
os
import
os
import
time
from
functools
import
partial
from
lxml
import
etree
from
lxml
import
etree
from
pprint
import
pprint
from
pprint
import
pprint
from
collections
import
namedtuple
from
collections
import
namedtuple
from
pkg_resources
import
resource_listdir
,
resource_string
,
resource_isdir
from
pkg_resources
import
resource_listdir
,
resource_string
,
resource_isdir
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.timeparse
import
parse_time
,
stringify_tim
e
from
.model
import
ModelMetaclass
,
String
,
Scope
,
ModuleScope
,
ModelTyp
e
from
xmodule.contentstore.content
import
StaticContent
,
XASSET_SRCREF_PREFIX
Date
=
ModelType
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
import
time
class
Date
(
ModelType
):
time_format
=
"
%
Y-
%
m-
%
dT
%
H:
%
M"
def
from_json
(
self
,
value
):
"""
Parse an optional metadata key containing a time: if present, complain
if it doesn't parse.
Return None if not present or invalid.
"""
try
:
return
time
.
strptime
(
value
,
self
.
time_format
)
except
ValueError
as
e
:
msg
=
"Field {0} has bad value '{1}': '{2}'"
.
format
(
self
.
_name
,
value
,
e
)
log
.
warning
(
msg
)
return
None
def
to_json
(
self
,
value
):
"""
Convert a time struct to a string
"""
return
time
.
strftime
(
self
.
time_format
,
value
)
log
=
logging
.
getLogger
(
'mitx.'
+
__name__
)
log
=
logging
.
getLogger
(
'mitx.'
+
__name__
)
...
@@ -157,6 +179,10 @@ class XModule(HTMLSnippet):
...
@@ -157,6 +179,10 @@ class XModule(HTMLSnippet):
See the HTML module for a simple example.
See the HTML module for a simple example.
'''
'''
__metaclass__
=
ModelMetaclass
display_name
=
String
(
help
=
"Display name for this module"
,
scope
=
Scope
(
student
=
False
,
module
=
ModuleScope
.
USAGE
))
# The default implementation of get_icon_class returns the icon_class
# The default implementation of get_icon_class returns the icon_class
# attribute of the class
# attribute of the class
#
#
...
@@ -165,8 +191,7 @@ class XModule(HTMLSnippet):
...
@@ -165,8 +191,7 @@ class XModule(HTMLSnippet):
# in the module
# in the module
icon_class
=
'other'
icon_class
=
'other'
def
__init__
(
self
,
system
,
location
,
definition
,
descriptor
,
def
__init__
(
self
,
system
,
location
,
descriptor
,
model_data
):
instance_state
=
None
,
shared_state
=
None
,
**
kwargs
):
'''
'''
Construct a new xmodule
Construct a new xmodule
...
@@ -214,63 +239,25 @@ class XModule(HTMLSnippet):
...
@@ -214,63 +239,25 @@ class XModule(HTMLSnippet):
'''
'''
self
.
system
=
system
self
.
system
=
system
self
.
location
=
Location
(
location
)
self
.
location
=
Location
(
location
)
self
.
definition
=
definition
self
.
descriptor
=
descriptor
self
.
descriptor
=
descriptor
self
.
instance_state
=
instance_state
self
.
shared_state
=
shared_state
self
.
id
=
self
.
location
.
url
()
self
.
id
=
self
.
location
.
url
()
self
.
url_name
=
self
.
location
.
name
self
.
url_name
=
self
.
location
.
name
self
.
category
=
self
.
location
.
category
self
.
category
=
self
.
location
.
category
self
.
metadata
=
kwargs
.
get
(
'metadata'
,
{})
self
.
_model_data
=
model_data
self
.
_loaded_children
=
None
@property
if
self
.
display_name
is
None
:
def
display_name
(
self
):
self
.
display_name
=
self
.
url_name
.
replace
(
'_'
,
' '
)
'''
Return a display name for the module: use display_name if defined in
metadata, otherwise convert the url name.
'''
return
self
.
metadata
.
get
(
'display_name'
,
self
.
url_name
.
replace
(
'_'
,
' '
))
def
__unicode__
(
self
):
def
__unicode__
(
self
):
return
'<x_module(id={0})>'
.
format
(
self
.
id
)
return
'<x_module(id={0})>'
.
format
(
self
.
id
)
def
get_children
(
self
):
'''
Return module instances for all the children of this module.
'''
if
self
.
_loaded_children
is
None
:
child_locations
=
self
.
get_children_locations
()
children
=
[
self
.
system
.
get_module
(
loc
)
for
loc
in
child_locations
]
# get_module returns None if the current user doesn't have access
# to the location.
self
.
_loaded_children
=
[
c
for
c
in
children
if
c
is
not
None
]
return
self
.
_loaded_children
def
get_children_locations
(
self
):
'''
Returns the locations of each of child modules.
Overriding this changes the behavior of get_children and
anything that uses get_children, such as get_display_items.
This method will not instantiate the modules of the children
unless absolutely necessary, so it is cheaper to call than get_children
These children will be the same children returned by the
descriptor unless descriptor.has_dynamic_children() is true.
'''
return
self
.
definition
.
get
(
'children'
,
[])
def
get_display_items
(
self
):
def
get_display_items
(
self
):
'''
'''
Returns a list of descendent module instances that will display
Returns a list of descendent module instances that will display
immediately inside this module.
immediately inside this module.
'''
'''
items
=
[]
items
=
[]
for
child
in
self
.
get_
children
():
for
child
in
self
.
children
():
items
.
extend
(
child
.
displayable_items
())
items
.
extend
(
child
.
displayable_items
())
return
items
return
items
...
@@ -290,18 +277,6 @@ class XModule(HTMLSnippet):
...
@@ -290,18 +277,6 @@ class XModule(HTMLSnippet):
### Functions used in the LMS
### Functions used in the LMS
def
get_instance_state
(
self
):
''' State of the object, as stored in the database
'''
return
'{}'
def
get_shared_state
(
self
):
'''
Get state that should be shared with other instances
using the same 'shared_state_key' attribute.
'''
return
'{}'
def
get_score
(
self
):
def
get_score
(
self
):
''' Score the student received on the problem.
''' Score the student received on the problem.
'''
'''
...
@@ -391,7 +366,10 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
...
@@ -391,7 +366,10 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
"""
"""
entry_point
=
"xmodule.v1"
entry_point
=
"xmodule.v1"
module_class
=
XModule
module_class
=
XModule
__metaclass__
=
ModelMetaclass
display_name
=
String
(
help
=
"Display name for this module"
,
scope
=
Scope
(
student
=
False
,
module
=
ModuleScope
.
USAGE
))
start
=
Date
(
help
=
"Start time when this module is visible"
,
scope
=
Scope
(
student
=
False
,
module
=
ModuleScope
.
USAGE
))
# Attributes for inspection of the descriptor
# Attributes for inspection of the descriptor
stores_state
=
False
# Indicates whether the xmodule state should be
stores_state
=
False
# Indicates whether the xmodule state should be
# stored in a database (independent of shared state)
# stored in a database (independent of shared state)
...
@@ -424,8 +402,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
...
@@ -424,8 +402,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
# ============================= STRUCTURAL MANIPULATION ===================
# ============================= STRUCTURAL MANIPULATION ===================
def
__init__
(
self
,
def
__init__
(
self
,
system
,
system
,
definition
=
None
,
location
,
**
kwargs
):
model_data
):
"""
"""
Construct a new XModuleDescriptor. The only required arguments are the
Construct a new XModuleDescriptor. The only required arguments are the
system, used for interaction with external resources, and the
system, used for interaction with external resources, and the
...
@@ -467,116 +445,36 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
...
@@ -467,116 +445,36 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
instance of the module data
instance of the module data
"""
"""
self
.
system
=
system
self
.
system
=
system
self
.
metadata
=
kwargs
.
get
(
'metadata'
,
{})
self
.
location
=
Location
(
location
)
self
.
definition
=
definition
if
definition
is
not
None
else
{}
self
.
location
=
Location
(
kwargs
.
get
(
'location'
))
self
.
url_name
=
self
.
location
.
name
self
.
url_name
=
self
.
location
.
name
self
.
category
=
self
.
location
.
category
self
.
category
=
self
.
location
.
category
self
.
shared_state_key
=
kwargs
.
get
(
'shared_state_key'
)
self
.
_model_data
=
model_data
self
.
_child_instances
=
None
self
.
_child_instances
=
None
self
.
_inherited_metadata
=
set
()
self
.
_inherited_metadata
=
set
()
@property
def
display_name
(
self
):
'''
Return a display name for the module: use display_name if defined in
metadata, otherwise convert the url name.
'''
return
self
.
metadata
.
get
(
'display_name'
,
self
.
url_name
.
replace
(
'_'
,
' '
))
@property
def
start
(
self
):
"""
If self.metadata contains start, return it. Else return None.
"""
if
'start'
not
in
self
.
metadata
:
return
None
return
self
.
_try_parse_time
(
'start'
)
@start.setter
def
start
(
self
,
value
):
if
isinstance
(
value
,
time
.
struct_time
):
self
.
metadata
[
'start'
]
=
stringify_time
(
value
)
@property
def
own_metadata
(
self
):
"""
Return the metadata that is not inherited, but was defined on this module.
"""
return
dict
((
k
,
v
)
for
k
,
v
in
self
.
metadata
.
items
()
if
k
not
in
self
.
_inherited_metadata
)
@staticmethod
def
compute_inherited_metadata
(
node
):
"""Given a descriptor, traverse all of its descendants and do metadata
inheritance. Should be called on a CourseDescriptor after importing a
course.
NOTE: This means that there is no such thing as lazy loading at the
moment--this accesses all the children."""
for
c
in
node
.
get_children
():
c
.
inherit_metadata
(
node
.
metadata
)
XModuleDescriptor
.
compute_inherited_metadata
(
c
)
def
inherit_metadata
(
self
,
metadata
):
"""
Updates this module with metadata inherited from a containing module.
Only metadata specified in self.inheritable_metadata will
be inherited
"""
# Set all inheritable metadata from kwargs that are
# in self.inheritable_metadata and aren't already set in metadata
for
attr
in
self
.
inheritable_metadata
:
if
attr
not
in
self
.
metadata
and
attr
in
metadata
:
self
.
_inherited_metadata
.
add
(
attr
)
self
.
metadata
[
attr
]
=
metadata
[
attr
]
def
get_children
(
self
):
"""Returns a list of XModuleDescriptor instances for the children of
this module"""
if
self
.
_child_instances
is
None
:
self
.
_child_instances
=
[]
for
child_loc
in
self
.
definition
.
get
(
'children'
,
[]):
try
:
child
=
self
.
system
.
load_item
(
child_loc
)
except
ItemNotFoundError
:
log
.
exception
(
'Unable to load item {loc}, skipping'
.
format
(
loc
=
child_loc
))
continue
# TODO (vshnayder): this should go away once we have
# proper inheritance support in mongo. The xml
# datastore does all inheritance on course load.
child
.
inherit_metadata
(
self
.
metadata
)
self
.
_child_instances
.
append
(
child
)
return
self
.
_child_instances
def
get_child_by_url_name
(
self
,
url_name
):
def
get_child_by_url_name
(
self
,
url_name
):
"""
"""
Return a child XModuleDescriptor with the specified url_name, if it exists, and None otherwise.
Return a child XModuleDescriptor with the specified url_name, if it exists, and None otherwise.
"""
"""
for
c
in
self
.
get_children
()
:
for
c
in
self
.
children
:
if
c
.
url_name
==
url_name
:
if
c
.
url_name
==
url_name
:
return
c
return
c
return
None
return
None
def
xmodule
_constructor
(
self
,
system
):
def
xmodule
(
self
,
system
):
"""
"""
Returns a constructor for an XModule. This constructor takes two
Returns a constructor for an XModule. This constructor takes two
arguments: instance_state and shared_state, and returns a fully
arguments: instance_state and shared_state, and returns a fully
instantiated XModule
instantiated XModule
"""
"""
return
partial
(
return
self
.
module_class
(
self
.
module_class
,
system
,
system
,
self
.
location
,
self
.
location
,
self
.
definition
,
self
,
self
,
metadata
=
self
.
metadata
system
.
xmodule_model_data
(
self
.
model_data
),
)
)
def
has_dynamic_children
(
self
):
def
has_dynamic_children
(
self
):
"""
"""
Returns True if this descriptor has dynamic children for a given
Returns True if this descriptor has dynamic children for a given
...
@@ -701,31 +599,14 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
...
@@ -701,31 +599,14 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
return
eq
return
eq
def
__repr__
(
self
):
def
__repr__
(
self
):
return
(
"{class_}({system!r},
{definition!r},
location={location!r},"
return
(
"{class_}({system!r}, location={location!r},"
" m
etadata={meta
data!r})"
.
format
(
" m
odel_data={model_
data!r})"
.
format
(
class_
=
self
.
__class__
.
__name__
,
class_
=
self
.
__class__
.
__name__
,
system
=
self
.
system
,
system
=
self
.
system
,
definition
=
self
.
definition
,
location
=
self
.
location
,
location
=
self
.
location
,
m
etadata
=
self
.
metadata
m
odel_data
=
self
.
_model_data
,
))
))
# ================================ Internal helpers =======================
def
_try_parse_time
(
self
,
key
):
"""
Parse an optional metadata key containing a time: if present, complain
if it doesn't parse.
Return None if not present or invalid.
"""
if
key
in
self
.
metadata
:
try
:
return
parse_time
(
self
.
metadata
[
key
])
except
ValueError
as
e
:
msg
=
"Descriptor {0} loaded with a bad metadata key '{1}': '{2}'"
.
format
(
self
.
location
.
url
(),
self
.
metadata
[
key
],
e
)
log
.
warning
(
msg
)
return
None
class
DescriptorSystem
(
object
):
class
DescriptorSystem
(
object
):
...
@@ -867,6 +748,9 @@ class ModuleSystem(object):
...
@@ -867,6 +748,9 @@ class ModuleSystem(object):
'''provide uniform access to attributes (like etree)'''
'''provide uniform access to attributes (like etree)'''
self
.
__dict__
[
attr
]
=
val
self
.
__dict__
[
attr
]
=
val
def
xmodule_module_data
(
self
,
module_data
):
return
module_data
def
__repr__
(
self
):
def
__repr__
(
self
):
return
repr
(
self
.
__dict__
)
return
repr
(
self
.
__dict__
)
...
...
common/lib/xmodule/xmodule/xml_module.py
View file @
8ba41635
...
@@ -287,9 +287,9 @@ class XmlDescriptor(XModuleDescriptor):
...
@@ -287,9 +287,9 @@ class XmlDescriptor(XModuleDescriptor):
filepath
=
cls
.
_format_filepath
(
xml_object
.
tag
,
name_to_pathname
(
url_name
))
filepath
=
cls
.
_format_filepath
(
xml_object
.
tag
,
name_to_pathname
(
url_name
))
definition_xml
=
cls
.
load_file
(
filepath
,
system
.
resources_fs
,
location
)
definition_xml
=
cls
.
load_file
(
filepath
,
system
.
resources_fs
,
location
)
else
:
else
:
definition_xml
=
xml_object
# this is just a pointer, not the real definition content
definition_xml
=
xml_object
# this is just a pointer, not the real definition content
definition
=
cls
.
load_definition
(
definition_xml
,
system
,
location
)
# note this removes metadata
definition
=
cls
.
load_definition
(
definition_xml
,
system
,
location
)
# note this removes metadata
# VS[compat] -- make Ike's github preview links work in both old and
# VS[compat] -- make Ike's github preview links work in both old and
# new file layouts
# new file layouts
if
is_pointer_tag
(
xml_object
):
if
is_pointer_tag
(
xml_object
):
...
@@ -299,13 +299,13 @@ class XmlDescriptor(XModuleDescriptor):
...
@@ -299,13 +299,13 @@ class XmlDescriptor(XModuleDescriptor):
metadata
=
cls
.
load_metadata
(
definition_xml
)
metadata
=
cls
.
load_metadata
(
definition_xml
)
# move definition metadata into dict
# move definition metadata into dict
dmdata
=
definition
.
get
(
'definition_metadata'
,
''
)
dmdata
=
definition
.
get
(
'definition_metadata'
,
''
)
if
dmdata
:
if
dmdata
:
metadata
[
'definition_metadata_raw'
]
=
dmdata
metadata
[
'definition_metadata_raw'
]
=
dmdata
try
:
try
:
metadata
.
update
(
json
.
loads
(
dmdata
))
metadata
.
update
(
json
.
loads
(
dmdata
))
except
Exception
as
err
:
except
Exception
as
err
:
log
.
debug
(
'Error
%
s in loading metadata
%
s'
%
(
err
,
dmdata
))
log
.
debug
(
'Error
%
s in loading metadata
%
s'
%
(
err
,
dmdata
))
metadata
[
'definition_metadata_err'
]
=
str
(
err
)
metadata
[
'definition_metadata_err'
]
=
str
(
err
)
# Set/override any metadata specified by policy
# Set/override any metadata specified by policy
...
@@ -313,11 +313,14 @@ class XmlDescriptor(XModuleDescriptor):
...
@@ -313,11 +313,14 @@ class XmlDescriptor(XModuleDescriptor):
if
k
in
system
.
policy
:
if
k
in
system
.
policy
:
cls
.
apply_policy
(
metadata
,
system
.
policy
[
k
])
cls
.
apply_policy
(
metadata
,
system
.
policy
[
k
])
model_data
=
{}
model_data
.
update
(
metadata
)
model_data
.
update
(
definition
)
return
cls
(
return
cls
(
system
,
system
,
definition
,
location
,
location
=
location
,
model_data
,
metadata
=
metadata
,
)
)
@classmethod
@classmethod
...
...
jenkins/base.sh
0 → 100644
View file @
8ba41635
function
github_status
{
gcli status create mitx mitx
$GIT_COMMIT
\
--params
=
$1
\
target_url:
$BUILD_URL
\
description:
"Build #
$BUILD_NUMBER
is running"
\
-f
csv
}
function
github_mark_failed_on_exit
{
trap
'[ $? == "0" ] || github_status state:failed'
EXIT
}
\ No newline at end of file
lms/djangoapps/courseware/courses.py
View file @
8ba41635
...
@@ -85,7 +85,7 @@ def course_image_url(course):
...
@@ -85,7 +85,7 @@ def course_image_url(course):
"""Try to look up the image url for the course. If it's not found,
"""Try to look up the image url for the course. If it's not found,
log an error and return the dead link"""
log an error and return the dead link"""
if
isinstance
(
modulestore
(),
XMLModuleStore
):
if
isinstance
(
modulestore
(),
XMLModuleStore
):
path
=
course
.
metadata
[
'data_dir'
]
+
"/images/course_image.jpg"
path
=
course
.
data_dir
+
"/images/course_image.jpg"
return
try_staticfiles_lookup
(
path
)
return
try_staticfiles_lookup
(
path
)
else
:
else
:
loc
=
course
.
location
.
_replace
(
tag
=
'c4x'
,
category
=
'asset'
,
name
=
'images_course_image.jpg'
)
loc
=
course
.
location
.
_replace
(
tag
=
'c4x'
,
category
=
'asset'
,
name
=
'images_course_image.jpg'
)
...
@@ -162,7 +162,9 @@ def get_course_about_section(course, section_key):
...
@@ -162,7 +162,9 @@ def get_course_about_section(course, section_key):
key
=
section_key
,
url
=
course
.
location
.
url
()))
key
=
section_key
,
url
=
course
.
location
.
url
()))
return
None
return
None
elif
section_key
==
"title"
:
elif
section_key
==
"title"
:
return
course
.
metadata
.
get
(
'display_name'
,
course
.
url_name
)
if
course
.
display_name
is
None
:
return
course
.
url_name
return
course
.
display_name
elif
section_key
==
"university"
:
elif
section_key
==
"university"
:
return
course
.
location
.
org
return
course
.
location
.
org
elif
section_key
==
"number"
:
elif
section_key
==
"number"
:
...
@@ -220,7 +222,7 @@ def get_course_syllabus_section(course, section_key):
...
@@ -220,7 +222,7 @@ def get_course_syllabus_section(course, section_key):
filepath
=
find_file
(
fs
,
dirs
,
section_key
+
".html"
)
filepath
=
find_file
(
fs
,
dirs
,
section_key
+
".html"
)
with
fs
.
open
(
filepath
)
as
htmlFile
:
with
fs
.
open
(
filepath
)
as
htmlFile
:
return
replace_urls
(
htmlFile
.
read
()
.
decode
(
'utf-8'
),
return
replace_urls
(
htmlFile
.
read
()
.
decode
(
'utf-8'
),
course
.
metadata
[
'data_dir'
]
,
course_namespace
=
course
.
location
)
course
.
data_dir
,
course_namespace
=
course
.
location
)
except
ResourceNotFoundError
:
except
ResourceNotFoundError
:
log
.
exception
(
"Missing syllabus section {key} in course {url}"
.
format
(
log
.
exception
(
"Missing syllabus section {key} in course {url}"
.
format
(
key
=
section_key
,
url
=
course
.
location
.
url
()))
key
=
section_key
,
url
=
course
.
location
.
url
()))
...
...
lms/djangoapps/courseware/module_render.py
View file @
8ba41635
...
@@ -245,7 +245,7 @@ def _get_module(user, request, location, student_module_cache, course_id, positi
...
@@ -245,7 +245,7 @@ def _get_module(user, request, location, student_module_cache, course_id, positi
make_psychometrics_data_update_handler
(
instance_module
))
make_psychometrics_data_update_handler
(
instance_module
))
try
:
try
:
module
=
descriptor
.
xmodule
_constructor
(
system
)(
instance_state
,
shared_state
)
module
=
descriptor
.
xmodule
(
system
)
except
:
except
:
log
.
exception
(
"Error creating module from descriptor {0}"
.
format
(
descriptor
))
log
.
exception
(
"Error creating module from descriptor {0}"
.
format
(
descriptor
))
...
@@ -259,7 +259,7 @@ def _get_module(user, request, location, student_module_cache, course_id, positi
...
@@ -259,7 +259,7 @@ def _get_module(user, request, location, student_module_cache, course_id, positi
error_msg
=
exc_info_to_str
(
sys
.
exc_info
()))
error_msg
=
exc_info_to_str
(
sys
.
exc_info
()))
# Make an error module
# Make an error module
return
err_descriptor
.
xmodule
_constructor
(
system
)(
None
,
None
)
return
err_descriptor
.
xmodule
(
system
)
_get_html
=
module
.
get_html
_get_html
=
module
.
get_html
...
...
rakefile
View file @
8ba41635
...
@@ -40,7 +40,7 @@ end
...
@@ -40,7 +40,7 @@ end
def
django_admin
(
system
,
env
,
command
,
*
args
)
def
django_admin
(
system
,
env
,
command
,
*
args
)
django_admin
=
ENV
[
'DJANGO_ADMIN_PATH'
]
||
select_executable
(
'django-admin.py'
,
'django-admin'
)
django_admin
=
ENV
[
'DJANGO_ADMIN_PATH'
]
||
select_executable
(
'django-admin.py'
,
'django-admin'
)
return
"
#{
django_admin
}
#{
command
}
--settings=
#{
system
}
.envs.
#{
env
}
--pythonpath=.
#{
args
.
join
(
' '
)
}
"
return
"
#{
django_admin
}
#{
command
}
--
traceback --
settings=
#{
system
}
.envs.
#{
env
}
--pythonpath=.
#{
args
.
join
(
' '
)
}
"
end
end
def
django_for_jasmine
(
system
,
django_reload
)
def
django_for_jasmine
(
system
,
django_reload
)
...
...
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