From 8702e405898b5033314ddbe4783c2938708a71fe Mon Sep 17 00:00:00 2001 From: Maxim Dorovkov <mdorovkov@users.noreply.github.com> Date: Thu, 16 May 2019 10:09:15 -0400 Subject: [PATCH] INCR-230 - Run python-modernize and isort on common/lib/xmodule/xmodule (#20506) * INCR-230 - Run python-modernize and isort on common/lib/xmodule/xmodule, plus a few minor fixes suggested by Jeremy --- common/lib/xmodule/xmodule/hidden_module.py | 2 + common/lib/xmodule/xmodule/html_checker.py | 2 + common/lib/xmodule/xmodule/html_module.py | 9 ++- .../xmodule/xmodule/library_content_module.py | 24 ++++--- .../xmodule/xmodule/library_root_xblock.py | 10 +-- common/lib/xmodule/xmodule/library_tools.py | 14 +++-- common/lib/xmodule/xmodule/lti_2_util.py | 11 ++-- common/lib/xmodule/xmodule/lti_module.py | 41 ++++++------ common/lib/xmodule/xmodule/mako_module.py | 2 + common/lib/xmodule/xmodule/mongo_utils.py | 4 +- common/lib/xmodule/xmodule/poll_module.py | 9 ++- common/lib/xmodule/xmodule/progress.py | 2 + .../lib/xmodule/xmodule/randomize_module.py | 3 +- common/lib/xmodule/xmodule/raw_module.py | 8 ++- common/lib/xmodule/xmodule/seq_module.py | 13 ++-- common/lib/xmodule/xmodule/services.py | 2 + .../lib/xmodule/xmodule/split_test_module.py | 40 ++++++------ common/lib/xmodule/xmodule/static_content.py | 10 +-- common/lib/xmodule/xmodule/stringify.py | 4 +- common/lib/xmodule/xmodule/studio_editable.py | 5 +- common/lib/xmodule/xmodule/tabs.py | 11 ++-- common/lib/xmodule/xmodule/template_module.py | 5 +- common/lib/xmodule/xmodule/templates.py | 2 + common/lib/xmodule/xmodule/timeinfo.py | 7 ++- common/lib/xmodule/xmodule/validation.py | 9 ++- common/lib/xmodule/xmodule/vertical_block.py | 10 +-- .../lib/xmodule/xmodule/word_cloud_module.py | 14 +++-- common/lib/xmodule/xmodule/wrapper_module.py | 3 +- common/lib/xmodule/xmodule/x_module.py | 62 ++++++++++--------- common/lib/xmodule/xmodule/xml_module.py | 12 ++-- 30 files changed, 211 insertions(+), 139 deletions(-) diff --git a/common/lib/xmodule/xmodule/hidden_module.py b/common/lib/xmodule/xmodule/hidden_module.py index 149390a4ec9..80d37421f27 100644 --- a/common/lib/xmodule/xmodule/hidden_module.py +++ b/common/lib/xmodule/xmodule/hidden_module.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from xmodule.raw_module import RawDescriptor from xmodule.x_module import XModule diff --git a/common/lib/xmodule/xmodule/html_checker.py b/common/lib/xmodule/xmodule/html_checker.py index 76c53a15912..771f47aeaf4 100644 --- a/common/lib/xmodule/xmodule/html_checker.py +++ b/common/lib/xmodule/xmodule/html_checker.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from lxml import etree diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index 2f7ff83a291..adfa3d8c58e 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import copy import logging import os @@ -6,15 +8,16 @@ import sys import textwrap from datetime import datetime +from pkg_resources import resource_string + +import six from django.conf import settings from fs.errors import ResourceNotFound from lxml import etree from path import Path as path -from pkg_resources import resource_string from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, List, Scope, String - from xmodule.contentstore.content import StaticContent from xmodule.editing_module import EditingDescriptor from xmodule.edxnotes_utils import edxnotes @@ -272,7 +275,7 @@ class HtmlDescriptor(HtmlBlock, XmlDescriptor, EditingDescriptor): # pylint: di msg = 'Unable to load file contents at path {0}: {1} '.format( filepath, err) # add more info and re-raise - raise Exception(msg), None, sys.exc_info()[2] + six.reraise(Exception(msg), None, sys.exc_info()[2]) # TODO (vshnayder): make export put things in the right places. diff --git a/common/lib/xmodule/xmodule/library_content_module.py b/common/lib/xmodule/xmodule/library_content_module.py index 13e505dc8bb..4fa2c261d8c 100644 --- a/common/lib/xmodule/xmodule/library_content_module.py +++ b/common/lib/xmodule/xmodule/library_content_module.py @@ -2,23 +2,27 @@ """ LibraryContent: The XBlock used to include blocks from a library in a course. """ +from __future__ import absolute_import + import json import logging import random from copy import copy from gettext import ngettext +from pkg_resources import resource_string + +import six +from capa.responsetypes import registry from lazy import lazy from lxml import etree from opaque_keys.edx.locator import LibraryLocator -from pkg_resources import resource_string from six import text_type +from six.moves import zip from web_fragments.fragment import Fragment from webob import Response from xblock.core import XBlock from xblock.fields import Integer, List, Scope, String - -from capa.responsetypes import registry from xmodule.studio_editable import StudioEditableDescriptor, StudioEditableModule from xmodule.validation import StudioValidation, StudioValidationMessage from xmodule.x_module import STUDENT_VIEW, XModule @@ -198,7 +202,7 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule): Helper method to publish an event for analytics purposes """ event_data = { - "location": unicode(self.location), + "location": six.text_type(self.location), "result": result, "previous_count": getattr(self, "_last_event_result_count", len(self.selected)), "max_count": self.max_count, @@ -439,7 +443,7 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe """ Copy any overrides the user has made on blocks in this library. """ - for field in source.fields.itervalues(): + for field in six.itervalues(source.fields): if field.scope == Scope.settings and field.is_set_on(source): setattr(dest, field.name, field.read_from(source)) if source.has_children: @@ -476,7 +480,7 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe """ latest_version = lib_tools.get_library_version(library_key) if latest_version is not None: - if version is None or version != unicode(latest_version): + if version is None or version != six.text_type(latest_version): validation.set_summary( StudioValidationMessage( StudioValidationMessage.WARNING, @@ -586,13 +590,13 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe user_perms = self.runtime.service(self, 'studio_user_permissions') all_libraries = [ (key, name) for key, name in lib_tools.list_available_libraries() - if user_perms.can_read(key) or self.source_library_id == unicode(key) + if user_perms.can_read(key) or self.source_library_id == six.text_type(key) ] all_libraries.sort(key=lambda entry: entry[1]) # Sort by name if self.source_library_id and self.source_library_key not in [entry[0] for entry in all_libraries]: all_libraries.append((self.source_library_id, _(u"Invalid Library"))) all_libraries = [(u"", _("No Library Selected"))] + all_libraries - values = [{"display_name": name, "value": unicode(key)} for key, name in all_libraries] + values = [{"display_name": name, "value": six.text_type(key)} for key, name in all_libraries] return values def editor_saved(self, user, old_metadata, old_content): @@ -645,11 +649,11 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe for child in self.get_children(): self.runtime.add_block_as_child_node(child, xml_object) # Set node attributes based on our fields. - for field_name, field in self.fields.iteritems(): # pylint: disable=no-member + for field_name, field in six.iteritems(self.fields): # pylint: disable=no-member if field_name in ('children', 'parent', 'content'): continue if field.is_set_on(self): - xml_object.set(field_name, unicode(field.read_from(self))) + xml_object.set(field_name, six.text_type(field.read_from(self))) return xml_object diff --git a/common/lib/xmodule/xmodule/library_root_xblock.py b/common/lib/xmodule/xmodule/library_root_xblock.py index d5cba5e2713..6494bc4440f 100644 --- a/common/lib/xmodule/xmodule/library_root_xblock.py +++ b/common/lib/xmodule/xmodule/library_root_xblock.py @@ -1,12 +1,14 @@ """ 'library' XBlock (LibraryRoot) """ +from __future__ import absolute_import + import logging +import six from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, List, Scope, String - from xmodule.studio_editable import StudioEditableModule log = logging.getLogger(__name__) @@ -49,7 +51,7 @@ class LibraryRoot(XBlock): return u"Library: {}".format(self.display_name) def __str__(self): - return unicode(self).encode('utf-8') + return six.text_type(self).encode('utf-8') def author_view(self, context): """ @@ -90,7 +92,7 @@ class LibraryRoot(XBlock): child = self.runtime.get_block(child_key) child_view_name = StudioEditableModule.get_preview_view_name(child) - if unicode(child.location) == force_render: + if six.text_type(child.location) == force_render: child_context['show_preview'] = True if child_context['show_preview']: @@ -100,7 +102,7 @@ class LibraryRoot(XBlock): fragment.add_fragment_resources(rendered_child) contents.append({ - 'id': unicode(child.location), + 'id': six.text_type(child.location), 'content': rendered_child.content, }) diff --git a/common/lib/xmodule/xmodule/library_tools.py b/common/lib/xmodule/xmodule/library_tools.py index 3c4682a8b96..1156f0f787f 100644 --- a/common/lib/xmodule/xmodule/library_tools.py +++ b/common/lib/xmodule/xmodule/library_tools.py @@ -1,10 +1,12 @@ """ XBlock runtime services for LibraryContentModule """ +from __future__ import absolute_import + +import six from django.core.exceptions import PermissionDenied from opaque_keys.edx.locator import LibraryLocator, LibraryUsageLocator from search.search_engine_base import SearchEngine - from xmodule.capa_module import ProblemBlock from xmodule.library_content_module import ANY_CAPA_TYPE_VALUE from xmodule.modulestore import ModuleStoreEnum @@ -70,9 +72,9 @@ class LibraryToolsService(object): """ Basic information about the given block """ orig_key, orig_version = self.store.get_block_original_usage(usage_key) return { - "usage_key": unicode(usage_key), - "original_usage_key": unicode(orig_key) if orig_key else None, - "original_usage_version": unicode(orig_version) if orig_version else None, + "usage_key": six.text_type(usage_key), + "original_usage_key": six.text_type(orig_key) if orig_key else None, + "original_usage_version": six.text_type(orig_version) if orig_version else None, } result_json = [] @@ -98,7 +100,7 @@ class LibraryToolsService(object): search_engine = SearchEngine.get_search_engine(index="library_index") if search_engine: filter_clause = { - "library": unicode(normalize_key_for_search(library.location.library_key)), + "library": six.text_type(normalize_key_for_search(library.location.library_key)), "content_type": ProblemBlock.INDEX_CONTENT_TYPE, "problem_types": capa_type } @@ -161,7 +163,7 @@ class LibraryToolsService(object): source_blocks.extend(library.children) with self.store.bulk_operations(dest_block.location.course_key): - dest_block.source_library_version = unicode(library.location.library_key.version_guid) + dest_block.source_library_version = six.text_type(library.location.library_key.version_guid) self.store.update_item(dest_block, user_id) head_validation = not version dest_block.children = self.store.copy_from_template( diff --git a/common/lib/xmodule/xmodule/lti_2_util.py b/common/lib/xmodule/xmodule/lti_2_util.py index e57a6bdbfb6..adf5708fdd3 100644 --- a/common/lib/xmodule/xmodule/lti_2_util.py +++ b/common/lib/xmodule/xmodule/lti_2_util.py @@ -3,14 +3,17 @@ A mixin class for LTI 2.0 functionality. This is really just done to refactor the code to keep the LTIModule class from getting too big """ +from __future__ import absolute_import + import base64 import hashlib import json import logging import re -import urllib import mock +import six +import six.moves.urllib.parse from oauthlib.oauth1 import Client from six import text_type from webob import Response @@ -106,16 +109,16 @@ class LTI20ModuleMixin(object): """ sha1 = hashlib.sha1() sha1.update(request.body) - oauth_body_hash = unicode(base64.b64encode(sha1.digest())) + oauth_body_hash = six.text_type(base64.b64encode(sha1.digest())) log.debug("[LTI] oauth_body_hash = {}".format(oauth_body_hash)) client_key, client_secret = self.get_client_key_secret() client = Client(client_key, client_secret) mock_request = mock.Mock( - uri=unicode(urllib.unquote(request.url)), + uri=six.text_type(six.moves.urllib.parse.unquote(request.url)), headers=request.headers, body=u"", decoded_body=u"", - http_method=unicode(request.method), + http_method=six.text_type(request.method), ) params = client.get_oauth_params(mock_request) mock_request.oauth_params = params diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py index 6bd104b39a9..248adfb58bb 100644 --- a/common/lib/xmodule/xmodule/lti_module.py +++ b/common/lib/xmodule/xmodule/lti_module.py @@ -53,26 +53,29 @@ What is supported: GET / PUT / DELETE HTTP methods respectively """ +from __future__ import absolute_import + import base64 import datetime import hashlib import logging import textwrap -import urllib from xml.sax.saxutils import escape +from pkg_resources import resource_string + import bleach import mock import oauthlib.oauth1 -from pytz import UTC +import six +import six.moves.urllib.parse from lxml import etree from oauthlib.oauth1.rfc5849 import signature -from pkg_resources import resource_string +from pytz import UTC from six import text_type from webob import Response from xblock.core import List, Scope, String, XBlock from xblock.fields import Boolean, Float - from xmodule.editing_module import MetadataOnlyEditingDescriptor from xmodule.lti_2_util import LTI20ModuleMixin, LTIError from xmodule.raw_module import EmptyDataRawDescriptor @@ -397,7 +400,7 @@ class LTIModule(LTIFields, LTI20ModuleMixin, XModule): if param_name not in PARAMETERS: param_name = 'custom_' + param_name - custom_parameters[unicode(param_name)] = unicode(param_value) + custom_parameters[six.text_type(param_name)] = six.text_type(param_value) return self.oauth_params( custom_parameters, @@ -460,7 +463,7 @@ class LTIModule(LTIFields, LTI20ModuleMixin, XModule): def get_user_id(self): user_id = self.runtime.anonymous_student_id assert user_id is not None - return unicode(urllib.quote(user_id)) + return six.text_type(six.moves.urllib.parse.quote(user_id)) def get_outcome_service_url(self, service_name="grade_handler"): """ @@ -506,7 +509,7 @@ class LTIModule(LTIFields, LTI20ModuleMixin, XModule): i4x-2-3-lti-31de800015cf4afb973356dbe81496df this part of resource_link_id: makes resource_link_id to be unique among courses inside same system. """ - return unicode(urllib.quote("{}-{}".format(self.system.hostname, self.location.html_id()))) + return six.text_type(six.moves.urllib.parse.quote("{}-{}".format(self.system.hostname, self.location.html_id()))) def get_lis_result_sourcedid(self): """ @@ -518,7 +521,7 @@ class LTIModule(LTIFields, LTI20ModuleMixin, XModule): This field is generally optional, but is required for grading. """ return "{context}:{resource_link}:{user_id}".format( - context=urllib.quote(self.context_id), + context=six.moves.urllib.parse.quote(self.context_id), resource_link=self.get_resource_link_id(), user_id=self.get_user_id() ) @@ -619,7 +622,7 @@ class LTIModule(LTIFields, LTI20ModuleMixin, XModule): try: __, headers, __ = client.sign( - unicode(self.launch_url.strip()), + six.text_type(self.launch_url.strip()), http_method=u'POST', body=body, headers=headers) @@ -649,7 +652,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} # so '='' becomes '%3D'. # We send form via browser, so browser will encode it again, # So we need to decode signature back: - params[u'oauth_signature'] = urllib.unquote(params[u'oauth_signature']).decode('utf8') + params[u'oauth_signature'] = six.moves.urllib.parse.unquote(params[u'oauth_signature']).decode('utf8') # Add LTI parameters to OAuth parameters for sending in form. params.update(body) @@ -753,7 +756,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} log.debug("[LTI]: " + error_message) return Response(response_xml_template.format(**failure_values), content_type="application/xml") - real_user = self.system.get_real_user(urllib.unquote(sourcedId.split(':')[-1])) + real_user = self.system.get_real_user(six.moves.urllib.parse.unquote(sourcedId.split(':')[-1])) if not real_user: # that means we can't save to database, as we do not have real user id. failure_values['imsx_messageIdentifier'] = escape(imsx_messageIdentifier) failure_values['imsx_description'] = "User not found." @@ -822,7 +825,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} client_key, client_secret = self.get_client_key_secret() headers = { - 'Authorization': unicode(request.headers.get('Authorization')), + 'Authorization': six.text_type(request.headers.get('Authorization')), 'Content-Type': content_type, } @@ -833,15 +836,15 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} oauth_headers = dict(oauth_params) oauth_signature = oauth_headers.pop('oauth_signature') mock_request_lti_1 = mock.Mock( - uri=unicode(urllib.unquote(self.get_outcome_service_url())), - http_method=unicode(request.method), - params=oauth_headers.items(), + uri=six.text_type(six.moves.urllib.parse.unquote(self.get_outcome_service_url())), + http_method=six.text_type(request.method), + params=list(oauth_headers.items()), signature=oauth_signature ) mock_request_lti_2 = mock.Mock( - uri=unicode(urllib.unquote(request.url)), - http_method=unicode(request.method), - params=oauth_headers.items(), + uri=six.text_type(six.moves.urllib.parse.unquote(request.url)), + http_method=six.text_type(request.method), + params=list(oauth_headers.items()), signature=oauth_signature ) if oauth_body_hash != oauth_headers.get('oauth_body_hash'): @@ -862,7 +865,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} "headers:{} url:{} method:{}".format( oauth_headers, self.get_outcome_service_url(), - unicode(request.method) + six.text_type(request.method) )) raise LTIError("OAuth signature verification has failed.") diff --git a/common/lib/xmodule/xmodule/mako_module.py b/common/lib/xmodule/xmodule/mako_module.py index 5dc123eed4a..651d43343c0 100644 --- a/common/lib/xmodule/xmodule/mako_module.py +++ b/common/lib/xmodule/xmodule/mako_module.py @@ -1,6 +1,8 @@ """ Code to handle mako templating for XModules and XBlocks. """ +from __future__ import absolute_import + from web_fragments.fragment import Fragment from .x_module import DescriptorSystem, XModuleDescriptor, shim_xmodule_js diff --git a/common/lib/xmodule/xmodule/mongo_utils.py b/common/lib/xmodule/xmodule/mongo_utils.py index ea6a37c9f68..1704f883a01 100644 --- a/common/lib/xmodule/xmodule/mongo_utils.py +++ b/common/lib/xmodule/xmodule/mongo_utils.py @@ -1,11 +1,13 @@ """ Common MongoDB connection functions. """ +from __future__ import absolute_import + import logging import pymongo -from pymongo import ReadPreference from mongodb_proxy import MongoProxy +from pymongo import ReadPreference logger = logging.getLogger(__name__) # pylint: disable=invalid-name diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py index f0eb18f7873..31e72624184 100644 --- a/common/lib/xmodule/xmodule/poll_module.py +++ b/common/lib/xmodule/xmodule/poll_module.py @@ -6,17 +6,20 @@ If student does not yet anwered - Question with set of choices. If student have answered - Question with statistics for each answers. """ +from __future__ import absolute_import + import cgi import json import logging from collections import OrderedDict from copy import deepcopy -from lxml import etree from pkg_resources import resource_string -from xblock.fields import Boolean, Dict, List, Scope, String +import six +from lxml import etree from openedx.core.djangolib.markup import Text +from xblock.fields import Boolean, Dict, List, Scope, String from xmodule.mako_module import MakoModuleDescriptor from xmodule.stringify import stringify_children from xmodule.x_module import XModule @@ -220,7 +223,7 @@ class PollDescriptor(PollFields, MakoModuleDescriptor, XmlDescriptor): def add_child(xml_obj, answer): # Escape answer text before adding to xml tree. - answer_text = unicode(Text(answer['text'])) + answer_text = six.text_type(Text(answer['text'])) child_str = u'<{tag_name} id="{id}">{text}</{tag_name}>'.format( tag_name=self._child_tag_name, id=answer['id'], text=answer_text) diff --git a/common/lib/xmodule/xmodule/progress.py b/common/lib/xmodule/xmodule/progress.py index afb05a5c2e6..9f01348abaf 100644 --- a/common/lib/xmodule/xmodule/progress.py +++ b/common/lib/xmodule/xmodule/progress.py @@ -5,6 +5,8 @@ For most subclassing needs, you should only need to reimplement frac() and __str__(). ''' +from __future__ import absolute_import + import numbers diff --git a/common/lib/xmodule/xmodule/randomize_module.py b/common/lib/xmodule/xmodule/randomize_module.py index 78d98e068af..2a5fdf92034 100644 --- a/common/lib/xmodule/xmodule/randomize_module.py +++ b/common/lib/xmodule/xmodule/randomize_module.py @@ -1,10 +1,11 @@ +from __future__ import absolute_import + import logging import random from lxml import etree from web_fragments.fragment import Fragment from xblock.fields import Integer, Scope - from xmodule.seq_module import SequenceDescriptor from xmodule.x_module import STUDENT_VIEW, XModule diff --git a/common/lib/xmodule/xmodule/raw_module.py b/common/lib/xmodule/xmodule/raw_module.py index 92d7dd56158..ce608be835d 100644 --- a/common/lib/xmodule/xmodule/raw_module.py +++ b/common/lib/xmodule/xmodule/raw_module.py @@ -1,12 +1,14 @@ +from __future__ import absolute_import + import logging -from exceptions import SerializationError from lxml import etree from xblock.fields import Scope, String - from xmodule.editing_module import XMLEditingDescriptor from xmodule.xml_module import XmlDescriptor +from .exceptions import SerializationError + log = logging.getLogger(__name__) @@ -78,7 +80,7 @@ class EmptyDataRawDescriptor(XmlDescriptor, XMLEditingDescriptor): @classmethod def definition_from_xml(cls, xml_object, system): - if len(xml_object) == 0 and len(xml_object.items()) == 0: + if len(xml_object) == 0 and len(list(xml_object.items())) == 0: return {'data': ''}, [] return {'data': etree.tostring(xml_object, pretty_print=True, encoding='unicode')}, [] diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index 553d74953f4..82a66bd3c8f 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -3,14 +3,19 @@ xModule implementation of a learning sequence """ # pylint: disable=abstract-method +from __future__ import absolute_import + import collections import json import logging from datetime import datetime +from functools import reduce + +from pkg_resources import resource_string +import six from lxml import etree from opaque_keys.edx.keys import UsageKey -from pkg_resources import resource_string from pytz import UTC from six import text_type from web_fragments.fragment import Fragment @@ -22,7 +27,7 @@ from .exceptions import NotFoundError from .fields import Date from .mako_module import MakoModuleDescriptor from .progress import Progress -from .x_module import STUDENT_VIEW, PUBLIC_VIEW, XModule +from .x_module import PUBLIC_VIEW, STUDENT_VIEW, XModule from .xml_module import XmlDescriptor log = logging.getLogger(__name__) @@ -536,7 +541,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): """ if not newrelic: return - newrelic.agent.add_custom_parameter('seq.block_id', unicode(self.location)) + newrelic.agent.add_custom_parameter('seq.block_id', six.text_type(self.location)) newrelic.agent.add_custom_parameter('seq.display_name', self.display_name or '') newrelic.agent.add_custom_parameter('seq.position', self.position) newrelic.agent.add_custom_parameter('seq.is_time_limited', self.is_time_limited) @@ -575,7 +580,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): if 1 <= self.position <= len(display_items): # Basic info about the Unit... current = display_items[self.position - 1] - newrelic.agent.add_custom_parameter('seq.current.block_id', unicode(current.location)) + newrelic.agent.add_custom_parameter('seq.current.block_id', six.text_type(current.location)) newrelic.agent.add_custom_parameter('seq.current.display_name', current.display_name or '') # Examining all items inside the Unit (or split_test, conditional, etc.) diff --git a/common/lib/xmodule/xmodule/services.py b/common/lib/xmodule/xmodule/services.py index 05e4bfb6532..95cea2a4233 100644 --- a/common/lib/xmodule/xmodule/services.py +++ b/common/lib/xmodule/xmodule/services.py @@ -1,6 +1,8 @@ """ Module contains various XModule/XBlock services """ +from __future__ import absolute_import + import inspect from config_models.models import ConfigurationModel diff --git a/common/lib/xmodule/xmodule/split_test_module.py b/common/lib/xmodule/xmodule/split_test_module.py index 7040ce6de8a..e9a965bc387 100644 --- a/common/lib/xmodule/xmodule/split_test_module.py +++ b/common/lib/xmodule/xmodule/split_test_module.py @@ -2,25 +2,27 @@ Module for running content split tests """ -import logging +from __future__ import absolute_import + import json -from webob import Response -from uuid import uuid4 +import logging +from functools import reduce from operator import itemgetter +from uuid import uuid4 -from xmodule.progress import Progress -from xmodule.seq_module import SequenceDescriptor -from xmodule.studio_editable import StudioEditableModule, StudioEditableDescriptor -from xmodule.x_module import XModule, module_attr, STUDENT_VIEW -from xmodule.validation import StudioValidation, StudioValidationMessage -from xmodule.modulestore.inheritance import UserPartitionList - +import six from lxml import etree from six import text_type - from web_fragments.fragment import Fragment +from webob import Response from xblock.core import XBlock -from xblock.fields import Scope, Integer, String, ReferenceValueDict +from xblock.fields import Integer, ReferenceValueDict, Scope, String +from xmodule.modulestore.inheritance import UserPartitionList +from xmodule.progress import Progress +from xmodule.seq_module import SequenceDescriptor +from xmodule.studio_editable import StudioEditableDescriptor, StudioEditableModule +from xmodule.validation import StudioValidation, StudioValidationMessage +from xmodule.x_module import STUDENT_VIEW, XModule, module_attr log = logging.getLogger('edx.' + __name__) @@ -179,7 +181,7 @@ class SplitTestModule(SplitTestFields, XModule, StudioEditableModule): child_descriptor = self.get_child_descriptor_by_location(child_location) else: # Oops. Config error. - log.debug("configuration error in split test module: invalid group_id %r (not one of %r). Showing error", str_group_id, self.group_id_to_child.keys()) + log.debug("configuration error in split test module: invalid group_id %r (not one of %r). Showing error", str_group_id, list(self.group_id_to_child.keys())) if child_descriptor is None: # Peak confusion is great. Now that we set child_descriptor, @@ -338,7 +340,7 @@ class SplitTestModule(SplitTestFields, XModule, StudioEditableModule): except Exception: log.info( "Can't get usage_id of Nonetype object in course {course_key}".format( - course_key=unicode(self.location.course_key) + course_key=six.text_type(self.location.course_key) ) ) raise @@ -362,7 +364,7 @@ class SplitTestModule(SplitTestFields, XModule, StudioEditableModule): user_partition = self.descriptor.get_selected_partition() if user_partition: for group in user_partition.groups: - group_id = unicode(group.id) + group_id = six.text_type(group.id) child_location = self.group_id_to_child.get(group_id, None) if child_location == vertical.location: return (group.name, group.id) @@ -534,7 +536,7 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes # Compute the active children in the order specified by the user partition active_children = [] for group in user_partition.groups: - group_id = unicode(group.id) + group_id = six.text_type(group.id) child_location = self.group_id_to_child.get(group_id, None) child = get_child_descriptor(child_location) if child: @@ -657,7 +659,7 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes changed = False for group in user_partition.groups: - str_group_id = unicode(group.id) + str_group_id = six.text_type(group.id) if str_group_id not in self.group_id_to_child: user_id = self.runtime.service(self, 'user').get_current_user().opt_attrs['edx-platform.user_id'] self._create_vertical_for_group(group, user_id) @@ -679,7 +681,7 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes user_partition = self.get_selected_partition() if user_partition: group_configuration_url = "{url}#{configuration_id}".format( - url='/group_configurations/' + unicode(self.location.course_key), + url='/group_configurations/' + six.text_type(self.location.course_key), configuration_id=str(user_partition.id) ) @@ -708,6 +710,6 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes runtime=self.system, ) self.children.append(dest_usage_key) # pylint: disable=no-member - self.group_id_to_child[unicode(group.id)] = dest_usage_key + self.group_id_to_child[six.text_type(group.id)] = dest_usage_key tooltip_title = module_attr('tooltip_title') diff --git a/common/lib/xmodule/xmodule/static_content.py b/common/lib/xmodule/xmodule/static_content.py index b89e119f516..c84475bcc60 100755 --- a/common/lib/xmodule/xmodule/static_content.py +++ b/common/lib/xmodule/xmodule/static_content.py @@ -4,6 +4,8 @@ This module has utility functions for gathering up the static content that is defined by XModules and XModuleDescriptors (javascript and css) """ +from __future__ import absolute_import + import errno import hashlib import json @@ -14,12 +16,12 @@ import textwrap from collections import defaultdict import django +import six from docopt import docopt from path import Path as path - from xmodule.x_module import XModuleDescriptor -from capa_module import ProblemBlock +from .capa_module import ProblemBlock LOG = logging.getLogger(__name__) @@ -183,7 +185,7 @@ def _write_files(output_root, contents, generated_suffix_map=None): for extra_file in to_delete: (output_root / extra_file).remove_p() - for filename, file_content in contents.iteritems(): + for filename, file_content in six.iteritems(contents): output_file = output_root / filename not_file = not output_file.isfile() @@ -209,7 +211,7 @@ def write_webpack(output_file, module_files, descriptor_files): config = { 'entry': {} } - for (owner, files) in module_files.items() + descriptor_files.items(): + for (owner, files) in list(module_files.items()) + list(descriptor_files.items()): unique_files = sorted(set('./{}'.format(file) for file in files)) if len(unique_files) == 1: unique_files = unique_files[0] diff --git a/common/lib/xmodule/xmodule/stringify.py b/common/lib/xmodule/xmodule/stringify.py index 35587d3b092..fc8180c3d12 100644 --- a/common/lib/xmodule/xmodule/stringify.py +++ b/common/lib/xmodule/xmodule/stringify.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import + from lxml import etree @@ -27,4 +29,4 @@ def stringify_children(node): parts.append(etree.tostring(c, with_tail=True, encoding='unicode')) # filter removes possible Nones in texts and tails - return u''.join(filter(None, parts)) + return u''.join([part for part in parts if part]) diff --git a/common/lib/xmodule/xmodule/studio_editable.py b/common/lib/xmodule/xmodule/studio_editable.py index 0261f58ec57..aa7c93154be 100644 --- a/common/lib/xmodule/xmodule/studio_editable.py +++ b/common/lib/xmodule/xmodule/studio_editable.py @@ -1,6 +1,9 @@ """ Mixin to support editing in Studio. """ +from __future__ import absolute_import + +import six from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW, module_attr @@ -27,7 +30,7 @@ class StudioEditableBlock(object): fragment.add_fragment_resources(rendered_child) contents.append({ - 'id': unicode(child.location), + 'id': six.text_type(child.location), 'content': rendered_child.content }) diff --git a/common/lib/xmodule/xmodule/tabs.py b/common/lib/xmodule/xmodule/tabs.py index e634bae879d..253e6d640b3 100644 --- a/common/lib/xmodule/xmodule/tabs.py +++ b/common/lib/xmodule/xmodule/tabs.py @@ -1,15 +1,17 @@ """ Implement CourseTab """ +from __future__ import absolute_import + import logging from abc import ABCMeta +import six from django.core.files.storage import get_storage_class +from openedx.core.lib.plugins import PluginError from six import text_type from xblock.fields import List -from openedx.core.lib.plugins import PluginError - log = logging.getLogger("edx.courseware") # Make '_' a no-op so we can scrape strings. Using lambda instead of @@ -20,14 +22,13 @@ _ = lambda text: text READ_ONLY_COURSE_TAB_ATTRIBUTES = ['type'] -class CourseTab(object): +class CourseTab(six.with_metaclass(ABCMeta, object)): """ The Course Tab class is a data abstraction for all tabs (i.e., course navigation links) within a course. It is an abstract class - to be inherited by various tab types. Derived classes are expected to override methods as needed. When a new tab class is created, it should define the type and add it in this class' factory method. """ - __metaclass__ = ABCMeta # Class property that specifies the type of the tab. It is generally a constant value for a # subclass, shared by all instances of the subclass. @@ -291,7 +292,7 @@ class TabFragmentViewMixin(object): """ Renders this tab to a web fragment. """ - return self.fragment_view.render_to_fragment(request, course_id=unicode(course.id), **kwargs) + return self.fragment_view.render_to_fragment(request, course_id=six.text_type(course.id), **kwargs) class StaticTab(CourseTab): diff --git a/common/lib/xmodule/xmodule/template_module.py b/common/lib/xmodule/xmodule/template_module.py index 908b90e8697..04bee9b9c0e 100644 --- a/common/lib/xmodule/xmodule/template_module.py +++ b/common/lib/xmodule/xmodule/template_module.py @@ -1,9 +1,10 @@ """ Template module """ +from __future__ import absolute_import + from lxml import etree from mako.template import Template - from xmodule.raw_module import RawDescriptor from xmodule.x_module import DEPRECATION_VSCOMPAT_EVENT, XModule @@ -55,7 +56,7 @@ class CustomTagDescriptor(RawDescriptor): raise Exception("Could not find impl attribute in customtag {0}" .format(self.location)) - params = dict(xmltree.items()) + params = dict(list(xmltree.items())) # cdodge: look up the template as a module template_loc = self.location.replace(category='custom_tag_template', name=template_name) diff --git a/common/lib/xmodule/xmodule/templates.py b/common/lib/xmodule/xmodule/templates.py index 3df220b1a7c..ac1cbf29178 100644 --- a/common/lib/xmodule/xmodule/templates.py +++ b/common/lib/xmodule/xmodule/templates.py @@ -9,6 +9,8 @@ samples. """ # should this move to cms since it's really only for module crud? +from __future__ import absolute_import + import logging from collections import defaultdict diff --git a/common/lib/xmodule/xmodule/timeinfo.py b/common/lib/xmodule/xmodule/timeinfo.py index 17ac38de52f..d9f4a6abc7a 100644 --- a/common/lib/xmodule/xmodule/timeinfo.py +++ b/common/lib/xmodule/xmodule/timeinfo.py @@ -1,5 +1,10 @@ +from __future__ import absolute_import + import logging + +import six from xmodule.fields import Timedelta + log = logging.getLogger(__name__) @@ -24,7 +29,7 @@ class TimeInfo(object): self.display_due_date = None if grace_period_string_or_timedelta is not None and self.display_due_date: - if isinstance(grace_period_string_or_timedelta, basestring): + if isinstance(grace_period_string_or_timedelta, six.string_types): try: self.grace_period = TimeInfo._delta_standin.from_json(grace_period_string_or_timedelta) except: diff --git a/common/lib/xmodule/xmodule/validation.py b/common/lib/xmodule/xmodule/validation.py index 2b6d4fce59b..abbfea93f76 100644 --- a/common/lib/xmodule/xmodule/validation.py +++ b/common/lib/xmodule/xmodule/validation.py @@ -1,6 +1,9 @@ """ Extension of XBlock Validation class to include information for presentation in Studio. """ +from __future__ import absolute_import + +import six from xblock.validation import Validation, ValidationMessage @@ -32,15 +35,15 @@ class StudioValidationMessage(ValidationMessage): """ super(StudioValidationMessage, self).__init__(message_type, message_text) if action_label is not None: - if not isinstance(action_label, unicode): + if not isinstance(action_label, six.text_type): raise TypeError("Action label must be unicode.") self.action_label = action_label if action_class is not None: - if not isinstance(action_class, basestring): + if not isinstance(action_class, six.string_types): raise TypeError("Action class must be a string.") self.action_class = action_class if action_runtime_event is not None: - if not isinstance(action_runtime_event, basestring): + if not isinstance(action_runtime_event, six.string_types): raise TypeError("Action runtime event must be a string.") self.action_runtime_event = action_runtime_event diff --git a/common/lib/xmodule/xmodule/vertical_block.py b/common/lib/xmodule/xmodule/vertical_block.py index 0d646337a62..ab3f7a9800e 100644 --- a/common/lib/xmodule/xmodule/vertical_block.py +++ b/common/lib/xmodule/xmodule/vertical_block.py @@ -4,20 +4,20 @@ VerticalBlock - an XBlock which renders its children in a column. from __future__ import absolute_import, division, print_function, unicode_literals -from copy import copy import logging +from copy import copy +from functools import reduce -from lxml import etree import six +from lxml import etree from web_fragments.fragment import Fragment from xblock.core import XBlock - from xmodule.mako_module import MakoTemplateBlockBase from xmodule.progress import Progress from xmodule.seq_module import SequenceFields from xmodule.studio_editable import StudioEditableBlock from xmodule.util.xmodule_django import add_webpack_to_fragment -from xmodule.x_module import STUDENT_VIEW, PUBLIC_VIEW, XModuleFields +from xmodule.x_module import PUBLIC_VIEW, STUDENT_VIEW, XModuleFields from xmodule.xml_module import XmlParserMixin log = logging.getLogger(__name__) @@ -101,7 +101,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse 'show_bookmark_button': child_context.get('show_bookmark_button', not is_child_of_vertical), 'bookmarked': child_context['bookmarked'], 'bookmark_id': u"{},{}".format( - child_context['username'], unicode(self.location)), # pylint: disable=no-member + child_context['username'], six.text_type(self.location)), # pylint: disable=no-member }) fragment.add_content(self.system.render_template('vert_module.html', fragment_context)) diff --git a/common/lib/xmodule/xmodule/word_cloud_module.py b/common/lib/xmodule/xmodule/word_cloud_module.py index 23eae87c986..f3a80110627 100644 --- a/common/lib/xmodule/xmodule/word_cloud_module.py +++ b/common/lib/xmodule/xmodule/word_cloud_module.py @@ -6,13 +6,17 @@ If student does not yet answered - `num_inputs` numbers of text inputs. If student have answered - words he entered and cloud. """ +from __future__ import absolute_import + import json import logging from pkg_resources import resource_string + +import six +from six.moves import map from web_fragments.fragment import Fragment from xblock.fields import Boolean, Dict, Integer, List, Scope, String - from xmodule.editing_module import MetadataOnlyEditingDescriptor from xmodule.raw_module import EmptyDataRawDescriptor from xmodule.x_module import XModule @@ -98,7 +102,7 @@ class WordCloudModule(WordCloudFields, XModule): def get_state(self): """Return success json answer for client.""" if self.submitted: - total_count = sum(self.all_words.itervalues()) + total_count = sum(six.itervalues(self.all_words)) return json.dumps({ 'status': 'success', 'submitted': True, @@ -144,7 +148,7 @@ class WordCloudModule(WordCloudFields, XModule): """ list_to_return = [] percents = 0 - for num, word_tuple in enumerate(top_words.iteritems()): + for num, word_tuple in enumerate(six.iteritems(top_words)): if num == len(top_words) - 1: percent = 100 - percents else: @@ -171,7 +175,7 @@ class WordCloudModule(WordCloudFields, XModule): """ return dict( sorted( - dict_obj.items(), + list(dict_obj.items()), key=lambda x: x[1], reverse=True )[:amount] @@ -197,7 +201,7 @@ class WordCloudModule(WordCloudFields, XModule): # Student words from client. # FIXME: we must use raw JSON, not a post data (multipart/form-data) raw_student_words = data.getall('student_words[]') - student_words = filter(None, map(self.good_word, raw_student_words)) + student_words = [word for word in map(self.good_word, raw_student_words) if word] self.student_words = student_words diff --git a/common/lib/xmodule/xmodule/wrapper_module.py b/common/lib/xmodule/xmodule/wrapper_module.py index 6c03dd59d35..8b5b7cf875f 100644 --- a/common/lib/xmodule/xmodule/wrapper_module.py +++ b/common/lib/xmodule/xmodule/wrapper_module.py @@ -1,8 +1,9 @@ # Same as vertical, # But w/o css delimiters between children -from xmodule.vertical_block import VerticalBlock +from __future__ import absolute_import +from xmodule.vertical_block import VerticalBlock # HACK: This shouldn't be hard-coded to two types # OBSOLETE: This obsoletes 'type' diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 2760bc83f17..360e87529a2 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1,45 +1,49 @@ +from __future__ import absolute_import + import logging import os import sys import time -import yaml +from collections import namedtuple +from functools import partial + +from pkg_resources import resource_exists, resource_isdir, resource_listdir, resource_string +import six +import yaml from contracts import contract, new_contract -from functools import partial +from lazy import lazy from lxml import etree -from collections import namedtuple -from pkg_resources import ( - resource_exists, - resource_listdir, - resource_string, - resource_isdir, -) +from opaque_keys.edx.asides import AsideDefinitionKeyV2, AsideUsageKeyV2 +from opaque_keys.edx.keys import UsageKey +from openedx.core.djangolib.markup import HTML from six import text_type +from six.moves import map from web_fragments.fragment import Fragment from webob import Response from webob.multidict import MultiDict -from lazy import lazy - from xblock.core import XBlock, XBlockAside from xblock.fields import ( - Scope, Integer, Float, List, - String, Dict, ScopeIds, Reference, ReferenceList, - ReferenceValueDict, UserScope + Dict, + Float, + Integer, + List, + Reference, + ReferenceList, + ReferenceValueDict, + Scope, + ScopeIds, + String, + UserScope ) - -from xblock.runtime import Runtime, IdReader, IdGenerator +from xblock.runtime import IdGenerator, IdReader, Runtime from xmodule import block_metadata_utils -from xmodule.fields import RelativeTime from xmodule.errortracker import exc_info_to_str +from xmodule.exceptions import UndefinedContext +from xmodule.fields import RelativeTime from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.util.xmodule_django import add_webpack_to_fragment -from opaque_keys.edx.keys import UsageKey -from opaque_keys.edx.asides import AsideUsageKeyV2, AsideDefinitionKeyV2 -from xmodule.exceptions import UndefinedContext - -from openedx.core.djangolib.markup import HTML - log = logging.getLogger(__name__) XMODULE_METRIC_NAME = 'edxapp.xmodule' @@ -908,9 +912,9 @@ class XModuleToXBlockMixin(object): # WebOb requests have multiple entries for uploaded files. handle_ajax # expects a single entry as a list. request_post = MultiDict(request.POST) - for key in set(request.POST.iterkeys()): + for key in set(six.iterkeys(request.POST)): if hasattr(request.POST[key], "file"): - request_post[key] = map(FileObjForWebobFiles, request.POST.getall(key)) + request_post[key] = list(map(FileObjForWebobFiles, request.POST.getall(key))) response_data = self.handle_ajax(suffix, request_post) return Response(response_data, content_type='application/json', charset='UTF-8') @@ -1239,7 +1243,7 @@ class XModuleDescriptor(XModuleDescriptorToXBlockMixin, HTMLSnippet, ResourceTem def __eq__(self, other): return (hasattr(other, 'scope_ids') and self.scope_ids == other.scope_ids and - self.fields.keys() == other.fields.keys() and + list(self.fields.keys()) == list(other.fields.keys()) and all(getattr(self, field.name) == getattr(other, field.name) for field in self.fields.values())) @@ -1718,7 +1722,7 @@ class XMLParsingSystem(DescriptorSystem): """ course_key = xblock.scope_ids.usage_id.course_key - for field in xblock.fields.itervalues(): + for field in six.itervalues(xblock.fields): if field.is_set_on(xblock): field_value = getattr(xblock, field.name) if field_value is None: @@ -1728,8 +1732,8 @@ class XMLParsingSystem(DescriptorSystem): elif isinstance(field, ReferenceList): setattr(xblock, field.name, [self._make_usage_key(course_key, ele) for ele in field_value]) elif isinstance(field, ReferenceValueDict): - for key, subvalue in field_value.iteritems(): - assert isinstance(subvalue, basestring) + for key, subvalue in six.iteritems(field_value): + assert isinstance(subvalue, six.string_types) field_value[key] = self._make_usage_key(course_key, subvalue) setattr(xblock, field.name, field_value) diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py index 20c5b02e07b..f7c3f45d027 100644 --- a/common/lib/xmodule/xmodule/xml_module.py +++ b/common/lib/xmodule/xmodule/xml_module.py @@ -1,15 +1,17 @@ +from __future__ import absolute_import + import copy import json import logging import os import sys +import six from lxml import etree from lxml.etree import Element, ElementTree, XMLParser from xblock.core import XML_NAMESPACES from xblock.fields import Dict, Scope, ScopeIds from xblock.runtime import KvsFieldData - from xmodule.modulestore import EdxJSONEncoder from xmodule.modulestore.inheritance import InheritanceKeyValueStore, own_metadata from xmodule.x_module import DEPRECATION_VSCOMPAT_EVENT, XModuleDescriptor @@ -61,7 +63,7 @@ def serialize_field(value): If the value is a string, then we simply return what was passed in. Otherwise, we return json.dumps on the input value. """ - if isinstance(value, basestring): + if isinstance(value, six.string_types): return value return json.dumps(value, cls=EdxJSONEncoder) @@ -208,7 +210,7 @@ class XmlParserMixin(object): # Add info about where we are, but keep the traceback msg = 'Unable to load file contents at path %s for item %s: %s ' % ( filepath, def_id, err) - raise Exception, msg, sys.exc_info()[2] + six.reraise(Exception, msg, sys.exc_info()[2]) @classmethod def load_definition(cls, xml_object, system, def_id, id_generator): @@ -273,7 +275,7 @@ class XmlParserMixin(object): Returns a dictionary {key: value}. """ metadata = {'xml_attributes': {}} - for attr, val in xml_object.attrib.iteritems(): + for attr, val in six.iteritems(xml_object.attrib): # VS[compat]. Remove after all key translations done attr = cls._translate(attr) @@ -293,7 +295,7 @@ class XmlParserMixin(object): Add the keys in policy to metadata, after processing them through the attrmap. Updates the metadata dict in place. """ - for attr, value in policy.iteritems(): + for attr, value in six.iteritems(policy): attr = cls._translate(attr) if attr not in cls.fields: # Store unknown attributes coming from policy.json -- GitLab