Give LoncapaProblem its own LoncapaSystem instead of ModuleSystem
LoncapaProblem was using ModuleSystem directly, but we're about to need i18n passed in, so this gives LoncapaProblem its own LoncapaSystem object to better module its dependencies. This commit simply passes through the attributes of ModuleSystem that Loncapa needs. [LMS-1597]
This commit is contained in:
@@ -63,37 +63,73 @@ log = logging.getLogger(__name__)
|
||||
# main class for this module
|
||||
|
||||
|
||||
class LoncapaSystem(object):
|
||||
"""
|
||||
An encapsulation of resources needed from the outside.
|
||||
|
||||
These interfaces are collected here so that a caller of LoncapaProblem
|
||||
can provide these resources however make sense for their environment, and
|
||||
this code can remain independent.
|
||||
|
||||
See :class:`ModuleSystem` for documentation of these attributes.
|
||||
|
||||
"""
|
||||
def __init__( # pylint: disable=invalid-name
|
||||
self,
|
||||
ajax_url,
|
||||
anonymous_student_id,
|
||||
cache,
|
||||
can_execute_unsafe_code,
|
||||
DEBUG, # pylint: disable=invalid-name
|
||||
filestore,
|
||||
node_path,
|
||||
render_template,
|
||||
seed, # Why do we do this if we have self.seed?
|
||||
STATIC_URL, # pylint: disable=invalid-name
|
||||
xqueue,
|
||||
):
|
||||
self.ajax_url = ajax_url
|
||||
self.anonymous_student_id = anonymous_student_id
|
||||
self.cache = cache
|
||||
self.can_execute_unsafe_code = can_execute_unsafe_code
|
||||
self.DEBUG = DEBUG # pylint: disable=invalid-name
|
||||
self.filestore = filestore
|
||||
self.node_path = node_path
|
||||
self.render_template = render_template
|
||||
self.seed = seed # Why do we do this if we have self.seed?
|
||||
self.STATIC_URL = STATIC_URL # pylint: disable=invalid-name
|
||||
self.xqueue = xqueue
|
||||
|
||||
|
||||
class LoncapaProblem(object):
|
||||
'''
|
||||
Main class for capa Problems.
|
||||
'''
|
||||
|
||||
def __init__(self, problem_text, id, state=None, seed=None, system=None):
|
||||
'''
|
||||
def __init__(self, problem_text, id, capa_system, state=None, seed=None):
|
||||
"""
|
||||
Initializes capa Problem.
|
||||
|
||||
Arguments:
|
||||
|
||||
- problem_text (string): xml defining the problem
|
||||
- id (string): identifier for this problem; often a filename (no spaces)
|
||||
- seed (int): random number generator seed (int)
|
||||
- state (dict): containing the following keys:
|
||||
- 'seed' - (int) random number generator seed
|
||||
- 'student_answers' - (dict) maps input id to the stored answer for that input
|
||||
- 'correct_map' (CorrectMap) a map of each input to their 'correctness'
|
||||
- 'done' - (bool) indicates whether or not this problem is considered done
|
||||
- 'input_state' - (dict) maps input_id to a dictionary that holds the state for that input
|
||||
- system (ModuleSystem): ModuleSystem instance which provides OS,
|
||||
rendering, and user context
|
||||
problem_text (string): xml defining the problem.
|
||||
id (string): identifier for this problem, often a filename (no spaces).
|
||||
capa_system (LoncapaSystem): LoncapaSystem instance which provides OS,
|
||||
rendering, user context, and other resources.
|
||||
state (dict): containing the following keys:
|
||||
- `seed` (int) random number generator seed
|
||||
- `student_answers` (dict) maps input id to the stored answer for that input
|
||||
- `correct_map` (CorrectMap) a map of each input to their 'correctness'
|
||||
- `done` (bool) indicates whether or not this problem is considered done
|
||||
- `input_state` (dict) maps input_id to a dictionary that holds the state for that input
|
||||
seed (int): random number generator seed.
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
## Initialize class variables from state
|
||||
self.do_reset()
|
||||
self.problem_id = id
|
||||
self.system = system
|
||||
if self.system is None:
|
||||
raise Exception()
|
||||
self.capa_system = capa_system
|
||||
|
||||
state = state or {}
|
||||
|
||||
@@ -412,8 +448,8 @@ class LoncapaProblem(object):
|
||||
filename = inc.get('file')
|
||||
if filename is not None:
|
||||
try:
|
||||
# open using ModuleSystem OSFS filestore
|
||||
ifp = self.system.filestore.open(filename)
|
||||
# open using LoncapaSystem OSFS filestore
|
||||
ifp = self.capa_system.filestore.open(filename)
|
||||
except Exception as err:
|
||||
log.warning(
|
||||
'Error %s in problem xml include: %s' % (
|
||||
@@ -422,12 +458,12 @@ class LoncapaProblem(object):
|
||||
)
|
||||
log.warning(
|
||||
'Cannot find file %s in %s' % (
|
||||
filename, self.system.filestore
|
||||
filename, self.capa_system.filestore
|
||||
)
|
||||
)
|
||||
# if debugging, don't fail - just log error
|
||||
# TODO (vshnayder): need real error handling, display to users
|
||||
if not self.system.get('DEBUG'):
|
||||
if not self.capa_system.DEBUG:
|
||||
raise
|
||||
else:
|
||||
continue
|
||||
@@ -443,7 +479,7 @@ class LoncapaProblem(object):
|
||||
log.warning('Cannot parse XML in %s' % (filename))
|
||||
# if debugging, don't fail - just log error
|
||||
# TODO (vshnayder): same as above
|
||||
if not self.system.get('DEBUG'):
|
||||
if not self.capa_system.DEBUG:
|
||||
raise
|
||||
else:
|
||||
continue
|
||||
@@ -476,9 +512,9 @@ class LoncapaProblem(object):
|
||||
continue
|
||||
|
||||
# path is an absolute path or a path relative to the data dir
|
||||
dir = os.path.join(self.system.filestore.root_path, dir)
|
||||
dir = os.path.join(self.capa_system.filestore.root_path, dir)
|
||||
# Check that we are within the filestore tree.
|
||||
reldir = os.path.relpath(dir, self.system.filestore.root_path)
|
||||
reldir = os.path.relpath(dir, self.capa_system.filestore.root_path)
|
||||
if ".." in reldir:
|
||||
log.warning("Ignoring Python directory outside of course: %r" % dir)
|
||||
continue
|
||||
@@ -527,9 +563,9 @@ class LoncapaProblem(object):
|
||||
context,
|
||||
random_seed=self.seed,
|
||||
python_path=python_path,
|
||||
cache=self.system.cache,
|
||||
cache=self.capa_system.cache,
|
||||
slug=self.problem_id,
|
||||
unsafely=self.system.can_execute_unsafe_code(),
|
||||
unsafely=self.capa_system.can_execute_unsafe_code(),
|
||||
)
|
||||
except Exception as err:
|
||||
log.exception("Error while execing script code: " + all_code)
|
||||
@@ -600,7 +636,7 @@ class LoncapaProblem(object):
|
||||
|
||||
input_type_cls = inputtypes.registry.get_class_for_tag(problemtree.tag)
|
||||
# save the input type so that we can make ajax calls on it if we need to
|
||||
self.inputs[input_id] = input_type_cls(self.system, problemtree, state)
|
||||
self.inputs[input_id] = input_type_cls(self.capa_system, problemtree, state)
|
||||
return self.inputs[input_id].get_html()
|
||||
|
||||
# let each Response render itself
|
||||
@@ -613,7 +649,7 @@ class LoncapaProblem(object):
|
||||
# let each custom renderer render itself:
|
||||
if problemtree.tag in customrender.registry.registered_tags():
|
||||
renderer_class = customrender.registry.get_class_for_tag(problemtree.tag)
|
||||
renderer = renderer_class(self.system, problemtree)
|
||||
renderer = renderer_class(self.capa_system, problemtree)
|
||||
return renderer.get_html()
|
||||
|
||||
# otherwise, render children recursively, and copy over attributes
|
||||
@@ -670,7 +706,7 @@ class LoncapaProblem(object):
|
||||
|
||||
# instantiate capa Response
|
||||
responsetype_cls = responsetypes.registry.get_class_for_tag(response.tag)
|
||||
responder = responsetype_cls(response, inputfields, self.context, self.system)
|
||||
responder = responsetype_cls(response, inputfields, self.context, self.capa_system)
|
||||
# save in list in self
|
||||
self.responders[response] = responder
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ class InputTypeBase(object):
|
||||
"""
|
||||
Instantiate an InputType class. Arguments:
|
||||
|
||||
- system : ModuleSystem instance which provides OS, rendering, and user context.
|
||||
- system : LoncapaModule instance which provides OS, rendering, and user context.
|
||||
Specifically, must have a render_template function.
|
||||
- xml : Element tree of this Input element
|
||||
- state : a dictionary with optional keys:
|
||||
@@ -146,7 +146,7 @@ class InputTypeBase(object):
|
||||
|
||||
self.xml = xml
|
||||
self.tag = xml.tag
|
||||
self.system = system
|
||||
self.capa_system = system
|
||||
|
||||
# NOTE: ID should only come from one place. If it comes from multiple,
|
||||
# we use state first, XML second (in case the xml changed, but we have
|
||||
@@ -257,7 +257,7 @@ class InputTypeBase(object):
|
||||
'value': self.value,
|
||||
'status': self.status,
|
||||
'msg': self.msg,
|
||||
'STATIC_URL': self.system.STATIC_URL,
|
||||
'STATIC_URL': self.capa_system.STATIC_URL,
|
||||
}
|
||||
context.update((a, v) for (
|
||||
a, v) in self.loaded_attributes.iteritems() if a in self.to_render)
|
||||
@@ -282,7 +282,7 @@ class InputTypeBase(object):
|
||||
|
||||
context = self._get_render_context()
|
||||
|
||||
html = self.system.render_template(self.template, context)
|
||||
html = self.capa_system.render_template(self.template, context)
|
||||
return etree.XML(html)
|
||||
|
||||
|
||||
@@ -505,9 +505,9 @@ class JSInput(InputTypeBase):
|
||||
def _extra_context(self):
|
||||
context = {
|
||||
'jschannel_loader': '{static_url}js/capa/src/jschannel.js'.format(
|
||||
static_url=self.system.STATIC_URL),
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
'jsinput_loader': '{static_url}js/capa/src/jsinput.js'.format(
|
||||
static_url=self.system.STATIC_URL),
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
'saved_state': self.value
|
||||
}
|
||||
|
||||
@@ -822,18 +822,19 @@ class MatlabInput(CodeInput):
|
||||
- 'message' - message to be rendered in case of error
|
||||
'''
|
||||
# only send data if xqueue exists
|
||||
if self.system.xqueue is None:
|
||||
if self.capa_system.xqueue is None:
|
||||
return {'success': False, 'message': 'Cannot connect to the queue'}
|
||||
|
||||
# pull relevant info out of get
|
||||
response = data['submission']
|
||||
|
||||
# construct xqueue headers
|
||||
qinterface = self.system.xqueue['interface']
|
||||
qinterface = self.capa_system.xqueue['interface']
|
||||
qtime = datetime.utcnow().strftime(xqueue_interface.dateformat)
|
||||
callback_url = self.system.xqueue['construct_callback']('ungraded_response')
|
||||
anonymous_student_id = self.system.anonymous_student_id
|
||||
queuekey = xqueue_interface.make_hashkey(str(self.system.seed) + qtime +
|
||||
callback_url = self.capa_system.xqueue['construct_callback']('ungraded_response')
|
||||
anonymous_student_id = self.capa_system.anonymous_student_id
|
||||
# TODO: Why is this using self.capa_system.seed when we have self.seed???
|
||||
queuekey = xqueue_interface.make_hashkey(str(self.capa_system.seed) + qtime +
|
||||
anonymous_student_id +
|
||||
self.input_id)
|
||||
xheader = xqueue_interface.make_xheader(
|
||||
@@ -1006,7 +1007,7 @@ class ChemicalEquationInput(InputTypeBase):
|
||||
"""
|
||||
return {
|
||||
'previewer': '{static_url}js/capa/chemical_equation_preview.js'.format(
|
||||
static_url=self.system.STATIC_URL),
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
}
|
||||
|
||||
def handle_ajax(self, dispatch, data):
|
||||
@@ -1091,7 +1092,7 @@ class FormulaEquationInput(InputTypeBase):
|
||||
|
||||
return {
|
||||
'previewer': '{static_url}js/capa/src/formula_equation_preview.js'.format(
|
||||
static_url=self.system.STATIC_URL),
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
'reported_status': reported_status,
|
||||
}
|
||||
|
||||
@@ -1274,7 +1275,7 @@ class EditAMoleculeInput(InputTypeBase):
|
||||
"""
|
||||
context = {
|
||||
'applet_loader': '{static_url}js/capa/editamolecule.js'.format(
|
||||
static_url=self.system.STATIC_URL),
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
}
|
||||
|
||||
return context
|
||||
@@ -1310,7 +1311,7 @@ class DesignProtein2dInput(InputTypeBase):
|
||||
"""
|
||||
context = {
|
||||
'applet_loader': '{static_url}js/capa/design-protein-2d.js'.format(
|
||||
static_url=self.system.STATIC_URL),
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
}
|
||||
|
||||
return context
|
||||
@@ -1346,7 +1347,7 @@ class EditAGeneInput(InputTypeBase):
|
||||
"""
|
||||
context = {
|
||||
'applet_loader': '{static_url}js/capa/edit-a-gene.js'.format(
|
||||
static_url=self.system.STATIC_URL),
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
}
|
||||
|
||||
return context
|
||||
|
||||
@@ -129,20 +129,20 @@ class LoncapaResponse(object):
|
||||
allowed_inputfields = []
|
||||
required_attributes = []
|
||||
|
||||
def __init__(self, xml, inputfields, context, system=None):
|
||||
def __init__(self, xml, inputfields, context, system):
|
||||
'''
|
||||
Init is passed the following arguments:
|
||||
|
||||
- xml : ElementTree of this Response
|
||||
- inputfields : ordered list of ElementTrees for each input entry field in this Response
|
||||
- context : script processor context
|
||||
- system : ModuleSystem instance which provides OS, rendering, and user context
|
||||
- system : LoncapaSystem instance which provides OS, rendering, and user context
|
||||
|
||||
'''
|
||||
self.xml = xml
|
||||
self.inputfields = inputfields
|
||||
self.context = context
|
||||
self.system = system
|
||||
self.capa_system = system
|
||||
|
||||
self.id = xml.get('id')
|
||||
|
||||
@@ -298,7 +298,7 @@ class LoncapaResponse(object):
|
||||
python_path=self.context['python_path'],
|
||||
slug=self.id,
|
||||
random_seed=self.context['seed'],
|
||||
unsafely=self.system.can_execute_unsafe_code(),
|
||||
unsafely=self.capa_system.can_execute_unsafe_code(),
|
||||
)
|
||||
except Exception as err:
|
||||
msg = 'Error %s in evaluating hint function %s' % (err, hintfn)
|
||||
@@ -444,7 +444,7 @@ class JavascriptResponse(LoncapaResponse):
|
||||
# manually being compiled to DATA_DIR/js/compiled.
|
||||
|
||||
# latestTimestamp = 0
|
||||
# basepath = self.system.filestore.root_path + '/js/'
|
||||
# basepath = self.capa_system.filestore.root_path + '/js/'
|
||||
# for filename in (self.display_dependencies + [self.display]):
|
||||
# filepath = basepath + filename
|
||||
# timestamp = os.stat(filepath).st_mtime
|
||||
@@ -467,7 +467,7 @@ class JavascriptResponse(LoncapaResponse):
|
||||
# outfile.close()
|
||||
|
||||
# TODO this should also be fixed when the above is fixed.
|
||||
filename = self.system.ajax_url.split('/')[-1] + '.js'
|
||||
filename = self.capa_system.ajax_url.split('/')[-1] + '.js'
|
||||
self.display_filename = 'compiled/' + filename
|
||||
|
||||
def parse_xml(self):
|
||||
@@ -510,16 +510,16 @@ class JavascriptResponse(LoncapaResponse):
|
||||
|
||||
def get_node_env(self):
|
||||
|
||||
js_dir = os.path.join(self.system.filestore.root_path, 'js')
|
||||
js_dir = os.path.join(self.capa_system.filestore.root_path, 'js')
|
||||
tmp_env = os.environ.copy()
|
||||
node_path = self.system.node_path + ":" + os.path.normpath(js_dir)
|
||||
node_path = self.capa_system.node_path + ":" + os.path.normpath(js_dir)
|
||||
tmp_env["NODE_PATH"] = node_path
|
||||
return tmp_env
|
||||
|
||||
def call_node(self, args):
|
||||
# Node.js code is un-sandboxed. If the XModuleSystem says we aren't
|
||||
# Node.js code is un-sandboxed. If the LoncapaSystem says we aren't
|
||||
# allowed to run unsafe code, then stop now.
|
||||
if not self.system.can_execute_unsafe_code():
|
||||
if not self.capa_system.can_execute_unsafe_code():
|
||||
raise LoncapaProblemError("Execution of unsafe Javascript code is not allowed.")
|
||||
|
||||
subprocess_args = ["node"]
|
||||
@@ -1154,7 +1154,7 @@ class CustomResponse(LoncapaResponse):
|
||||
python_path=self.context['python_path'],
|
||||
slug=self.id,
|
||||
random_seed=self.context['seed'],
|
||||
unsafely=self.system.can_execute_unsafe_code(),
|
||||
unsafely=self.capa_system.can_execute_unsafe_code(),
|
||||
)
|
||||
return globals_dict['cfn_return']
|
||||
return check_function
|
||||
@@ -1169,8 +1169,8 @@ class CustomResponse(LoncapaResponse):
|
||||
else:
|
||||
answer_src = answer.get('src')
|
||||
if answer_src is not None:
|
||||
self.code = self.system.filesystem.open(
|
||||
'src/' + answer_src).read()
|
||||
# TODO: this code seems not to be used any more since self.capa_system.filesystem doesn't exist.
|
||||
self.code = self.capa_system.filesystem.open('src/' + answer_src).read()
|
||||
else:
|
||||
self.code = answer.text
|
||||
|
||||
@@ -1249,8 +1249,8 @@ class CustomResponse(LoncapaResponse):
|
||||
'testdat': 'hello world',
|
||||
})
|
||||
|
||||
# pass self.system.debug to cfn
|
||||
self.context['debug'] = self.system.DEBUG
|
||||
# Pass DEBUG to the check function.
|
||||
self.context['debug'] = self.capa_system.DEBUG
|
||||
|
||||
# Run the check function
|
||||
self.execute_check_function(idset, submission)
|
||||
@@ -1275,10 +1275,10 @@ class CustomResponse(LoncapaResponse):
|
||||
safe_exec.safe_exec(
|
||||
self.code,
|
||||
self.context,
|
||||
cache=self.system.cache,
|
||||
cache=self.capa_system.cache,
|
||||
slug=self.id,
|
||||
random_seed=self.context['seed'],
|
||||
unsafely=self.system.can_execute_unsafe_code(),
|
||||
unsafely=self.capa_system.can_execute_unsafe_code(),
|
||||
)
|
||||
except Exception as err:
|
||||
self._handle_exec_exception(err)
|
||||
@@ -1470,18 +1470,21 @@ ScoreMessage = namedtuple('ScoreMessage', ['valid', 'correct', 'points', 'msg'])
|
||||
@registry.register
|
||||
class CodeResponse(LoncapaResponse):
|
||||
"""
|
||||
Grade student code using an external queueing server, called 'xqueue'
|
||||
Grade student code using an external queueing server, called 'xqueue'.
|
||||
|
||||
Expects 'xqueue' dict in ModuleSystem with the following keys that are needed by CodeResponse:
|
||||
system.xqueue = { 'interface': XqueueInterface object,
|
||||
'construct_callback': Per-StudentModule callback URL
|
||||
constructor, defaults to using 'score_update'
|
||||
as the correct dispatch (function),
|
||||
'default_queuename': Default queuename to submit request (string)
|
||||
}
|
||||
Expects 'xqueue' dict in LoncapaSystem with the following keys that are
|
||||
needed by CodeResponse::
|
||||
|
||||
capa_system.xqueue = {
|
||||
'interface': XQueueInterface object.
|
||||
'construct_callback': Per-StudentModule callback URL constructor,
|
||||
defaults to using 'score_update' as the correct dispatch (function).
|
||||
'default_queuename': Default queue name to submit request (string).
|
||||
}
|
||||
|
||||
External requests are only submitted for student submission grading, not
|
||||
for getting reference answers.
|
||||
|
||||
External requests are only submitted for student submission grading
|
||||
(i.e. and not for getting reference answers)
|
||||
"""
|
||||
|
||||
tags = ['coderesponse']
|
||||
@@ -1504,8 +1507,8 @@ class CodeResponse(LoncapaResponse):
|
||||
self.url = xml.get('url', None)
|
||||
|
||||
# We do not support xqueue within Studio.
|
||||
if self.system.xqueue is not None:
|
||||
default_queuename = self.system.xqueue['default_queuename']
|
||||
if self.capa_system.xqueue is not None:
|
||||
default_queuename = self.capa_system.xqueue['default_queuename']
|
||||
else:
|
||||
default_queuename = None
|
||||
self.queue_name = xml.get('queuename', default_queuename)
|
||||
@@ -1548,7 +1551,7 @@ class CodeResponse(LoncapaResponse):
|
||||
raise Exception(err)
|
||||
|
||||
# We do not support xqueue within Studio.
|
||||
if self.system.xqueue is None:
|
||||
if self.capa_system.xqueue is None:
|
||||
cmap = CorrectMap()
|
||||
cmap.set(self.answer_id, queuestate=None,
|
||||
msg='Error checking problem: no external queueing server is configured.')
|
||||
@@ -1557,16 +1560,16 @@ class CodeResponse(LoncapaResponse):
|
||||
# Prepare xqueue request
|
||||
#------------------------------------------------------------
|
||||
|
||||
qinterface = self.system.xqueue['interface']
|
||||
qinterface = self.capa_system.xqueue['interface']
|
||||
qtime = datetime.strftime(datetime.now(UTC), xqueue_interface.dateformat)
|
||||
|
||||
anonymous_student_id = self.system.anonymous_student_id
|
||||
anonymous_student_id = self.capa_system.anonymous_student_id
|
||||
|
||||
# Generate header
|
||||
queuekey = xqueue_interface.make_hashkey(
|
||||
str(self.system.seed) + qtime + anonymous_student_id + self.answer_id
|
||||
str(self.capa_system.seed) + qtime + anonymous_student_id + self.answer_id
|
||||
)
|
||||
callback_url = self.system.xqueue['construct_callback']()
|
||||
callback_url = self.capa_system.xqueue['construct_callback']()
|
||||
xheader = xqueue_interface.make_xheader(
|
||||
lms_callback_url=callback_url,
|
||||
lms_key=queuekey,
|
||||
@@ -1748,8 +1751,8 @@ class ExternalResponse(LoncapaResponse):
|
||||
if answer is not None:
|
||||
answer_src = answer.get('src')
|
||||
if answer_src is not None:
|
||||
self.code = self.system.filesystem.open(
|
||||
'src/' + answer_src).read()
|
||||
# TODO: this code seems not to be used any more since self.capa_system.filesystem doesn't exist.
|
||||
self.code = self.capa_system.filesystem.open('src/' + answer_src).read()
|
||||
else:
|
||||
self.code = answer.text
|
||||
else:
|
||||
@@ -1791,7 +1794,7 @@ class ExternalResponse(LoncapaResponse):
|
||||
log.error(msg)
|
||||
raise Exception(msg)
|
||||
|
||||
if self.system.DEBUG:
|
||||
if self.capa_system.DEBUG:
|
||||
log.info('response = %s', req.text)
|
||||
|
||||
if (not req.text) or (not req.text.strip()):
|
||||
@@ -1830,7 +1833,7 @@ class ExternalResponse(LoncapaResponse):
|
||||
rxml = self.do_external_request('get_score', extra_payload)
|
||||
except Exception as err: # pylint: disable=W0703
|
||||
log.error('Error %s', err)
|
||||
if self.system.DEBUG:
|
||||
if self.capa_system.DEBUG:
|
||||
cmap.set_dict(dict(zip(sorted(
|
||||
self.answer_ids), ['incorrect'] * len(idset))))
|
||||
cmap.set_property(
|
||||
@@ -1862,7 +1865,7 @@ class ExternalResponse(LoncapaResponse):
|
||||
exans = json.loads(rxml.find('expected').text)
|
||||
except Exception as err: # pylint: disable=W0703
|
||||
log.error('Error %s', err)
|
||||
if self.system.DEBUG:
|
||||
if self.capa_system.DEBUG:
|
||||
msg = '<span class="inline-error">%s</span>' % str(
|
||||
err).replace('<', '<')
|
||||
exans = [''] * len(self.answer_ids)
|
||||
@@ -2100,7 +2103,7 @@ class SchematicResponse(LoncapaResponse):
|
||||
answer_src = answer.get('src')
|
||||
if answer_src is not None:
|
||||
# Untested; never used
|
||||
self.code = self.system.filestore.open('src/' + answer_src).read()
|
||||
self.code = self.capa_system.filestore.open('src/' + answer_src).read()
|
||||
else:
|
||||
self.code = answer.text
|
||||
|
||||
@@ -2114,10 +2117,10 @@ class SchematicResponse(LoncapaResponse):
|
||||
safe_exec.safe_exec(
|
||||
self.code,
|
||||
self.context,
|
||||
cache=self.system.cache,
|
||||
cache=self.capa_system.cache,
|
||||
slug=self.id,
|
||||
random_seed=self.context['seed'],
|
||||
unsafely=self.system.can_execute_unsafe_code(),
|
||||
unsafely=self.capa_system.can_execute_unsafe_code(),
|
||||
)
|
||||
except Exception as err:
|
||||
msg = 'Error %s in evaluating SchematicResponse' % err
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import fs.osfs
|
||||
"""Tools for helping with testing capa."""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
from capa.capa_problem import LoncapaProblem
|
||||
from xmodule.x_module import ModuleSystem
|
||||
import fs.osfs
|
||||
|
||||
from capa.capa_problem import LoncapaProblem, LoncapaSystem
|
||||
from mock import Mock, MagicMock
|
||||
|
||||
import xml.sax.saxutils as saxutils
|
||||
@@ -26,34 +28,28 @@ xqueue_interface = MagicMock()
|
||||
xqueue_interface.send_to_queue.return_value = (0, 'Success!')
|
||||
|
||||
|
||||
def test_system():
|
||||
def test_capa_system():
|
||||
"""
|
||||
Construct a mock ModuleSystem instance.
|
||||
Construct a mock LoncapaSystem instance.
|
||||
|
||||
"""
|
||||
the_system = Mock(
|
||||
spec=ModuleSystem,
|
||||
spec=LoncapaSystem,
|
||||
ajax_url='/dummy-ajax-url',
|
||||
STATIC_URL='/dummy-static/',
|
||||
DEBUG=True,
|
||||
track_function=Mock(),
|
||||
get_module=Mock(),
|
||||
render_template=tst_render_template,
|
||||
replace_urls=Mock(),
|
||||
user=Mock(),
|
||||
seed=0,
|
||||
filestore=fs.osfs.OSFS(os.path.join(TEST_DIR, "test_files")),
|
||||
debug=True,
|
||||
hostname="edx.org",
|
||||
xqueue={'interface': xqueue_interface, 'construct_callback': calledback_url, 'default_queuename': 'testqueue', 'waittime': 10},
|
||||
node_path=os.environ.get("NODE_PATH", "/usr/local/lib/node_modules"),
|
||||
anonymous_student_id='student',
|
||||
cache=None,
|
||||
can_execute_unsafe_code=lambda: False,
|
||||
DEBUG=True,
|
||||
filestore=fs.osfs.OSFS(os.path.join(TEST_DIR, "test_files")),
|
||||
node_path=os.environ.get("NODE_PATH", "/usr/local/lib/node_modules"),
|
||||
render_template=tst_render_template,
|
||||
seed=0,
|
||||
STATIC_URL='/dummy-static/',
|
||||
xqueue={'interface': xqueue_interface, 'construct_callback': calledback_url, 'default_queuename': 'testqueue', 'waittime': 10},
|
||||
)
|
||||
return the_system
|
||||
|
||||
|
||||
def new_loncapa_problem(xml, system=None):
|
||||
def new_loncapa_problem(xml, capa_system=None):
|
||||
"""Construct a `LoncapaProblem` suitable for unit tests."""
|
||||
return LoncapaProblem(xml, id='1', seed=723, system=system or test_system())
|
||||
return LoncapaProblem(xml, id='1', seed=723, capa_system=capa_system or test_capa_system())
|
||||
|
||||
@@ -2,7 +2,7 @@ from lxml import etree
|
||||
import unittest
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
from . import test_system
|
||||
from . import test_capa_system
|
||||
from capa import customrender
|
||||
|
||||
# just a handy shortcut
|
||||
@@ -11,7 +11,7 @@ lookup_tag = customrender.registry.get_class_for_tag
|
||||
|
||||
def extract_context(xml):
|
||||
"""
|
||||
Given an xml element corresponding to the output of test_system.render_template, get back the
|
||||
Given an xml element corresponding to the output of test_capa_system.render_template, get back the
|
||||
original context
|
||||
"""
|
||||
return eval(xml.text)
|
||||
@@ -26,7 +26,7 @@ class HelperTest(unittest.TestCase):
|
||||
Make sure that our helper function works!
|
||||
'''
|
||||
def check(self, d):
|
||||
xml = etree.XML(test_system().render_template('blah', d))
|
||||
xml = etree.XML(test_capa_system().render_template('blah', d))
|
||||
self.assertEqual(d, extract_context(xml))
|
||||
|
||||
def test_extract_context(self):
|
||||
@@ -46,11 +46,11 @@ class SolutionRenderTest(unittest.TestCase):
|
||||
xml_str = """<solution id="solution_12">{s}</solution>""".format(s=solution)
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
renderer = lookup_tag('solution')(test_system(), element)
|
||||
renderer = lookup_tag('solution')(test_capa_system(), element)
|
||||
|
||||
self.assertEqual(renderer.id, 'solution_12')
|
||||
|
||||
# Our test_system "renders" templates to a div with the repr of the context.
|
||||
# Our test_capa_system "renders" templates to a div with the repr of the context.
|
||||
xml = renderer.get_html()
|
||||
context = extract_context(xml)
|
||||
self.assertEqual(context, {'id': 'solution_12'})
|
||||
@@ -65,7 +65,7 @@ class MathRenderTest(unittest.TestCase):
|
||||
xml_str = """<math>{tex}</math>""".format(tex=latex_in)
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
renderer = lookup_tag('math')(test_system(), element)
|
||||
renderer = lookup_tag('math')(test_capa_system(), element)
|
||||
|
||||
self.assertEqual(renderer.mathstr, mathjax_out)
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ import textwrap
|
||||
import mock
|
||||
|
||||
from .response_xml_factory import StringResponseXMLFactory, CustomResponseXMLFactory
|
||||
from . import test_system, new_loncapa_problem
|
||||
from . import test_capa_system, new_loncapa_problem
|
||||
|
||||
|
||||
class CapaHtmlRenderTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CapaHtmlRenderTest, self).setUp()
|
||||
self.system = test_system()
|
||||
self.capa_system = test_capa_system()
|
||||
|
||||
def test_blank_problem(self):
|
||||
"""
|
||||
@@ -44,7 +44,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
""")
|
||||
|
||||
# Create the problem
|
||||
problem = new_loncapa_problem(xml_str, system=self.system)
|
||||
problem = new_loncapa_problem(xml_str, capa_system=self.capa_system)
|
||||
|
||||
# Render the HTML
|
||||
rendered_html = etree.XML(problem.get_html())
|
||||
@@ -119,12 +119,12 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
xml_str = StringResponseXMLFactory().build_xml(**kwargs)
|
||||
|
||||
# Mock out the template renderer
|
||||
the_system = test_system()
|
||||
the_system = test_capa_system()
|
||||
the_system.render_template = mock.Mock()
|
||||
the_system.render_template.return_value = "<div>Input Template Render</div>"
|
||||
|
||||
# Create the problem and render the HTML
|
||||
problem = new_loncapa_problem(xml_str, system=the_system)
|
||||
problem = new_loncapa_problem(xml_str, capa_system=the_system)
|
||||
rendered_html = etree.XML(problem.get_html())
|
||||
|
||||
# Expect problem has been turned into a <div>
|
||||
@@ -253,7 +253,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
self.assertRegexpMatches(the_html, r"<div>\s+</div>")
|
||||
|
||||
def _create_test_file(self, path, content_str):
|
||||
test_fp = self.system.filestore.open(path, "w")
|
||||
test_fp = self.capa_system.filestore.open(path, "w")
|
||||
test_fp.write(content_str)
|
||||
test_fp.close()
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ from lxml import etree
|
||||
import unittest
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
from . import test_system
|
||||
from . import test_capa_system
|
||||
from capa import inputtypes
|
||||
from mock import ANY, patch
|
||||
from pyparsing import ParseException
|
||||
@@ -47,7 +47,7 @@ class OptionInputTest(unittest.TestCase):
|
||||
state = {'value': 'Down',
|
||||
'id': 'sky_input',
|
||||
'status': 'answered'}
|
||||
option_input = lookup_tag('optioninput')(test_system(), element, state)
|
||||
option_input = lookup_tag('optioninput')(test_capa_system(), element, state)
|
||||
|
||||
context = option_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -106,7 +106,7 @@ class ChoiceGroupTest(unittest.TestCase):
|
||||
'id': 'sky_input',
|
||||
'status': 'answered'}
|
||||
|
||||
the_input = lookup_tag(tag)(test_system(), element, state)
|
||||
the_input = lookup_tag(tag)(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -159,7 +159,7 @@ class JavascriptInputTest(unittest.TestCase):
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
state = {'value': '3', }
|
||||
the_input = lookup_tag('javascriptinput')(test_system(), element, state)
|
||||
the_input = lookup_tag('javascriptinput')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -190,7 +190,7 @@ class TextLineTest(unittest.TestCase):
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
state = {'value': 'BumbleBee', }
|
||||
the_input = lookup_tag('textline')(test_system(), element, state)
|
||||
the_input = lookup_tag('textline')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -221,7 +221,7 @@ class TextLineTest(unittest.TestCase):
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
state = {'value': 'BumbleBee', }
|
||||
the_input = lookup_tag('textline')(test_system(), element, state)
|
||||
the_input = lookup_tag('textline')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -264,7 +264,7 @@ class TextLineTest(unittest.TestCase):
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
state = {'value': 'BumbleBee', }
|
||||
the_input = lookup_tag('textline')(test_system(), element, state)
|
||||
the_input = lookup_tag('textline')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -305,7 +305,7 @@ class FileSubmissionTest(unittest.TestCase):
|
||||
'status': 'incomplete',
|
||||
'feedback': {'message': '3'}, }
|
||||
input_class = lookup_tag('filesubmission')
|
||||
the_input = input_class(test_system(), element, state)
|
||||
the_input = input_class(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -353,7 +353,7 @@ class CodeInputTest(unittest.TestCase):
|
||||
'feedback': {'message': '3'}, }
|
||||
|
||||
input_class = lookup_tag('codeinput')
|
||||
the_input = input_class(test_system(), element, state)
|
||||
the_input = input_class(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -405,7 +405,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'feedback': {'message': '3'}, }
|
||||
|
||||
self.input_class = lookup_tag('matlabinput')
|
||||
self.the_input = self.input_class(test_system(), elt, state)
|
||||
self.the_input = self.input_class(test_capa_system(), elt, state)
|
||||
|
||||
def test_rendering(self):
|
||||
context = self.the_input._get_render_context() # pylint: disable=W0212
|
||||
@@ -436,7 +436,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'feedback': {'message': '3'}, }
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_system(), elt, state)
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
expected = {
|
||||
@@ -466,7 +466,7 @@ class MatlabTest(unittest.TestCase):
|
||||
}
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_system(), elt, state)
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
expected = {
|
||||
'STATIC_URL': '/dummy-static/',
|
||||
@@ -494,7 +494,7 @@ class MatlabTest(unittest.TestCase):
|
||||
}
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_system(), elt, state)
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
expected = {
|
||||
'STATIC_URL': '/dummy-static/',
|
||||
@@ -519,7 +519,7 @@ class MatlabTest(unittest.TestCase):
|
||||
data = {'submission': 'x = 1234;'}
|
||||
response = self.the_input.handle_ajax("plot", data)
|
||||
|
||||
test_system().xqueue['interface'].send_to_queue.assert_called_with(header=ANY, body=ANY)
|
||||
test_capa_system().xqueue['interface'].send_to_queue.assert_called_with(header=ANY, body=ANY)
|
||||
|
||||
self.assertTrue(response['success'])
|
||||
self.assertTrue(self.the_input.input_state['queuekey'] is not None)
|
||||
@@ -528,7 +528,7 @@ class MatlabTest(unittest.TestCase):
|
||||
def test_plot_data_failure(self):
|
||||
data = {'submission': 'x = 1234;'}
|
||||
error_message = 'Error message!'
|
||||
test_system().xqueue['interface'].send_to_queue.return_value = (1, error_message)
|
||||
test_capa_system().xqueue['interface'].send_to_queue.return_value = (1, error_message)
|
||||
response = self.the_input.handle_ajax("plot", data)
|
||||
self.assertFalse(response['success'])
|
||||
self.assertEqual(response['message'], error_message)
|
||||
@@ -544,7 +544,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'feedback': {'message': '3'}, }
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_system(), elt, state)
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
inner_msg = 'hello!'
|
||||
queue_msg = json.dumps({'msg': inner_msg})
|
||||
|
||||
@@ -562,7 +562,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'feedback': {'message': '3'}, }
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_system(), elt, state)
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
inner_msg = 'hello!'
|
||||
queue_msg = json.dumps({'msg': inner_msg})
|
||||
|
||||
@@ -601,7 +601,7 @@ class SchematicTest(unittest.TestCase):
|
||||
state = {'value': value,
|
||||
'status': 'unsubmitted'}
|
||||
|
||||
the_input = lookup_tag('schematic')(test_system(), element, state)
|
||||
the_input = lookup_tag('schematic')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -643,7 +643,7 @@ class ImageInputTest(unittest.TestCase):
|
||||
state = {'value': value,
|
||||
'status': 'unsubmitted'}
|
||||
|
||||
the_input = lookup_tag('imageinput')(test_system(), element, state)
|
||||
the_input = lookup_tag('imageinput')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -697,7 +697,7 @@ class CrystallographyTest(unittest.TestCase):
|
||||
state = {'value': value,
|
||||
'status': 'unsubmitted'}
|
||||
|
||||
the_input = lookup_tag('crystallography')(test_system(), element, state)
|
||||
the_input = lookup_tag('crystallography')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -738,7 +738,7 @@ class VseprTest(unittest.TestCase):
|
||||
state = {'value': value,
|
||||
'status': 'unsubmitted'}
|
||||
|
||||
the_input = lookup_tag('vsepr_input')(test_system(), element, state)
|
||||
the_input = lookup_tag('vsepr_input')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -768,7 +768,7 @@ class ChemicalEquationTest(unittest.TestCase):
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
state = {'value': 'H2OYeah', }
|
||||
self.the_input = lookup_tag('chemicalequationinput')(test_system(), element, state)
|
||||
self.the_input = lookup_tag('chemicalequationinput')(test_capa_system(), element, state)
|
||||
|
||||
def test_rendering(self):
|
||||
''' Verify that the render context matches the expected render context'''
|
||||
@@ -853,7 +853,7 @@ class FormulaEquationTest(unittest.TestCase):
|
||||
element = etree.fromstring(xml_str)
|
||||
|
||||
state = {'value': 'x^2+1/2'}
|
||||
self.the_input = lookup_tag('formulaequationinput')(test_system(), element, state)
|
||||
self.the_input = lookup_tag('formulaequationinput')(test_capa_system(), element, state)
|
||||
|
||||
def test_rendering(self):
|
||||
"""
|
||||
@@ -1005,7 +1005,7 @@ class DragAndDropTest(unittest.TestCase):
|
||||
]
|
||||
}
|
||||
|
||||
the_input = lookup_tag('drag_and_drop_input')(test_system(), element, state)
|
||||
the_input = lookup_tag('drag_and_drop_input')(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
expected = {
|
||||
@@ -1056,7 +1056,7 @@ class AnnotationInputTest(unittest.TestCase):
|
||||
|
||||
tag = 'annotationinput'
|
||||
|
||||
the_input = lookup_tag(tag)(test_system(), element, state)
|
||||
the_input = lookup_tag(tag)(test_capa_system(), element, state)
|
||||
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
|
||||
@@ -1146,7 +1146,7 @@ class TestChoiceText(unittest.TestCase):
|
||||
'submitted_message': 'Answer received.'
|
||||
}
|
||||
expected.update(state)
|
||||
the_input = lookup_tag(tag)(test_system(), element, state)
|
||||
the_input = lookup_tag(tag)(test_capa_system(), element, state)
|
||||
context = the_input._get_render_context() # pylint: disable=W0212
|
||||
self.assertEqual(context, expected)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import textwrap
|
||||
import requests
|
||||
import mock
|
||||
|
||||
from . import new_loncapa_problem, test_system
|
||||
from . import new_loncapa_problem, test_capa_system
|
||||
import calc
|
||||
|
||||
from capa.responsetypes import LoncapaProblemError, \
|
||||
@@ -37,9 +37,9 @@ class ResponseTest(unittest.TestCase):
|
||||
if self.xml_factory_class:
|
||||
self.xml_factory = self.xml_factory_class()
|
||||
|
||||
def build_problem(self, system=None, **kwargs):
|
||||
def build_problem(self, capa_system=None, **kwargs):
|
||||
xml = self.xml_factory.build_xml(**kwargs)
|
||||
return new_loncapa_problem(xml, system=system)
|
||||
return new_loncapa_problem(xml, capa_system=capa_system)
|
||||
|
||||
def assert_grade(self, problem, submission, expected_correctness, msg=None):
|
||||
input_dict = {'1_2_1': submission}
|
||||
@@ -1022,10 +1022,10 @@ class JavascriptResponseTest(ResponseTest):
|
||||
coffee_file_path = os.path.dirname(__file__) + "/test_files/js/*.coffee"
|
||||
os.system("node_modules/.bin/coffee -c %s" % (coffee_file_path))
|
||||
|
||||
system = test_system()
|
||||
system.can_execute_unsafe_code = lambda: True
|
||||
capa_system = test_capa_system()
|
||||
capa_system.can_execute_unsafe_code = lambda: True
|
||||
problem = self.build_problem(
|
||||
system=system,
|
||||
capa_system=capa_system,
|
||||
generator_src="test_problem_generator.js",
|
||||
grader_src="test_problem_grader.js",
|
||||
display_class="TestProblemDisplay",
|
||||
@@ -1040,12 +1040,12 @@ class JavascriptResponseTest(ResponseTest):
|
||||
def test_cant_execute_javascript(self):
|
||||
# If the system says to disallow unsafe code execution, then making
|
||||
# this problem will raise an exception.
|
||||
system = test_system()
|
||||
system.can_execute_unsafe_code = lambda: False
|
||||
capa_system = test_capa_system()
|
||||
capa_system.can_execute_unsafe_code = lambda: False
|
||||
|
||||
with self.assertRaises(LoncapaProblemError):
|
||||
self.build_problem(
|
||||
system=system,
|
||||
capa_system=capa_system,
|
||||
generator_src="test_problem_generator.js",
|
||||
grader_src="test_problem_grader.js",
|
||||
display_class="TestProblemDisplay",
|
||||
|
||||
@@ -11,7 +11,7 @@ import sys
|
||||
|
||||
from pkg_resources import resource_string
|
||||
|
||||
from capa.capa_problem import LoncapaProblem
|
||||
from capa.capa_problem import LoncapaProblem, LoncapaSystem
|
||||
from capa.responsetypes import StudentInputError, \
|
||||
ResponseError, LoncapaProblemError
|
||||
from capa.util import convert_files_to_filenames
|
||||
@@ -260,12 +260,26 @@ class CapaMixin(CapaFields):
|
||||
if text is None:
|
||||
text = self.data
|
||||
|
||||
capa_system = LoncapaSystem(
|
||||
ajax_url=self.system.ajax_url,
|
||||
anonymous_student_id=self.system.anonymous_student_id,
|
||||
cache=self.system.cache,
|
||||
can_execute_unsafe_code=self.system.can_execute_unsafe_code,
|
||||
DEBUG=self.system.DEBUG,
|
||||
filestore=self.system.filestore,
|
||||
node_path=self.system.node_path,
|
||||
render_template=self.system.render_template,
|
||||
seed=self.system.seed, # Why do we do this if we have self.seed?
|
||||
STATIC_URL=self.system.STATIC_URL,
|
||||
xqueue=self.system.xqueue,
|
||||
)
|
||||
|
||||
return LoncapaProblem(
|
||||
problem_text=text,
|
||||
id=self.location.html_id(),
|
||||
state=state,
|
||||
seed=self.seed,
|
||||
system=self.runtime,
|
||||
capa_system=capa_system,
|
||||
)
|
||||
|
||||
def get_state_for_lcp(self):
|
||||
|
||||
Reference in New Issue
Block a user