Fix some of the common test collection issues. (#21340)
* Remove old performance tests that we haven't been running. As far as I can tell, these tests to capture HAR files were created 5 years ago and not being run as a part of our suite? They capture HAR data that we do nothing with so even if they were running we should remove them until we're ready to care about consuming this kind of information. * Update password test unicode string. * Add ugettext translation helper function. * Fix lambda syntax that is not valid in python 3. * Fix ur raw strings which his not valid in python 3 * Use edx_six.get_gettext instead of ugettext. * Fix a few other encoding issues. * Don't use old form of sorted funciton. This form which uses a 'cmp' method is not available in python 3.
This commit is contained in:
@@ -48,8 +48,8 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase):
|
||||
|
||||
def test_unicode_password(self):
|
||||
""" Tests that validate_password enforces unicode """
|
||||
byte_str = b'𤭮'
|
||||
unicode_str = u'𤭮'
|
||||
byte_str = unicode_str.encode('utf-8')
|
||||
|
||||
# Sanity checks and demonstration of why this test is useful
|
||||
self.assertEqual(len(byte_str), 4)
|
||||
|
||||
@@ -59,7 +59,9 @@ from six import text_type
|
||||
from capa.xqueue_interface import XQUEUE_TIMEOUT
|
||||
from chem import chemcalc
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from openedx.core.lib import edx_six
|
||||
from xmodule.stringify import stringify_children
|
||||
from openedx.core.lib import edx_six
|
||||
|
||||
from . import xqueue_interface
|
||||
from .registry import TagRegistry
|
||||
@@ -256,6 +258,7 @@ class InputTypeBase(object):
|
||||
# Something went wrong: add xml to message, but keep the traceback
|
||||
msg = u"Error in xml '{x}': {err} ".format(
|
||||
x=etree.tostring(xml), err=text_type(err))
|
||||
msg = Exception(msg)
|
||||
six.reraise(Exception, msg, sys.exc_info()[2])
|
||||
|
||||
@classmethod
|
||||
@@ -326,7 +329,7 @@ class InputTypeBase(object):
|
||||
context = {
|
||||
'id': self.input_id,
|
||||
'value': self.value,
|
||||
'status': Status(self.status, self.capa_system.i18n.ugettext),
|
||||
'status': Status(self.status, edx_six.get_gettext(self.capa_system.i18n)),
|
||||
'msg': self.msg,
|
||||
'response_data': self.response_data,
|
||||
'STATIC_URL': self.capa_system.STATIC_URL,
|
||||
@@ -427,14 +430,21 @@ class OptionInput(InputTypeBase):
|
||||
options = re.sub(r"([a-zA-Z])('|\\')([a-zA-Z])", r"\1'\3", options)
|
||||
options = re.sub(r"\\'", r"'", options) # replace already escaped single quotes
|
||||
# parse the set of possible options
|
||||
lexer = shlex.shlex(options[1:-1].encode('utf8'))
|
||||
if six.PY3:
|
||||
lexer = shlex.shlex(options[1:-1])
|
||||
else:
|
||||
lexer = shlex.shlex(options[1:-1].encode('utf-8'))
|
||||
|
||||
lexer.quotes = "'"
|
||||
# Allow options to be separated by whitespace as well as commas
|
||||
lexer.whitespace = ", "
|
||||
|
||||
# remove quotes
|
||||
# convert escaped single quotes (html encoded string) back to single quotes
|
||||
tokens = [x[1:-1].decode('utf8').replace("'", "'") for x in lexer]
|
||||
if six.PY3:
|
||||
tokens = [x[1:-1].replace("'", "'") for x in lexer]
|
||||
else:
|
||||
tokens = [x[1:-1].decode('utf-8').replace("'", "'") for x in lexer]
|
||||
|
||||
# make list of (option_id, option_description), with description=id
|
||||
return [(t, t) for t in tokens]
|
||||
@@ -451,7 +461,7 @@ class OptionInput(InputTypeBase):
|
||||
"""
|
||||
Return extra context.
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
return {'default_option_text': _('Select an option')}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -499,7 +509,7 @@ class ChoiceGroup(InputTypeBase):
|
||||
self.html_input_type = "checkbox"
|
||||
self.suffix = '[]'
|
||||
else:
|
||||
_ = i18n.ugettext
|
||||
_ = edx_six.get_gettext(i18n)
|
||||
# Translators: 'ChoiceGroup' is an input type and should not be translated.
|
||||
msg = _("ChoiceGroup: unexpected tag {tag_name}").format(tag_name=self.tag)
|
||||
raise Exception(msg)
|
||||
@@ -535,7 +545,7 @@ class ChoiceGroup(InputTypeBase):
|
||||
"""
|
||||
|
||||
choices = []
|
||||
_ = i18n.ugettext
|
||||
_ = edx_six.get_gettext(i18n)
|
||||
|
||||
for choice in element:
|
||||
if choice.tag == 'choice':
|
||||
@@ -731,7 +741,7 @@ class FileSubmission(InputTypeBase):
|
||||
Do some magic to handle queueing status (render as "queued" instead of "incomplete"),
|
||||
pull queue_len from the msg field. (TODO: get rid of the queue_len hack).
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
submitted_msg = _("Your files have been submitted. As soon as your submission is"
|
||||
" graded, this message will be replaced with the grader's feedback.")
|
||||
self.submitted_msg = submitted_msg
|
||||
@@ -803,7 +813,7 @@ class CodeInput(InputTypeBase):
|
||||
|
||||
def setup(self):
|
||||
""" setup this input type """
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
submitted_msg = _("Your answer has been submitted. As soon as your submission is"
|
||||
" graded, this message will be replaced with the grader's feedback.")
|
||||
self.submitted_msg = submitted_msg
|
||||
@@ -814,7 +824,7 @@ class CodeInput(InputTypeBase):
|
||||
"""
|
||||
Define queue_len, arial_label and code mirror exit message context variables
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
return {
|
||||
'queue_len': self.queue_len,
|
||||
'aria_label': _('{programming_language} editor').format(
|
||||
@@ -844,7 +854,7 @@ class MatlabInput(CodeInput):
|
||||
"""
|
||||
Handle matlab-specific parsing
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
|
||||
submitted_msg = _("Submitted. As soon as a response is returned, "
|
||||
"this message will be replaced by that feedback.")
|
||||
@@ -927,7 +937,7 @@ class MatlabInput(CodeInput):
|
||||
def _extra_context(self):
|
||||
""" Set up additional context variables"""
|
||||
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
|
||||
queue_msg = self.queue_msg
|
||||
if len(self.queue_msg) > 0: # An empty string cannot be parsed as XML but is okay to include in the template.
|
||||
@@ -976,7 +986,7 @@ class MatlabInput(CodeInput):
|
||||
dict - 'success' - whether or not we successfully queued this submission
|
||||
- 'message' - message to be rendered in case of error
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# only send data if xqueue exists
|
||||
if self.capa_system.xqueue is None:
|
||||
return {'success': False, 'message': _('Cannot connect to the queue')}
|
||||
@@ -1203,7 +1213,7 @@ class ChemicalEquationInput(InputTypeBase):
|
||||
}
|
||||
"""
|
||||
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
result = {'preview': '',
|
||||
'error': ''}
|
||||
try:
|
||||
@@ -1287,7 +1297,7 @@ class FormulaEquationInput(InputTypeBase):
|
||||
'request_start' : <time sent with request>
|
||||
}
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
result = {'preview': '',
|
||||
'error': ''}
|
||||
|
||||
@@ -1706,7 +1716,7 @@ class ChoiceTextGroup(InputTypeBase):
|
||||
elif self.tag == 'checkboxtextgroup':
|
||||
self.html_input_type = "checkbox"
|
||||
else:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
msg = _("{input_type}: unexpected tag {tag_name}").format(
|
||||
input_type="ChoiceTextGroup", tag_name=self.tag
|
||||
)
|
||||
@@ -1785,7 +1795,7 @@ class ChoiceTextGroup(InputTypeBase):
|
||||
]
|
||||
"""
|
||||
|
||||
_ = i18n.ugettext
|
||||
_ = edx_six.get_gettext(i18n)
|
||||
choices = []
|
||||
|
||||
for choice in element:
|
||||
|
||||
@@ -46,6 +46,7 @@ from six.moves import map, range, zip
|
||||
import capa.safe_exec as safe_exec
|
||||
import capa.xqueue_interface as xqueue_interface
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from openedx.core.lib import edx_six
|
||||
|
||||
from . import correctmap
|
||||
from .registry import TagRegistry
|
||||
@@ -254,7 +255,7 @@ class LoncapaResponse(six.with_metaclass(abc.ABCMeta, object)):
|
||||
- renderer : procedure which produces HTML given an ElementTree
|
||||
- response_msg: a message displayed at the end of the Response
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
|
||||
# response_id = problem_id + response index
|
||||
response_id = self.xml.attrib['id']
|
||||
@@ -344,7 +345,7 @@ class LoncapaResponse(six.with_metaclass(abc.ABCMeta, object)):
|
||||
e.g. [{'text': 'a hint', 'trigger':[{'choice': 'choice_0', 'selected': True},
|
||||
{'choice': 'choice_1', 'selected':True}]}]
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# 1. Establish the hint_texts
|
||||
# This can lead to early-exit if the hint is blank.
|
||||
if not hint_log:
|
||||
@@ -489,7 +490,7 @@ class LoncapaResponse(six.with_metaclass(abc.ABCMeta, object)):
|
||||
unsafely=self.capa_system.can_execute_unsafe_code(),
|
||||
)
|
||||
except Exception as err:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
msg = _('Error {err} in evaluating hint function {hintfn}.').format(err=err, hintfn=hintfn)
|
||||
sourcenum = getattr(self.xml, 'sourceline', _('(Source code line unavailable)'))
|
||||
msg += "\n" + _("See XML source line {sourcenum}.").format(sourcenum=sourcenum)
|
||||
@@ -1184,7 +1185,7 @@ class MultipleChoiceResponse(LoncapaResponse):
|
||||
Fails with LoncapaProblemError if called on a response that is not masking.
|
||||
"""
|
||||
# if not self.has_mask():
|
||||
# _ = self.capa_system.i18n.ugettext
|
||||
# _ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# # Translators: 'unmask_name' is a method name and should not be translated.
|
||||
# msg = "unmask_name called on response that is not masked"
|
||||
# raise LoncapaProblemError(msg)
|
||||
@@ -1215,7 +1216,7 @@ class MultipleChoiceResponse(LoncapaResponse):
|
||||
if choicegroups:
|
||||
choicegroup = choicegroups[0]
|
||||
if choicegroup.get('answer-pool') is not None:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# Translators: 'shuffle' and 'answer-pool' are attribute names and should not be translated.
|
||||
msg = _("Do not use shuffle and answer-pool at the same time")
|
||||
raise LoncapaProblemError(msg)
|
||||
@@ -1298,7 +1299,7 @@ class MultipleChoiceResponse(LoncapaResponse):
|
||||
try:
|
||||
num_choices = int(num_str)
|
||||
except ValueError:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# Translators: 'answer-pool' is an attribute name and should not be translated.
|
||||
msg = _("answer-pool value should be an integer")
|
||||
raise LoncapaProblemError(msg)
|
||||
@@ -1365,7 +1366,7 @@ class MultipleChoiceResponse(LoncapaResponse):
|
||||
# Or perhaps in the overall author workflow, these errors are unhelpful and
|
||||
# should all be removed.
|
||||
if len(correct_choices) < 1 or len(incorrect_choices) < 1:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# Translators: 'Choicegroup' is an input type and should not be translated.
|
||||
msg = _("Choicegroup must include at least 1 correct and 1 incorrect choice")
|
||||
raise LoncapaProblemError(msg)
|
||||
@@ -1535,7 +1536,7 @@ class NumericalResponse(LoncapaResponse):
|
||||
self.correct_answer = answer[0] + self.answer_range[0] + ', ' + self.answer_range[1] + answer[-1]
|
||||
except Exception:
|
||||
log.debug("Content error--answer '%s' is not a valid range tolerance answer", answer)
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
raise StudentInputError(
|
||||
_("There was a problem with the staff answer to this problem.")
|
||||
)
|
||||
@@ -1567,7 +1568,7 @@ class NumericalResponse(LoncapaResponse):
|
||||
correct_ans = evaluator({}, {}, answer)
|
||||
except Exception:
|
||||
log.debug("Content error--answer '%s' is not a valid number", answer)
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
raise StudentInputError(
|
||||
_("There was a problem with the staff answer to this problem.")
|
||||
)
|
||||
@@ -1591,7 +1592,7 @@ class NumericalResponse(LoncapaResponse):
|
||||
|
||||
student_answer = student_answers[self.answer_id]
|
||||
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
general_exception = StudentInputError(
|
||||
_(u"Could not interpret '{student_answer}' as a number.").format(student_answer=cgi.escape(student_answer))
|
||||
)
|
||||
@@ -1778,7 +1779,7 @@ class NumericalResponse(LoncapaResponse):
|
||||
return False
|
||||
|
||||
def get_answers(self):
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# Example: "Answer: Answer_1 or Answer_2 or Answer_3".
|
||||
separator = Text(' {b_start}{or_separator}{b_end} ').format(
|
||||
# Translators: Separator used in NumericalResponse to display multiple answers.
|
||||
@@ -1833,7 +1834,7 @@ class StringResponse(LoncapaResponse):
|
||||
This response type allows one or more answers.
|
||||
|
||||
Additional answers are added by `additional_answer` tag.
|
||||
If `regexp` is in `type` attribute, than answers and hints are treated as regular expressions.
|
||||
If `regexp` is in `type` attribute, then answers and hints are treated as regular expressions.
|
||||
|
||||
Examples:
|
||||
<stringresponse answer="Michigan">
|
||||
@@ -2028,7 +2029,7 @@ class StringResponse(LoncapaResponse):
|
||||
if not given:
|
||||
return False
|
||||
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# backward compatibility, should be removed in future.
|
||||
if self.backward:
|
||||
return self.check_string_backward(expected, given)
|
||||
@@ -2067,7 +2068,7 @@ class StringResponse(LoncapaResponse):
|
||||
return hints_to_show
|
||||
|
||||
def get_answers(self):
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# Translators: Separator used in StringResponse to display multiple answers.
|
||||
# Example: "Answer: Answer_1 or Answer_2 or Answer_3".
|
||||
separator = HTML(' <b>{}</b> ').format(_('or'))
|
||||
@@ -2171,7 +2172,7 @@ class CustomResponse(LoncapaResponse):
|
||||
student_answers is a dict with everything from request.POST, but with the first part
|
||||
of each key removed (the string before the first "_").
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
|
||||
log.debug('%s: student_answers=%s', six.text_type(self), student_answers)
|
||||
|
||||
@@ -2431,7 +2432,7 @@ class CustomResponse(LoncapaResponse):
|
||||
# Raise an exception
|
||||
else:
|
||||
log.error(traceback.format_exc())
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
raise ResponseError(
|
||||
_("CustomResponse: check function returned an invalid dictionary!")
|
||||
)
|
||||
@@ -2555,7 +2556,7 @@ class SymbolicResponse(CustomResponse):
|
||||
except Exception as err:
|
||||
log.error("oops in SymbolicResponse (cfn) error %s", err)
|
||||
log.error(traceback.format_exc())
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# Translators: 'SymbolicResponse' is a problem type and should not be translated.
|
||||
msg = _(u"An error occurred with SymbolicResponse. The error was: {error_msg}").format(
|
||||
error_msg=err,
|
||||
@@ -2651,12 +2652,12 @@ class CodeResponse(LoncapaResponse):
|
||||
|
||||
self.initial_display = find_with_default(
|
||||
codeparam, 'initial_display', '')
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
self.answer = find_with_default(codeparam, 'answer_display',
|
||||
_(u'No answer provided.'))
|
||||
|
||||
def get_score(self, student_answers):
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
try:
|
||||
# Note that submission can be a file
|
||||
submission = student_answers[self.answer_id]
|
||||
@@ -2732,7 +2733,7 @@ class CodeResponse(LoncapaResponse):
|
||||
|
||||
cmap = CorrectMap()
|
||||
if error:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
error_msg = _('Unable to deliver your submission to grader (Reason: {error_msg}).'
|
||||
' Please try again later.').format(error_msg=msg)
|
||||
cmap.set(self.answer_id, queuestate=None, msg=error_msg)
|
||||
@@ -2752,7 +2753,7 @@ class CodeResponse(LoncapaResponse):
|
||||
"""Updates the user's score based on the returned message from the grader."""
|
||||
(valid_score_msg, correct, points, msg) = self._parse_score_msg(score_msg)
|
||||
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
|
||||
if not valid_score_msg:
|
||||
# Translators: 'grader' refers to the edX automatic code grader.
|
||||
@@ -3086,7 +3087,7 @@ class FormulaResponse(LoncapaResponse):
|
||||
Each dictionary represents a test case for the answer.
|
||||
Returns a tuple of formula evaluation results.
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
|
||||
out = []
|
||||
for var_dict in var_dict_list:
|
||||
@@ -3283,7 +3284,7 @@ class SchematicResponse(LoncapaResponse):
|
||||
unsafely=self.capa_system.can_execute_unsafe_code(),
|
||||
)
|
||||
except Exception as err:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
# Translators: 'SchematicResponse' is a problem type and should not be translated.
|
||||
msg = _('Error in evaluating SchematicResponse. The error was: {error_msg}').format(error_msg=err)
|
||||
raise ResponseError(msg)
|
||||
@@ -3339,7 +3340,7 @@ class ImageResponse(LoncapaResponse):
|
||||
self.answer_ids = [ie.get('id') for ie in self.ielements]
|
||||
|
||||
def get_score(self, student_answers):
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
correct_map = CorrectMap()
|
||||
expectedset = self.get_mapped_answers()
|
||||
for aid in self.answer_ids: # loop through IDs of <imageinput>
|
||||
@@ -3601,7 +3602,7 @@ class ChoiceTextResponse(LoncapaResponse):
|
||||
and `answer_values` is used for displaying correct answers.
|
||||
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
context = self.context
|
||||
self.answer_values = {self.answer_id: []}
|
||||
self.assign_choice_names()
|
||||
@@ -3849,7 +3850,7 @@ class ChoiceTextResponse(LoncapaResponse):
|
||||
|
||||
Returns True if and only if all student inputs are correct.
|
||||
"""
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
_ = edx_six.get_gettext(self.capa_system.i18n)
|
||||
inputs_correct = True
|
||||
for answer_name, answer_value in six.iteritems(numtolerance_inputs):
|
||||
# If `self.corrrect_inputs` does not contain an entry for
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import gettext
|
||||
import io
|
||||
import os
|
||||
import os.path
|
||||
import xml.sax.saxutils as saxutils
|
||||
@@ -116,6 +117,6 @@ def load_fixture(relpath):
|
||||
in the same directory as the test file.
|
||||
"""
|
||||
abspath = os.path.join(os.path.dirname(__file__), 'test_files', relpath)
|
||||
with open(abspath) as fixture_file:
|
||||
with io.open(abspath, encoding="utf-8") as fixture_file:
|
||||
contents = fixture_file.read()
|
||||
return contents.decode('utf8')
|
||||
return contents
|
||||
|
||||
@@ -699,18 +699,18 @@ class StringResponseTest(ResponseTest): # pylint: disable=missing-docstring
|
||||
b) regexp is saved to xml and is read in python as repr of that string
|
||||
So a\d in front-end editor will become a\\\\d in xml, so it will match a1 as student answer.
|
||||
"""
|
||||
problem = self.build_problem(answer=ur"5\\æ", case_sensitive=False, regexp=True)
|
||||
self.assert_grade(problem, ur"5\æ", "correct")
|
||||
problem = self.build_problem(answer=u"5\\\\æ", case_sensitive=False, regexp=True)
|
||||
self.assert_grade(problem, u"5\\æ", "correct")
|
||||
|
||||
problem = self.build_problem(answer=u"5\\\\æ", case_sensitive=False, regexp=True)
|
||||
self.assert_grade(problem, ur"5\æ", "correct")
|
||||
self.assert_grade(problem, u"5\\æ", "correct")
|
||||
|
||||
def test_backslash(self):
|
||||
problem = self.build_problem(answer=u"a\\\\c1", case_sensitive=False, regexp=True)
|
||||
self.assert_grade(problem, ur"a\c1", "correct")
|
||||
self.assert_grade(problem, u"a\\c1", "correct")
|
||||
|
||||
def test_special_chars(self):
|
||||
problem = self.build_problem(answer=ur"a \s1", case_sensitive=False, regexp=True)
|
||||
problem = self.build_problem(answer=u"a \\s1", case_sensitive=False, regexp=True)
|
||||
self.assert_grade(problem, u"a 1", "correct")
|
||||
|
||||
def test_case_sensitive(self):
|
||||
|
||||
@@ -102,7 +102,7 @@ def contextualize_text(text, context): # private
|
||||
"""
|
||||
if not text:
|
||||
return text
|
||||
for key in sorted(context, lambda x, y: cmp(len(y), len(x))):
|
||||
for key in sorted(context, key=len, reverse=True):
|
||||
# TODO (vshnayder): This whole replacement thing is a big hack
|
||||
# right now--context contains not just the vars defined in the
|
||||
# program, but also e.g. a reference to the numpy module.
|
||||
|
||||
@@ -7,6 +7,7 @@ import json
|
||||
import re
|
||||
|
||||
import requests
|
||||
import six
|
||||
from lazy import lazy
|
||||
|
||||
from common.test.acceptance.fixtures import LMS_BASE_URL, STUDIO_BASE_URL
|
||||
@@ -88,8 +89,9 @@ class ConfigModelFixture(object):
|
||||
if response.ok:
|
||||
# auto_auth returns information about the newly created user
|
||||
# capture this so it can be used by by the testcases.
|
||||
user_pattern = re.compile(ur'Logged in user {0} \({1}\) with password {2} and user_id {3}'.format(
|
||||
r'(?P<username>\S+)', r'(?P<email>[^\)]+)', r'(?P<password>\S+)', r'(?P<user_id>\d+)'))
|
||||
user_pattern = re.compile(
|
||||
six.text_type(r'Logged in user {0} \({1}\) with password {2} and user_id {3}').format( # pylint: disable=unicode-format-string
|
||||
r'(?P<username>\S+)', r'(?P<email>[^\)]+)', r'(?P<password>\S+)', r'(?P<user_id>\d+)'))
|
||||
user_matches = re.match(user_pattern, response.text)
|
||||
if user_matches:
|
||||
self.user = user_matches.groupdict() # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
@@ -68,7 +68,7 @@ class ImportExportMixin(object):
|
||||
"""
|
||||
string = self.q(css='.item-progresspoint-success-date').text[0]
|
||||
|
||||
return re.match(ur'\(([^ ]+).+?(\d{2}:\d{2})', string).groups()
|
||||
return re.match(six.text_type(r'\(([^ ]+).+?(\d{2}:\d{2})'), string).groups() # pylint: disable=unicode-format-string
|
||||
|
||||
def wait_for_tasks(self, completed=False, fail_on=None):
|
||||
"""
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
"""
|
||||
Single page performance tests for LMS.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from bok_choy.web_app_test import with_cache
|
||||
|
||||
from common.test.acceptance.fixtures.course import CourseFixture, CourseUpdateDesc, XBlockFixtureDesc
|
||||
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
|
||||
from common.test.acceptance.pages.common.logout import LogoutPage
|
||||
from common.test.acceptance.pages.lms.course_info import CourseInfoPage
|
||||
from common.test.acceptance.pages.lms.courseware import CoursewarePage
|
||||
from common.test.acceptance.pages.lms.dashboard import DashboardPage
|
||||
from common.test.acceptance.pages.lms.login import LoginPage
|
||||
from common.test.acceptance.pages.lms.progress import ProgressPage
|
||||
from common.test.acceptance.tests.helpers import UniqueCourseTest, load_data_str
|
||||
|
||||
|
||||
class LmsPerformanceTest(UniqueCourseTest):
|
||||
"""
|
||||
Base class to capture LMS performance with HTTP Archives.
|
||||
"""
|
||||
username = 'test_student'
|
||||
email = 'student101@example.com'
|
||||
har_mode = 'explicit'
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Setup course
|
||||
"""
|
||||
super(LmsPerformanceTest, self).setUp()
|
||||
|
||||
# Install a course with sections/problems, tabs, updates, and handouts
|
||||
course_fix = CourseFixture(
|
||||
self.course_info['org'], self.course_info['number'],
|
||||
self.course_info['run'], self.course_info['display_name']
|
||||
)
|
||||
|
||||
course_fix.add_update(CourseUpdateDesc(date='January 29, 2014', content='Test course update1'))
|
||||
course_fix.add_update(CourseUpdateDesc(date='January 30, 2014', content='Test course update2'))
|
||||
course_fix.add_update(CourseUpdateDesc(date='January 31, 2014', content='Test course update3'))
|
||||
|
||||
course_fix.add_children(
|
||||
XBlockFixtureDesc('chapter', 'Test Section 1').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection 1').add_children(
|
||||
XBlockFixtureDesc('problem', 'Test Problem 1', data=load_data_str('multiple_choice.xml')),
|
||||
XBlockFixtureDesc('problem', 'Test Problem 2', data=load_data_str('formula_problem.xml')),
|
||||
XBlockFixtureDesc('html', 'Test HTML', data="<html>Html child text</html>"),
|
||||
)
|
||||
),
|
||||
XBlockFixtureDesc('chapter', 'Test Section 2').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection 2').add_children(
|
||||
XBlockFixtureDesc('html', 'Html Child', data="<html>Html child text</html>")
|
||||
)
|
||||
),
|
||||
XBlockFixtureDesc('chapter', 'Test Section 3').add_children(
|
||||
XBlockFixtureDesc('sequential', 'Test Subsection 3').add_children(
|
||||
XBlockFixtureDesc('problem', 'Test Problem 3')
|
||||
)
|
||||
)
|
||||
).install()
|
||||
|
||||
AutoAuthPage(self.browser, username=self.username, email=self.email, course_id=self.course_id).visit()
|
||||
|
||||
def _make_har_file(self, page):
|
||||
"""
|
||||
Visit page and make HAR file.
|
||||
"""
|
||||
har_name = '{page}_{course}'.format(page=type(page).__name__, course=self.course_info['number'])
|
||||
|
||||
self.har_capturer.add_page(self.browser, har_name)
|
||||
page.visit()
|
||||
self.har_capturer.save_har(self.browser, har_name)
|
||||
|
||||
@with_cache
|
||||
def test_visit_coursware(self):
|
||||
"""
|
||||
Produce a HAR for loading the Coursware page.
|
||||
"""
|
||||
courseware_page = CoursewarePage(self.browser, self.course_id)
|
||||
self._make_har_file(courseware_page)
|
||||
|
||||
@with_cache
|
||||
def test_visit_dashboard(self):
|
||||
"""
|
||||
Produce a HAR for loading the Dashboard page.
|
||||
"""
|
||||
dashboard_page = DashboardPage(self.browser)
|
||||
self._make_har_file(dashboard_page)
|
||||
|
||||
@with_cache
|
||||
def test_visit_course_info(self):
|
||||
"""
|
||||
Produce a HAR for loading the Course Info page.
|
||||
"""
|
||||
course_info_page = CourseInfoPage(self.browser, self.course_id)
|
||||
self._make_har_file(course_info_page)
|
||||
|
||||
@with_cache
|
||||
def test_visit_login_page(self):
|
||||
"""
|
||||
Produce a HAR for loading the Login page.
|
||||
"""
|
||||
login_page = LoginPage(self.browser)
|
||||
|
||||
# Logout previously logged in user to be able to see Login page.
|
||||
LogoutPage(self.browser).visit()
|
||||
self._make_har_file(login_page)
|
||||
|
||||
@with_cache
|
||||
def test_visit_progress_page(self):
|
||||
"""
|
||||
Produce a HAR for loading the Progress page.
|
||||
"""
|
||||
progress_page = ProgressPage(self.browser, self.course_id)
|
||||
self._make_har_file(progress_page)
|
||||
@@ -1,100 +0,0 @@
|
||||
"""
|
||||
Single page performance tests for Studio.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from bok_choy.web_app_test import with_cache
|
||||
|
||||
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
|
||||
from common.test.acceptance.pages.studio.overview import CourseOutlinePage
|
||||
|
||||
from ..tests.helpers import AcceptanceTest
|
||||
|
||||
|
||||
class StudioPagePerformanceTest(AcceptanceTest):
|
||||
"""
|
||||
Base class to capture studio performance with HTTP Archives.
|
||||
|
||||
To import courses for the bok choy tests, pass the --imports_dir=<course directory> argument to the paver command
|
||||
where <course directory> contains the (un-archived) courses to be imported.
|
||||
"""
|
||||
course_org = 'edX'
|
||||
course_num = 'Open_DemoX'
|
||||
course_run = 'edx_demo_course'
|
||||
har_mode = 'explicit'
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Authenticate as staff so we can view and edit courses.
|
||||
"""
|
||||
super(StudioPagePerformanceTest, self).setUp()
|
||||
AutoAuthPage(self.browser, staff=True).visit()
|
||||
|
||||
def record_visit_outline(self):
|
||||
"""
|
||||
Produce a HAR for loading the course outline page.
|
||||
"""
|
||||
course_outline_page = CourseOutlinePage(self.browser, self.course_org, self.course_num, self.course_run)
|
||||
har_name = 'OutlinePage_{org}_{course}'.format(
|
||||
org=self.course_org,
|
||||
course=self.course_num
|
||||
)
|
||||
self.har_capturer.add_page(self.browser, har_name)
|
||||
course_outline_page.visit()
|
||||
self.har_capturer.save_har(self.browser, har_name)
|
||||
|
||||
def record_visit_unit(self, section_title, subsection_title, unit_title):
|
||||
"""
|
||||
Produce a HAR for loading a unit page.
|
||||
"""
|
||||
course_outline_page = CourseOutlinePage(self.browser, self.course_org, self.course_num, self.course_run).visit()
|
||||
course_outline_unit = course_outline_page.section(section_title).subsection(subsection_title).expand_subsection().unit(unit_title)
|
||||
har_name = 'UnitPage_{org}_{course}'.format(
|
||||
org=self.course_org,
|
||||
course=self.course_num
|
||||
)
|
||||
self.har_capturer.add_page(self.browser, har_name)
|
||||
course_outline_unit.go_to()
|
||||
self.har_capturer.save_har(self.browser, har_name)
|
||||
|
||||
|
||||
class StudioJusticePerformanceTest(StudioPagePerformanceTest):
|
||||
"""
|
||||
Test performance on the HarvardX Justice course.
|
||||
"""
|
||||
course_org = 'HarvardX'
|
||||
course_num = 'ER22x'
|
||||
course_run = '2013_Spring'
|
||||
|
||||
@with_cache
|
||||
def test_visit_outline(self):
|
||||
"""Record visiting the Justice course outline page"""
|
||||
self.record_visit_outline()
|
||||
|
||||
@with_cache
|
||||
def test_visit_unit(self):
|
||||
"""Record visiting a Justice unit page"""
|
||||
self.record_visit_unit(
|
||||
'Lecture 1 - Doing the Right Thing',
|
||||
'Discussion Prompt: Ethics of Torture',
|
||||
'Discussion Prompt: Ethics of Torture'
|
||||
)
|
||||
|
||||
|
||||
class StudioPub101PerformanceTest(StudioPagePerformanceTest):
|
||||
"""
|
||||
Test performance on Andy's PUB101 outline page.
|
||||
"""
|
||||
course_org = 'AndyA'
|
||||
course_num = 'PUB101'
|
||||
course_run = 'PUB101'
|
||||
|
||||
@with_cache
|
||||
def test_visit_outline(self):
|
||||
"""Record visiting the PUB101 course outline page"""
|
||||
self.record_visit_outline()
|
||||
|
||||
@with_cache
|
||||
def test_visit_unit(self):
|
||||
"""Record visiting the PUB101 unit page"""
|
||||
self.record_visit_unit('Released', 'Released', 'Released')
|
||||
@@ -11,6 +11,7 @@ from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from pytz import UTC
|
||||
import six
|
||||
from six.moves import map
|
||||
|
||||
from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc
|
||||
@@ -1040,9 +1041,11 @@ class DiscussionEditorPreviewTest(UniqueCourseTest):
|
||||
appear in the preview box
|
||||
"""
|
||||
self.page.set_new_post_editor_value(
|
||||
ur'\begin{equation}'
|
||||
ur'\tau_g(\omega) = - \frac{d}{d\omega}\phi(\omega) \hspace{2em} (1) '
|
||||
ur'\end{equation}'
|
||||
six.text_type(
|
||||
r'\begin{equation}'
|
||||
r'\tau_g(\omega) = - \frac{d}{d\omega}\phi(\omega) \hspace{2em} (1) ' # pylint: disable=unicode-format-string
|
||||
r'\end{equation}'
|
||||
)
|
||||
)
|
||||
self.assertIsNotNone(self.page.get_new_post_preview_text())
|
||||
self.page.click_element(".cancel")
|
||||
|
||||
@@ -504,7 +504,7 @@ def _section_course_info(course, access):
|
||||
|
||||
try:
|
||||
sorted_cutoffs = sorted(list(course.grade_cutoffs.items()), key=lambda i: i[1], reverse=True)
|
||||
advance = lambda memo, (letter, score): u"{}: {}, ".format(letter, score) + memo
|
||||
advance = lambda memo, letter_score_tuple: u"{}: {}, ".format(letter_score_tuple[0], letter_score_tuple[1]) + memo # pylint: disable=line-too-long
|
||||
section_data['grade_cutoffs'] = reduce(advance, sorted_cutoffs, "")[:-2]
|
||||
except Exception: # pylint: disable=broad-except
|
||||
section_data['grade_cutoffs'] = "Not Available"
|
||||
|
||||
16
openedx/core/lib/edx_six.py
Normal file
16
openedx/core/lib/edx_six.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
Extra methods to do some python 2 to 3 things we need to do in edx-platform.
|
||||
|
||||
This is internal and should not be referenced outside of the edx-platform repo.
|
||||
"""
|
||||
import six
|
||||
|
||||
|
||||
def get_gettext(o):
|
||||
"""
|
||||
In python 2 return the ugettext attribute. In python 3 return gettext.
|
||||
"""
|
||||
if six.PY3:
|
||||
return o.gettext
|
||||
else:
|
||||
return o.ugettext
|
||||
Reference in New Issue
Block a user