From 47292e5f92f268fd3ddf4231e0490bf8aca6f0cf Mon Sep 17 00:00:00 2001 From: Jeremy Bowman Date: Wed, 8 May 2019 12:13:22 -0400 Subject: [PATCH] Update StringIO usage for Python 3 (#20462) --- common/djangoapps/util/models.py | 4 +-- common/lib/capa/capa/checker.py | 6 ++-- .../xmodule/xmodule/contentstore/content.py | 10 +++---- common/lib/xmodule/xmodule/course_module.py | 4 +-- common/lib/xmodule/xmodule/graders.py | 29 +++++++++---------- common/lib/xmodule/xmodule/modulestore/xml.py | 6 ++-- .../core/djangoapps/profile_images/images.py | 4 +-- 7 files changed, 30 insertions(+), 33 deletions(-) diff --git a/common/djangoapps/util/models.py b/common/djangoapps/util/models.py index 413640b0b6..ba15db5871 100644 --- a/common/djangoapps/util/models.py +++ b/common/djangoapps/util/models.py @@ -1,9 +1,9 @@ """Models for the util app. """ from __future__ import absolute_import -import cStringIO import gzip import logging +from io import BytesIO import six from config_models.models import ConfigurationModel @@ -37,7 +37,7 @@ def decompress_string(value): try: val = value.encode('utf').decode('base64') - zbuf = cStringIO.StringIO(val) + zbuf = BytesIO(val) zfile = gzip.GzipFile(fileobj=zbuf) ret = zfile.read() zfile.close() diff --git a/common/lib/capa/capa/checker.py b/common/lib/capa/capa/checker.py index c11aab4650..25d9bee7e5 100755 --- a/common/lib/capa/capa/checker.py +++ b/common/lib/capa/capa/checker.py @@ -8,7 +8,7 @@ from __future__ import print_function import argparse import logging import sys -from cStringIO import StringIO +from io import BytesIO from mako.lookup import TemplateLookup from path import Path as path @@ -75,8 +75,8 @@ def command_test(problem): # We're going to trap stdout/stderr from the problems (yes, some print) old_stdout, old_stderr = sys.stdout, sys.stderr try: - sys.stdout = StringIO() - sys.stderr = StringIO() + sys.stdout = BytesIO() + sys.stderr = BytesIO() check_that_suggested_answers_work(problem) check_that_blanks_fail(problem) diff --git a/common/lib/xmodule/xmodule/contentstore/content.py b/common/lib/xmodule/xmodule/contentstore/content.py index 83af3bb6d0..ed0c4c6ddf 100644 --- a/common/lib/xmodule/xmodule/contentstore/content.py +++ b/common/lib/xmodule/xmodule/contentstore/content.py @@ -3,8 +3,8 @@ from __future__ import absolute_import import logging import os import re -import StringIO import uuid +from io import BytesIO import six from opaque_keys import InvalidKeyError @@ -418,10 +418,10 @@ class ContentStore(object): # for svg simply store the provided svg file, since vector graphics should be good enough # for downscaling client-side if tempfile_path is None: - thumbnail_file = StringIO.StringIO(content.data) + thumbnail_file = BytesIO(content.data) else: with open(tempfile_path) as f: - thumbnail_file = StringIO.StringIO(f.read()) + thumbnail_file = BytesIO(f.read()) thumbnail_content = StaticContent(thumbnail_file_location, thumbnail_name, 'image/svg+xml', thumbnail_file) self.save(thumbnail_content) @@ -431,13 +431,13 @@ class ContentStore(object): # the max-height/width to be whatever you pass in as 'size' # @todo: move the thumbnail size to a configuration setting?!? if tempfile_path is None: - source = StringIO.StringIO(content.data) + source = BytesIO(content.data) else: source = tempfile_path # We use the context manager here to avoid leaking the inner file descriptor # of the Image object -- this way it gets closed after we're done with using it. - thumbnail_file = StringIO.StringIO() + thumbnail_file = BytesIO() with Image.open(source) as image: # I've seen some exceptions from the PIL library when trying to save palletted # PNG files to JPEG. Per the google-universe, they suggest converting to RGB first. diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 6d4f81c0ea..bbcd6f2873 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -3,8 +3,8 @@ Django module container for classes and operations related to the "Course Module """ import json import logging -from cStringIO import StringIO from datetime import datetime, timedelta +from io import BytesIO import dateutil.parser from django.conf import settings @@ -1103,7 +1103,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor, LicenseMixin): # bleh, have to parse the XML here to just pull out the url_name attribute # I don't think it's stored anywhere in the instance. - course_file = StringIO(xml_data.encode('ascii', 'ignore')) + course_file = BytesIO(xml_data.encode('ascii', 'ignore')) xml_obj = etree.parse(course_file, parser=edx_xml_parser).getroot() policy_dir = None diff --git a/common/lib/xmodule/xmodule/graders.py b/common/lib/xmodule/xmodule/graders.py index f3bf301d82..cb9ebd6149 100644 --- a/common/lib/xmodule/xmodule/graders.py +++ b/common/lib/xmodule/xmodule/graders.py @@ -2,7 +2,7 @@ Code used to calculate learner grades. """ -from __future__ import division +from __future__ import absolute_import, division import abc import inspect @@ -12,9 +12,11 @@ import sys from collections import OrderedDict from datetime import datetime +import six from contracts import contract from pytz import UTC from django.utils.translation import ugettext_lazy as _ +from six.moves import range # pylint: disable=ungrouped-imports from xmodule.util.misc import get_short_labeler @@ -22,11 +24,10 @@ from xmodule.util.misc import get_short_labeler log = logging.getLogger("edx.courseware") -class ScoreBase(object): +class ScoreBase(six.with_metaclass(abc.ABCMeta, object)): """ Abstract base class for encapsulating fields of values scores. """ - __metaclass__ = abc.ABCMeta @contract(graded="bool", first_attempted="datetime|None") def __init__(self, graded, first_attempted): @@ -179,8 +180,8 @@ def grader_from_conf(conf): raise ValueError("Configuration has no appropriate grader class.") bad_args = invalid_args(subgrader_class.__init__, subgraderconf) - if len(bad_args) > 0: - log.warning("Invalid arguments for a subgrader: %s", bad_args) + if bad_args: + log.warning(u"Invalid arguments for a subgrader: %s", bad_args) for key in bad_args: del subgraderconf[key] @@ -192,12 +193,12 @@ def grader_from_conf(conf): msg = ("Unable to parse grader configuration:\n " + str(subgraderconf) + "\n Error was:\n " + str(error)) - raise ValueError(msg), None, sys.exc_info()[2] + six.reraise(ValueError(msg), None, sys.exc_info()[2]) return WeightedSubsectionsGrader(subgraders) -class CourseGrader(object): +class CourseGrader(six.with_metaclass(abc.ABCMeta, object)): """ A course grader takes the totaled scores for each graded section (that a student has started) in the course. From these scores, the grader calculates an overall percentage @@ -238,8 +239,6 @@ class CourseGrader(object): """ - __metaclass__ = abc.ABCMeta - @abc.abstractmethod def grade(self, grade_sheet, generate_random_scores=False): '''Given a grade sheet, return a dict containing grading information''' @@ -267,10 +266,10 @@ class WeightedSubsectionsGrader(CourseGrader): @property def sum_of_weights(self): - sum = 0 + result = 0 for _, _, weight in self.subgraders: - sum += weight - return sum + result += weight + return result def grade(self, grade_sheet, generate_random_scores=False): total_percent = 0.0 @@ -379,7 +378,7 @@ class AssignmentFormatGrader(CourseGrader): return aggregate_score, dropped_indices def grade(self, grade_sheet, generate_random_scores=False): - scores = grade_sheet.get(self.type, {}).values() + scores = list(grade_sheet.get(self.type, {}).values()) breakdown = [] labeler = get_short_labeler(self.short_label) for i in range(max(self.min_count, len(scores))): @@ -486,9 +485,7 @@ class ShowCorrectness(object): and aggregate subsection and course grades. """ - """ - Constants used to indicate when to show correctness - """ + # Constants used to indicate when to show correctness ALWAYS = "always" PAST_DUE = "past_due" NEVER = "never" diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py index 5205ba35a8..5e7016d8a3 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml.py +++ b/common/lib/xmodule/xmodule/modulestore/xml.py @@ -6,9 +6,9 @@ import os import re import sys import glob - from collections import defaultdict -from cStringIO import StringIO +from io import BytesIO + from fs.osfs import OSFS from importlib import import_module from lxml import etree @@ -450,7 +450,7 @@ class XMLModuleStore(ModuleStoreReadBase): # VS[compat] # TODO (cpennington): Remove this once all fall 2012 courses have # been imported into the cms from xml - course_file = StringIO(clean_out_mako_templating(course_file.read())) + course_file = BytesIO(clean_out_mako_templating(course_file.read())) course_data = etree.parse(course_file, parser=edx_xml_parser).getroot() diff --git a/openedx/core/djangoapps/profile_images/images.py b/openedx/core/djangoapps/profile_images/images.py index d067dcbf8f..aefb28e8b7 100644 --- a/openedx/core/djangoapps/profile_images/images.py +++ b/openedx/core/djangoapps/profile_images/images.py @@ -5,7 +5,7 @@ from __future__ import absolute_import from collections import namedtuple from contextlib import closing -from cStringIO import StringIO +from io import BytesIO import piexif import six @@ -177,7 +177,7 @@ def _create_image_file(image, exif): Note that the file object returned is a django ContentFile which holds data in memory (not on disk). """ - string_io = StringIO() + string_io = BytesIO() # The if/else dance below is required, because PIL raises an exception if # you pass None as the value of the exif kwarg.