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