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
9dbd4c5b
Commit
9dbd4c5b
authored
Jan 16, 2014
by
Ned Batchelder
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2197 from edx/ned/add-responsetypes-registry
Make a ResponseType registry.
parents
a505fa95
3942876e
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
66 additions
and
70 deletions
+66
-70
common/lib/capa/capa/capa_problem.py
+4
-8
common/lib/capa/capa/inputtypes.py
+21
-44
common/lib/capa/capa/registry.py
+5
-0
common/lib/capa/capa/responsetypes.py
+36
-18
No files found.
common/lib/capa/capa/capa_problem.py
View file @
9dbd4c5b
...
...
@@ -25,18 +25,14 @@ from copy import deepcopy
from
capa.correctmap
import
CorrectMap
import
capa.inputtypes
as
inputtypes
import
capa.customrender
as
customrender
import
capa.responsetypes
as
responsetypes
from
capa.util
import
contextualize_text
,
convert_files_to_filenames
import
capa.xqueue_interface
as
xqueue_interface
# to be replaced with auto-registering
import
capa.responsetypes
as
responsetypes
from
capa.safe_exec
import
safe_exec
from
pytz
import
UTC
# dict of tagname, Response Class -- this should come from auto-registering
response_tag_dict
=
dict
([(
x
.
response_tag
,
x
)
for
x
in
responsetypes
.
__all__
])
# extra things displayed after "show answers" is pressed
solution_tags
=
[
'solution'
]
...
...
@@ -652,7 +648,7 @@ class LoncapaProblem(object):
'''
response_id
=
1
self
.
responders
=
{}
for
response
in
tree
.
xpath
(
'//'
+
"|//"
.
join
(
response
_tag_dict
)):
for
response
in
tree
.
xpath
(
'//'
+
"|//"
.
join
(
response
types
.
registry
.
registered_tags
()
)):
response_id_str
=
self
.
problem_id
+
"_"
+
str
(
response_id
)
# create and save ID for this response
response
.
set
(
'id'
,
response_id_str
)
...
...
@@ -673,8 +669,8 @@ class LoncapaProblem(object):
answer_id
=
answer_id
+
1
# instantiate capa Response
respon
der
=
response_tag_dict
[
response
.
tag
](
response
,
inputfields
,
self
.
context
,
self
.
system
)
respon
setype_cls
=
responsetypes
.
registry
.
get_class_for_tag
(
response
.
tag
)
responder
=
responsetype_cls
(
response
,
inputfields
,
self
.
context
,
self
.
system
)
# save in list in self
self
.
responders
[
response
]
=
responder
...
...
common/lib/capa/capa/inputtypes.py
View file @
9dbd4c5b
...
...
@@ -289,6 +289,7 @@ class InputTypeBase(object):
#-----------------------------------------------------------------------------
@registry.register
class
OptionInput
(
InputTypeBase
):
"""
Input type for selecting and Select option input type.
...
...
@@ -333,14 +334,13 @@ class OptionInput(InputTypeBase):
return
[
Attribute
(
'options'
,
transform
=
cls
.
parse_options
),
Attribute
(
'inline'
,
False
)]
registry
.
register
(
OptionInput
)
#-----------------------------------------------------------------------------
# TODO: consolidate choicegroup, radiogroup, checkboxgroup after discussion of
# desired semantics.
@registry.register
class
ChoiceGroup
(
InputTypeBase
):
"""
Radio button or checkbox inputs: multiple choice or true/false
...
...
@@ -415,12 +415,10 @@ class ChoiceGroup(InputTypeBase):
return
choices
registry
.
register
(
ChoiceGroup
)
#-----------------------------------------------------------------------------
@registry.register
class
JavascriptInput
(
InputTypeBase
):
"""
Hidden field for javascript to communicate via; also loads the required
...
...
@@ -451,13 +449,11 @@ class JavascriptInput(InputTypeBase):
if
self
.
value
==
""
:
self
.
value
=
'null'
registry
.
register
(
JavascriptInput
)
#-----------------------------------------------------------------------------
@registry.register
class
JSInput
(
InputTypeBase
):
"""
Inputtype for general javascript inputs. Intended to be used with
...
...
@@ -480,7 +476,7 @@ class JSInput(InputTypeBase):
height="500"
width="400"/>
See the documentation in docs/data/source/course_data_formats/jsinput.rst
See the documentation in docs/data/source/course_data_formats/jsinput.rst
for more information.
"""
...
...
@@ -517,11 +513,10 @@ class JSInput(InputTypeBase):
return
context
registry
.
register
(
JSInput
)
#-----------------------------------------------------------------------------
@registry.register
class
TextLine
(
InputTypeBase
):
"""
A text line input. Can do math preview if "math"="1" is specified.
...
...
@@ -587,11 +582,10 @@ class TextLine(InputTypeBase):
return
{
'do_math'
:
self
.
do_math
,
'preprocessor'
:
self
.
preprocessor
,
}
registry
.
register
(
TextLine
)
#-----------------------------------------------------------------------------
@registry.register
class
FileSubmission
(
InputTypeBase
):
"""
Upload some files (e.g. for programming assignments)
...
...
@@ -636,11 +630,10 @@ class FileSubmission(InputTypeBase):
def
_extra_context
(
self
):
return
{
'queue_len'
:
self
.
queue_len
,
}
registry
.
register
(
FileSubmission
)
#-----------------------------------------------------------------------------
@registry.register
class
CodeInput
(
InputTypeBase
):
"""
A text area input for code--uses codemirror, does syntax highlighting, special tab handling,
...
...
@@ -700,12 +693,11 @@ class CodeInput(InputTypeBase):
"""Defined queue_len, add it """
return
{
'queue_len'
:
self
.
queue_len
,
}
registry
.
register
(
CodeInput
)
#-----------------------------------------------------------------------------
@registry.register
class
MatlabInput
(
CodeInput
):
'''
InputType for handling Matlab code input
...
...
@@ -866,11 +858,9 @@ class MatlabInput(CodeInput):
return
{
'success'
:
error
==
0
,
'message'
:
msg
}
registry
.
register
(
MatlabInput
)
#-----------------------------------------------------------------------------
@registry.register
class
Schematic
(
InputTypeBase
):
"""
InputType for the schematic editor
...
...
@@ -893,11 +883,10 @@ class Schematic(InputTypeBase):
Attribute
(
'submit_analyses'
,
None
),
]
registry
.
register
(
Schematic
)
#-----------------------------------------------------------------------------
@registry.register
class
ImageInput
(
InputTypeBase
):
"""
Clickable image as an input field. Element should specify the image source, height,
...
...
@@ -939,11 +928,10 @@ class ImageInput(InputTypeBase):
return
{
'gx'
:
self
.
gx
,
'gy'
:
self
.
gy
}
registry
.
register
(
ImageInput
)
#-----------------------------------------------------------------------------
@registry.register
class
Crystallography
(
InputTypeBase
):
"""
An input for crystallography -- user selects 3 points on the axes, and we get a plane.
...
...
@@ -963,11 +951,10 @@ class Crystallography(InputTypeBase):
Attribute
(
'width'
),
]
registry
.
register
(
Crystallography
)
# -------------------------------------------------------------------------
@registry.register
class
VseprInput
(
InputTypeBase
):
"""
Input for molecular geometry--show possible structures, let student
...
...
@@ -988,11 +975,10 @@ class VseprInput(InputTypeBase):
Attribute
(
'geometries'
),
]
registry
.
register
(
VseprInput
)
#-------------------------------------------------------------------------
@registry.register
class
ChemicalEquationInput
(
InputTypeBase
):
"""
An input type for entering chemical equations. Supports live preview.
...
...
@@ -1064,11 +1050,10 @@ class ChemicalEquationInput(InputTypeBase):
return
result
registry
.
register
(
ChemicalEquationInput
)
#-------------------------------------------------------------------------
@registry.register
class
FormulaEquationInput
(
InputTypeBase
):
"""
An input type for entering formula equations. Supports live preview.
...
...
@@ -1160,11 +1145,10 @@ class FormulaEquationInput(InputTypeBase):
return
result
registry
.
register
(
FormulaEquationInput
)
#-----------------------------------------------------------------------------
@registry.register
class
DragAndDropInput
(
InputTypeBase
):
"""
Input for drag and drop problems. Allows student to drag and drop images and
...
...
@@ -1259,11 +1243,10 @@ class DragAndDropInput(InputTypeBase):
self
.
loaded_attributes
[
'drag_and_drop_json'
]
=
json
.
dumps
(
to_js
)
self
.
to_render
.
add
(
'drag_and_drop_json'
)
registry
.
register
(
DragAndDropInput
)
#-------------------------------------------------------------------------
@registry.register
class
EditAMoleculeInput
(
InputTypeBase
):
"""
An input type for edit-a-molecule. Integrates with the molecule editor java applet.
...
...
@@ -1296,11 +1279,10 @@ class EditAMoleculeInput(InputTypeBase):
return
context
registry
.
register
(
EditAMoleculeInput
)
#-----------------------------------------------------------------------------
@registry.register
class
DesignProtein2dInput
(
InputTypeBase
):
"""
An input type for design of a protein in 2D. Integrates with the Protex java applet.
...
...
@@ -1333,11 +1315,10 @@ class DesignProtein2dInput(InputTypeBase):
return
context
registry
.
register
(
DesignProtein2dInput
)
#-----------------------------------------------------------------------------
@registry.register
class
EditAGeneInput
(
InputTypeBase
):
"""
An input type for editing a gene.
...
...
@@ -1370,11 +1351,10 @@ class EditAGeneInput(InputTypeBase):
return
context
registry
.
register
(
EditAGeneInput
)
#---------------------------------------------------------------------
@registry.register
class
AnnotationInput
(
InputTypeBase
):
"""
Input type for annotations: students can enter some notes or other text
...
...
@@ -1481,9 +1461,8 @@ class AnnotationInput(InputTypeBase):
return
extra_context
registry
.
register
(
AnnotationInput
)
@registry.register
class
ChoiceTextGroup
(
InputTypeBase
):
"""
Groups of radiobutton/checkboxes with text inputs.
...
...
@@ -1686,5 +1665,3 @@ class ChoiceTextGroup(InputTypeBase):
# Add the tuple for the current choice to the list of choices
choices
.
append
((
choice
.
get
(
"name"
),
components
))
return
choices
registry
.
register
(
ChoiceTextGroup
)
common/lib/capa/capa/registry.py
View file @
9dbd4c5b
"""A registry for finding classes based on tags in the class."""
class
TagRegistry
(
object
):
"""
A registry mapping tags to handlers.
...
...
@@ -35,6 +37,9 @@ class TagRegistry(object):
for
t
in
cls
.
tags
:
self
.
_mapping
[
t
]
=
cls
# Returning the cls means we can use this as a decorator.
return
cls
def
registered_tags
(
self
):
"""
Get a list of all the tags that have been registered.
...
...
common/lib/capa/capa/responsetypes.py
View file @
9dbd4c5b
...
...
@@ -33,6 +33,7 @@ from shapely.geometry import Point, MultiPoint
# specific library imports
from
calc
import
evaluator
,
UndefinedVariable
from
.
import
correctmap
from
.registry
import
TagRegistry
from
datetime
import
datetime
from
pytz
import
UTC
from
.util
import
(
compare_with_tolerance
,
contextualize_text
,
convert_files_to_filenames
,
...
...
@@ -45,6 +46,7 @@ import capa.safe_exec as safe_exec
log
=
logging
.
getLogger
(
__name__
)
registry
=
TagRegistry
()
CorrectMap
=
correctmap
.
CorrectMap
# pylint: disable=C0103
CORRECTMAP_PY
=
None
...
...
@@ -92,7 +94,7 @@ class LoncapaResponse(object):
Each subclass must also define the following attributes:
-
response_tag : xhtml tag
identifying this response (used in auto-registering)
-
tags : xhtml tags
identifying this response (used in auto-registering)
In addition, these methods are optional:
...
...
@@ -120,7 +122,7 @@ class LoncapaResponse(object):
"""
__metaclass__
=
abc
.
ABCMeta
# abc = Abstract Base Class
response_tag
=
None
tags
=
None
hint_tag
=
None
max_inputfields
=
None
...
...
@@ -405,13 +407,14 @@ class LoncapaResponse(object):
#-----------------------------------------------------------------------------
@registry.register
class
JavascriptResponse
(
LoncapaResponse
):
"""
This response type is used when the student's answer is graded via
Javascript using Node.js.
"""
response_tag
=
'javascriptresponse'
tags
=
[
'javascriptresponse'
]
max_inputfields
=
1
allowed_inputfields
=
[
'javascriptinput'
]
...
...
@@ -605,6 +608,7 @@ class JavascriptResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
ChoiceResponse
(
LoncapaResponse
):
"""
This response type is used when the student chooses from a discrete set of
...
...
@@ -653,7 +657,7 @@ class ChoiceResponse(LoncapaResponse):
"""
response_tag
=
'choiceresponse'
tags
=
[
'choiceresponse'
]
max_inputfields
=
1
allowed_inputfields
=
[
'checkboxgroup'
,
'radiogroup'
]
correct_choices
=
None
...
...
@@ -702,10 +706,11 @@ class ChoiceResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
MultipleChoiceResponse
(
LoncapaResponse
):
# TODO: handle direction and randomize
response_tag
=
'multiplechoiceresponse'
tags
=
[
'multiplechoiceresponse'
]
max_inputfields
=
1
allowed_inputfields
=
[
'choicegroup'
]
correct_choices
=
None
...
...
@@ -759,9 +764,10 @@ class MultipleChoiceResponse(LoncapaResponse):
return
{
self
.
answer_id
:
self
.
correct_choices
}
@registry.register
class
TrueFalseResponse
(
MultipleChoiceResponse
):
response_tag
=
'truefalseresponse'
tags
=
[
'truefalseresponse'
]
def
mc_setup_response
(
self
):
i
=
0
...
...
@@ -786,12 +792,13 @@ class TrueFalseResponse(MultipleChoiceResponse):
#-----------------------------------------------------------------------------
@registry.register
class
OptionResponse
(
LoncapaResponse
):
'''
TODO: handle direction and randomize
'''
response_tag
=
'optionresponse'
tags
=
[
'optionresponse'
]
hint_tag
=
'optionhint'
allowed_inputfields
=
[
'optioninput'
]
answer_fields
=
None
...
...
@@ -819,13 +826,14 @@ class OptionResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
NumericalResponse
(
LoncapaResponse
):
'''
This response type expects a number or formulaic expression that evaluates
to a number (e.g. `4+5/2^2`), and accepts with a tolerance.
'''
response_tag
=
'numericalresponse'
tags
=
[
'numericalresponse'
]
hint_tag
=
'numericalhint'
allowed_inputfields
=
[
'textline'
,
'formulaequationinput'
]
required_attributes
=
[
'answer'
]
...
...
@@ -946,6 +954,7 @@ class NumericalResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
StringResponse
(
LoncapaResponse
):
'''
This response type allows one or more answers.
...
...
@@ -978,7 +987,7 @@ class StringResponse(LoncapaResponse):
</hintgroup>
</stringresponse>
'''
response_tag
=
'stringresponse'
tags
=
[
'stringresponse'
]
hint_tag
=
'stringhint'
allowed_inputfields
=
[
'textline'
]
required_attributes
=
[
'answer'
]
...
...
@@ -1080,13 +1089,14 @@ class StringResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
CustomResponse
(
LoncapaResponse
):
'''
Custom response. The python code to be run should be in <answer>...</answer>
or in a <script>...</script>
'''
response_tag
=
'customresponse'
tags
=
[
'customresponse'
]
allowed_inputfields
=
[
'textline'
,
'textbox'
,
'crystallography'
,
'chemicalequationinput'
,
'vsepr_input'
,
...
...
@@ -1408,12 +1418,13 @@ class CustomResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
SymbolicResponse
(
CustomResponse
):
"""
Symbolic math response checking, using symmath library.
"""
response_tag
=
'symbolicresponse'
tags
=
[
'symbolicresponse'
]
max_inputfields
=
1
def
setup_response
(
self
):
...
...
@@ -1456,6 +1467,7 @@ class SymbolicResponse(CustomResponse):
ScoreMessage
=
namedtuple
(
'ScoreMessage'
,
[
'valid'
,
'correct'
,
'points'
,
'msg'
])
# pylint: disable=invalid-name
@registry.register
class
CodeResponse
(
LoncapaResponse
):
"""
Grade student code using an external queueing server, called 'xqueue'
...
...
@@ -1472,7 +1484,7 @@ class CodeResponse(LoncapaResponse):
(i.e. and not for getting reference answers)
"""
response_tag
=
'coderesponse'
tags
=
[
'coderesponse'
]
allowed_inputfields
=
[
'textbox'
,
'filesubmission'
,
'matlabinput'
]
max_inputfields
=
1
payload
=
None
...
...
@@ -1705,6 +1717,7 @@ class CodeResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
ExternalResponse
(
LoncapaResponse
):
"""
Grade the students input using an external server.
...
...
@@ -1713,7 +1726,7 @@ class ExternalResponse(LoncapaResponse):
"""
response_tag
=
'externalresponse'
tags
=
[
'externalresponse'
]
allowed_inputfields
=
[
'textline'
,
'textbox'
]
awdmap
=
{
'EXACT_ANS'
:
'correct'
,
# TODO: handle other loncapa responses
...
...
@@ -1864,12 +1877,13 @@ class ExternalResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
FormulaResponse
(
LoncapaResponse
):
"""
Checking of symbolic math response using numerical sampling.
"""
response_tag
=
'formularesponse'
tags
=
[
'formularesponse'
]
hint_tag
=
'formulahint'
allowed_inputfields
=
[
'textline'
,
'formulaequationinput'
]
required_attributes
=
[
'answer'
,
'samples'
]
...
...
@@ -2068,11 +2082,12 @@ class FormulaResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
SchematicResponse
(
LoncapaResponse
):
"""
Circuit schematic response type.
"""
response_tag
=
'schematicresponse'
tags
=
[
'schematicresponse'
]
allowed_inputfields
=
[
'schematic'
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
...
...
@@ -2118,6 +2133,7 @@ class SchematicResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
ImageResponse
(
LoncapaResponse
):
"""
Handle student response for image input: the input is a click on an image,
...
...
@@ -2145,7 +2161,7 @@ class ImageResponse(LoncapaResponse):
True, if click is inside any region or rectangle. Otherwise False.
"""
response_tag
=
'imageresponse'
tags
=
[
'imageresponse'
]
allowed_inputfields
=
[
'imageinput'
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
...
...
@@ -2248,6 +2264,7 @@ class ImageResponse(LoncapaResponse):
#-----------------------------------------------------------------------------
@registry.register
class
AnnotationResponse
(
LoncapaResponse
):
"""
Checking of annotation responses.
...
...
@@ -2255,7 +2272,7 @@ class AnnotationResponse(LoncapaResponse):
The response contains both a comment (student commentary) and an option (student tag).
Only the tag is currently graded. Answers may be incorrect, partially correct, or correct.
"""
response_tag
=
'annotationresponse'
tags
=
[
'annotationresponse'
]
allowed_inputfields
=
[
'annotationinput'
]
max_inputfields
=
1
default_scoring
=
{
'incorrect'
:
0
,
'partially-correct'
:
1
,
'correct'
:
2
}
...
...
@@ -2371,6 +2388,7 @@ class AnnotationResponse(LoncapaResponse):
return
None
@registry.register
class
ChoiceTextResponse
(
LoncapaResponse
):
"""
Allows for multiple choice responses with text inputs
...
...
@@ -2378,7 +2396,7 @@ class ChoiceTextResponse(LoncapaResponse):
ChoiceResponse.
"""
response_tag
=
'choicetextresponse'
tags
=
[
'choicetextresponse'
]
max_inputfields
=
1
allowed_inputfields
=
[
'choicetextgroup'
,
'checkboxtextgroup'
,
...
...
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