INCR-411: Updates on Python 3.x

This commit is contained in:
amitvadhel
2019-07-11 00:15:16 +03:00
parent 9d856c4cec
commit 182a177b4e
7 changed files with 56 additions and 46 deletions

View File

@@ -13,6 +13,8 @@ Main module which shows problems (of "capa" type).
This is used by capa_module.
"""
from __future__ import absolute_import
import logging
import os.path
import re
@@ -21,6 +23,7 @@ from copy import deepcopy
from datetime import datetime
from xml.sax.saxutils import unescape
import six
from lxml import etree
from pytz import UTC
@@ -208,7 +211,7 @@ class LoncapaProblem(object):
# Run response late_transforms last (see MultipleChoiceResponse)
# Sort the responses to be in *_1 *_2 ... order.
responses = self.responders.values()
responses = list(self.responders.values())
responses = sorted(responses, key=lambda resp: int(resp.id[resp.id.rindex('_') + 1:]))
for response in responses:
if hasattr(response, 'late_transforms'):
@@ -492,7 +495,7 @@ class LoncapaProblem(object):
answer_ids = []
for response in self.responders.keys():
results = self.responder_answers[response]
answer_ids.append(results.keys())
answer_ids.append(list(results.keys()))
return answer_ids
def find_correct_answer_text(self, answer_id):
@@ -612,7 +615,7 @@ class LoncapaProblem(object):
self.find_answer_text(answer_id, answer) for answer in current_answer
)
elif isinstance(current_answer, basestring) and current_answer.startswith('choice_'):
elif isinstance(current_answer, six.string_types) and current_answer.startswith('choice_'):
# Many problem (e.g. checkbox) report "choice_0" "choice_1" etc.
# Here we transform it
elems = self.tree.xpath('//*[@id="{answer_id}"]//*[@name="{choice_number}"]'.format(
@@ -625,7 +628,7 @@ class LoncapaProblem(object):
choices_map = dict(input_cls.extract_choices(choicegroup, self.capa_system.i18n, text_only=True))
answer_text = choices_map[current_answer]
elif isinstance(current_answer, basestring):
elif isinstance(current_answer, six.string_types):
# Already a string with the answer
answer_text = current_answer
@@ -903,7 +906,7 @@ class LoncapaProblem(object):
Used by get_html.
"""
if not isinstance(problemtree.tag, basestring):
if not isinstance(problemtree.tag, six.string_types):
# Comment and ProcessingInstruction nodes are not Elements,
# and we're ok leaving those behind.
# BTW: etree gives us no good way to distinguish these things

View File

@@ -2,18 +2,17 @@
"""
Commandline tool for doing operations on Problems
"""
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import absolute_import, print_function, unicode_literals
import argparse
import logging
import sys
from io import BytesIO
from calc import UndefinedVariable
from mako.lookup import TemplateLookup
from path import Path as path
from calc import UndefinedVariable
from capa.capa_problem import LoncapaProblem
logging.basicConfig(format="%(levelname)s %(message)s")

View File

@@ -38,6 +38,8 @@ graded status as'status'
# makes sense, but a bunch of problems have markup that assumes block. Bigger TODO: figure out a
# general css and layout strategy for capa, document it, then implement it.
from __future__ import absolute_import
import json
import logging
import re
@@ -49,16 +51,17 @@ from datetime import datetime
import bleach
import html5lib
import pyparsing
import six
from calc.preview import latex_preview
from lxml import etree
from six import text_type
import xqueue_interface
from calc.preview import latex_preview
from capa.xqueue_interface import XQUEUE_TIMEOUT
from chem import chemcalc
from openedx.core.djangolib.markup import HTML, Text
from xmodule.stringify import stringify_children
from . import xqueue_interface
from .registry import TagRegistry
from .util import sanitize_html
@@ -82,7 +85,7 @@ class Status(object):
}
__slots__ = ('classname', '_status', 'display_name', 'display_tooltip')
def __init__(self, status, gettext_func=unicode):
def __init__(self, status, gettext_func=six.text_type):
self.classname = self.css_classes.get(status, status)
_ = gettext_func
names = {
@@ -107,7 +110,7 @@ class Status(object):
['incomplete', 'unanswered', 'unsubmitted'], _('Not yet answered.')
)
)
self.display_name = names.get(status, unicode(status))
self.display_name = names.get(status, six.text_type(status))
self.display_tooltip = tooltips.get(status, u'')
self._status = status or ''
@@ -253,7 +256,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))
raise Exception, msg, sys.exc_info()[2]
six.reraise(Exception, msg, sys.exc_info()[2])
@classmethod
def get_attributes(cls):
@@ -341,14 +344,14 @@ class InputTypeBase(object):
# Every list should contain the status id
status_id = 'status_' + self.input_id
descriptions.append(status_id)
descriptions.extend(self.response_data.get('descriptions', {}).keys())
descriptions.extend(list(self.response_data.get('descriptions', {}).keys()))
description_ids = ' '.join(descriptions)
context.update(
{'describedby_html': HTML('aria-describedby="{}"').format(description_ids)}
)
context.update(
(a, v) for (a, v) in self.loaded_attributes.iteritems() if a in self.to_render
(a, v) for (a, v) in six.iteritems(self.loaded_attributes) if a in self.to_render
)
context.update(self._extra_context())
if self.answervariable:
@@ -554,7 +557,7 @@ class ChoiceGroup(InputTypeBase):
return choices
def get_user_visible_answer(self, internal_answer):
if isinstance(internal_answer, basestring):
if isinstance(internal_answer, six.string_types):
return self._choices_map[internal_answer]
return [self._choices_map[i] for i in internal_answer]
@@ -689,7 +692,7 @@ class TextLine(InputTypeBase):
'class_name': self.loaded_attributes['preprocessorClassName'],
'script_src': self.loaded_attributes['preprocessorSrc'],
}
if None in self.preprocessor.values():
if None in list(self.preprocessor.values()):
self.preprocessor = None
def _extra_context(self):
@@ -1594,7 +1597,7 @@ class AnnotationInput(InputTypeBase):
d = {}
comment_value = d.get('comment', '')
if not isinstance(comment_value, basestring):
if not isinstance(comment_value, six.string_types):
comment_value = ''
options_value = d.get('options', [])

View File

@@ -50,7 +50,7 @@ class TagRegistry(object):
"""
Get a list of all the tags that have been registered.
"""
return self._mapping.keys()
return list(self._mapping.keys())
def get_class_for_tag(self, tag):
"""

View File

@@ -10,6 +10,8 @@ Used by capa_problem.py
# pylint: disable=attribute-defined-outside-init
# standard library imports
from __future__ import absolute_import
import abc
# TODO: Refactor this code and fix this issue.
import cgi
@@ -22,6 +24,7 @@ import re
import sys
import textwrap
import traceback
from cmath import isnan
from collections import namedtuple
from datetime import datetime
from sys import float_info
@@ -29,18 +32,19 @@ from sys import float_info
import html5lib
import numpy
import requests
import six
# specific library imports
from calc import UndefinedVariable, UnmatchedParenthesis, evaluator
from lxml import etree
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
from pyparsing import ParseException
from pytz import UTC
from shapely.geometry import MultiPoint, Point
from six import text_type
from six.moves import map, range, zip
import capa.safe_exec as safe_exec
import capa.xqueue_interface as xqueue_interface
# specific library imports
from calc import UndefinedVariable, UnmatchedParenthesis, evaluator
from cmath import isnan
from openedx.core.djangolib.markup import HTML, Text
from . import correctmap
@@ -103,7 +107,7 @@ class StudentInputError(Exception):
# Main base class for CAPA responsetypes
class LoncapaResponse(object):
class LoncapaResponse(six.with_metaclass(abc.ABCMeta, object)):
"""
Base class for CAPA responsetypes. Each response type (ie a capa question,
which is part of a capa problem) is represented as a subclass,
@@ -140,7 +144,6 @@ class LoncapaResponse(object):
- hint_tag : xhtml tag identifying hint associated with this response inside
hintgroup
"""
__metaclass__ = abc.ABCMeta # abc = Abstract Base Class
tags = None
hint_tag = None
@@ -179,14 +182,14 @@ class LoncapaResponse(object):
for abox in inputfields:
if abox.tag not in self.allowed_inputfields:
msg = "%s: cannot have input field %s" % (
unicode(self), abox.tag)
six.text_type(self), abox.tag)
msg += "\nSee XML source line %s" % getattr(
xml, 'sourceline', '[unavailable]')
raise LoncapaProblemError(msg)
if self.max_inputfields and len(inputfields) > self.max_inputfields:
msg = "%s: cannot have more than %s input fields" % (
unicode(self), self.max_inputfields)
six.text_type(self), self.max_inputfields)
msg += "\nSee XML source line %s" % getattr(
xml, 'sourceline', '[unavailable]')
raise LoncapaProblemError(msg)
@@ -194,7 +197,7 @@ class LoncapaResponse(object):
for prop in self.required_attributes:
if not xml.get(prop):
msg = "Error in problem specification: %s missing required attribute %s" % (
unicode(self), prop)
six.text_type(self), prop)
msg += "\nSee XML source line %s" % getattr(
xml, 'sourceline', '[unavailable]')
raise LoncapaProblemError(msg)
@@ -1455,10 +1458,10 @@ class OptionResponse(LoncapaResponse):
Return student answers variable name if exist in context else None.
"""
if aid in student_answers:
for key, val in self.context.iteritems():
for key, val in six.iteritems(self.context):
# convert val into unicode because student answer always be a unicode string
# even it is a list, dict etc.
if unicode(val) == student_answers[aid]:
if six.text_type(val) == student_answers[aid]:
return '$' + key
return None
@@ -2170,7 +2173,7 @@ class CustomResponse(LoncapaResponse):
"""
_ = self.capa_system.i18n.ugettext
log.debug('%s: student_answers=%s', unicode(self), student_answers)
log.debug('%s: student_answers=%s', six.text_type(self), student_answers)
# ordered list of answer id's
# sort the responses on the bases of the problem's position number
@@ -2284,7 +2287,7 @@ class CustomResponse(LoncapaResponse):
def execute_check_function(self, idset, submission):
# exec the check function
if isinstance(self.code, basestring):
if isinstance(self.code, six.string_types):
try:
safe_exec.safe_exec(
self.code,
@@ -2897,7 +2900,7 @@ class ExternalResponse(LoncapaResponse):
# no <answer> stanza; get code from <script>
self.code = self.context['script_code']
if not self.code:
msg = '%s: Missing answer script code for externalresponse' % unicode(
msg = '%s: Missing answer script code for externalresponse' % six.text_type(
self)
msg += "\nSee XML source line %s" % getattr(
self.xml, 'sourceline', '[unavailable]')
@@ -2972,8 +2975,8 @@ class ExternalResponse(LoncapaResponse):
except Exception as err: # pylint: disable=broad-except
log.error('Error %s', err)
if self.capa_system.DEBUG:
cmap.set_dict(dict(zip(sorted(
self.answer_ids), ['incorrect'] * len(idset))))
cmap.set_dict(dict(list(zip(sorted(
self.answer_ids), ['incorrect'] * len(idset)))))
cmap.set_property(
self.answer_ids[0], 'msg',
Text('<span class="inline-error">{}</span>').format(str(err))
@@ -3013,7 +3016,7 @@ class ExternalResponse(LoncapaResponse):
log.error('Expected %s answers from external server, only got %s!',
len(self.answer_ids), len(exans))
raise Exception('Short response from external server')
return dict(zip(self.answer_ids, exans))
return dict(list(zip(self.answer_ids, exans)))
#-----------------------------------------------------------------------------
@@ -3151,9 +3154,8 @@ class FormulaResponse(LoncapaResponse):
"""
variables = samples.split('@')[0].split(',')
numsamples = int(samples.split('@')[1].split('#')[1])
sranges = zip(*map(lambda x: map(float, x.split(",")),
samples.split('@')[1].split('#')[0].split(':')))
ranges = dict(zip(variables, sranges))
sranges = list(zip(*[list(map(float, x.split(","))) for x in samples.split('@')[1].split('#')[0].split(':')]))
ranges = dict(list(zip(variables, sranges)))
out = []
for _ in range(numsamples):
@@ -3286,7 +3288,7 @@ class SchematicResponse(LoncapaResponse):
msg = _('Error in evaluating SchematicResponse. The error was: {error_msg}').format(error_msg=err)
raise ResponseError(msg)
cmap = CorrectMap()
cmap.set_dict(dict(zip(sorted(self.answer_ids), self.context['correct'])))
cmap.set_dict(dict(list(zip(sorted(self.answer_ids), self.context['correct']))))
return cmap
def get_answers(self):
@@ -3468,8 +3470,8 @@ class AnnotationResponse(LoncapaResponse):
student_option = self._get_submitted_option_id(student_answer)
scoring = self.scoring_map[self.answer_id]
is_valid = student_option is not None and student_option in scoring.keys(
)
is_valid = student_option is not None and student_option in list(scoring.keys(
))
(correctness, points) = ('incorrect', None)
if is_valid:
@@ -3541,7 +3543,7 @@ class AnnotationResponse(LoncapaResponse):
json_d = {}
comment_value = json_d.get('comment', '')
if not isinstance(json_d, basestring):
if not isinstance(json_d, six.string_types):
comment_value = ''
options_value = json_d.get('options', [])
@@ -3849,7 +3851,7 @@ class ChoiceTextResponse(LoncapaResponse):
"""
_ = self.capa_system.i18n.ugettext
inputs_correct = True
for answer_name, answer_value in numtolerance_inputs.iteritems():
for answer_name, answer_value in six.iteritems(numtolerance_inputs):
# If `self.corrrect_inputs` does not contain an entry for
# `answer_name`, this means that answer_name is a decoy
# input's value, and validation of its numericality is the

View File

@@ -1,17 +1,18 @@
"""
Utility functions for capa.
"""
from __future__ import absolute_import
import re
from cmath import isinf, isnan
from decimal import Decimal
import bleach
from calc import evaluator
from lxml import etree
from calc import evaluator
from cmath import isinf, isnan
from openedx.core.djangolib.markup import HTML
#-----------------------------------------------------------------------------
#
# Utility functions used in CAPA responsetypes

View File

@@ -1,3 +1,5 @@
from __future__ import absolute_import
from setuptools import find_packages, setup
setup(