diff --git a/openedx/core/lib/api/authentication.py b/openedx/core/lib/api/authentication.py index a22aced6d7..12374ca7f6 100644 --- a/openedx/core/lib/api/authentication.py +++ b/openedx/core/lib/api/authentication.py @@ -1,5 +1,6 @@ """ Common Authentication Handlers used across projects. """ +from __future__ import absolute_import import logging import django.utils.timezone diff --git a/openedx/core/lib/api/fields.py b/openedx/core/lib/api/fields.py index ef7e57a2e6..85f18b8da0 100644 --- a/openedx/core/lib/api/fields.py +++ b/openedx/core/lib/api/fields.py @@ -1,4 +1,5 @@ """Fields useful for edX API implementations.""" +from __future__ import absolute_import from rest_framework.serializers import Field, URLField diff --git a/openedx/core/lib/api/mixins.py b/openedx/core/lib/api/mixins.py index 909fb8b765..e4b10c8311 100644 --- a/openedx/core/lib/api/mixins.py +++ b/openedx/core/lib/api/mixins.py @@ -1,6 +1,7 @@ """ Django Rest Framework view mixins. """ +from __future__ import absolute_import from django.core.exceptions import ValidationError from django.http import Http404 from rest_framework import status diff --git a/openedx/core/lib/api/parsers.py b/openedx/core/lib/api/parsers.py index 9e1b9c6f44..92139ebce6 100644 --- a/openedx/core/lib/api/parsers.py +++ b/openedx/core/lib/api/parsers.py @@ -7,6 +7,7 @@ desired parsers. See http://www.django-rest-framework.org/api-guide/parsers/ for details. """ +from __future__ import absolute_import from rest_framework.exceptions import ParseError, UnsupportedMediaType from rest_framework.parsers import FileUploadParser, JSONParser diff --git a/openedx/core/lib/api/permissions.py b/openedx/core/lib/api/permissions.py index f5520923cf..a97a59747f 100644 --- a/openedx/core/lib/api/permissions.py +++ b/openedx/core/lib/api/permissions.py @@ -2,6 +2,7 @@ API library for Django REST Framework permissions-oriented workflows """ +from __future__ import absolute_import from django.conf import settings from django.http import Http404 from opaque_keys import InvalidKeyError diff --git a/openedx/core/lib/api/serializers.py b/openedx/core/lib/api/serializers.py index d3d08fbcbb..06984dbb95 100644 --- a/openedx/core/lib/api/serializers.py +++ b/openedx/core/lib/api/serializers.py @@ -2,9 +2,11 @@ Serializers to be used in APIs. """ +from __future__ import absolute_import from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey, UsageKey from rest_framework import serializers +import six class CollapsedReferenceSerializer(serializers.HyperlinkedModelSerializer): @@ -46,7 +48,7 @@ class CourseKeyField(serializers.Field): def to_representation(self, data): """Convert a course key to unicode. """ - return unicode(data) + return six.text_type(data) def to_internal_value(self, data): """Convert unicode to a course key. """ @@ -61,7 +63,7 @@ class UsageKeyField(serializers.Field): def to_representation(self, data): """Convert a usage key to unicode. """ - return unicode(data) + return six.text_type(data) def to_internal_value(self, data): """Convert unicode to a usage key. """ diff --git a/openedx/core/lib/api/test_utils.py b/openedx/core/lib/api/test_utils.py index 77d8b48675..f132597c92 100644 --- a/openedx/core/lib/api/test_utils.py +++ b/openedx/core/lib/api/test_utils.py @@ -1,6 +1,7 @@ """ Helpers for API tests. """ +from __future__ import absolute_import import base64 import json import re diff --git a/openedx/core/lib/api/tests/mixins.py b/openedx/core/lib/api/tests/mixins.py index 72fdd55f41..b2457cbc09 100644 --- a/openedx/core/lib/api/tests/mixins.py +++ b/openedx/core/lib/api/tests/mixins.py @@ -1,6 +1,7 @@ """ Mixins for JWT auth tests. """ +from __future__ import absolute_import from time import time from django.conf import settings diff --git a/openedx/core/lib/api/tests/test_authentication.py b/openedx/core/lib/api/tests/test_authentication.py index 7a8cd0f5fa..f01b6303ff 100644 --- a/openedx/core/lib/api/tests/test_authentication.py +++ b/openedx/core/lib/api/tests/test_authentication.py @@ -5,6 +5,7 @@ Tests for OAuth2. This module is copied from django-rest-framework-oauth from __future__ import unicode_literals +from __future__ import absolute_import import itertools import json import unittest diff --git a/openedx/core/lib/api/tests/test_exceptions.py b/openedx/core/lib/api/tests/test_exceptions.py index 5d9c5eabd6..904c5674b6 100644 --- a/openedx/core/lib/api/tests/test_exceptions.py +++ b/openedx/core/lib/api/tests/test_exceptions.py @@ -1,9 +1,11 @@ """ Test Custom Exceptions """ +from __future__ import absolute_import import ddt from django.test import TestCase from rest_framework import exceptions as drf_exceptions +import six @ddt.ddt @@ -15,7 +17,7 @@ class TestDictExceptionsAllowDictDetails(TestCase): def test_drf_errors_are_not_coerced_to_strings(self): # Demonstrate that dictionaries in exceptions are not coerced to strings. exc = drf_exceptions.AuthenticationFailed({u'error_code': -1}) - self.assertNotIsInstance(exc.detail, basestring) + self.assertNotIsInstance(exc.detail, six.string_types) @ddt.data( drf_exceptions.AuthenticationFailed, diff --git a/openedx/core/lib/api/tests/test_fields.py b/openedx/core/lib/api/tests/test_fields.py index bce0c6aaad..ef031341f7 100644 --- a/openedx/core/lib/api/tests/test_fields.py +++ b/openedx/core/lib/api/tests/test_fields.py @@ -1,4 +1,5 @@ """ Tests for custom DRF fields. """ +from __future__ import absolute_import import ddt from django.test import TestCase diff --git a/openedx/core/lib/api/tests/test_parsers.py b/openedx/core/lib/api/tests/test_parsers.py index 3cacde41c7..47d8db47c6 100644 --- a/openedx/core/lib/api/tests/test_parsers.py +++ b/openedx/core/lib/api/tests/test_parsers.py @@ -2,6 +2,7 @@ TestCases verifying proper behavior of custom DRF request parsers. """ +from __future__ import absolute_import from collections import namedtuple from io import BytesIO diff --git a/openedx/core/lib/api/tests/test_permissions.py b/openedx/core/lib/api/tests/test_permissions.py index 140c07ccee..10e72c6ad7 100644 --- a/openedx/core/lib/api/tests/test_permissions.py +++ b/openedx/core/lib/api/tests/test_permissions.py @@ -1,5 +1,6 @@ """ Tests for API permissions classes. """ +from __future__ import absolute_import import ddt from django.contrib.auth.models import AnonymousUser from django.http import Http404 diff --git a/openedx/core/lib/api/view_utils.py b/openedx/core/lib/api/view_utils.py index d92dfbe26a..7568b45bd4 100644 --- a/openedx/core/lib/api/view_utils.py +++ b/openedx/core/lib/api/view_utils.py @@ -1,6 +1,7 @@ """ Utilities related to API views """ +from __future__ import absolute_import from collections import Sequence from django.core.exceptions import NON_FIELD_ERRORS, ObjectDoesNotExist, ValidationError from django.http import Http404 @@ -14,7 +15,7 @@ from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.request import clone_request from rest_framework.response import Response -from six import text_type +from six import text_type, iteritems from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser from openedx.core.lib.api.permissions import IsUserInUrl @@ -129,7 +130,7 @@ def add_serializer_errors(serializer, data, field_errors): """Adds errors from serializer validation to field_errors. data is the original data to deserialize.""" if not serializer.is_valid(): errors = serializer.errors - for key, error in errors.iteritems(): + for key, error in iteritems(errors): field_errors[key] = { 'developer_message': u"Value '{field_value}' is not valid for field '{field_name}': {error}".format( field_value=data.get(key, ''), field_name=key, error=error diff --git a/openedx/core/lib/cache_utils.py b/openedx/core/lib/cache_utils.py index 3910d33f7c..e9157586b2 100644 --- a/openedx/core/lib/cache_utils.py +++ b/openedx/core/lib/cache_utils.py @@ -1,15 +1,18 @@ """ Utilities related to caching. """ +from __future__ import absolute_import import collections -import cPickle as pickle import functools import itertools import zlib +import wrapt from django.utils.encoding import force_text from edx_django_utils.cache import RequestCache -import wrapt +from six import iteritems +from six.moves import map +from six.moves import cPickle as pickle def request_cached(namespace=None, arg_map_function=None, request_cache_getter=None): @@ -85,10 +88,10 @@ def _func_call_cache_key(func, arg_map_function, *args, **kwargs): """ arg_map_function = arg_map_function or force_text - converted_args = map(arg_map_function, args) - converted_kwargs = map(arg_map_function, _sorted_kwargs_list(kwargs)) + converted_args = list(map(arg_map_function, args)) + converted_kwargs = list(map(arg_map_function, _sorted_kwargs_list(kwargs))) - cache_keys = [func.__module__, func.func_name] + converted_args + converted_kwargs + cache_keys = [func.__module__, func.__name__] + converted_args + converted_kwargs return u'.'.join(cache_keys) @@ -96,7 +99,7 @@ def _sorted_kwargs_list(kwargs): """ Returns a unique and deterministic ordered list from the given kwargs. """ - sorted_kwargs = sorted(kwargs.iteritems()) + sorted_kwargs = sorted(iteritems(kwargs)) sorted_kwargs_list = list(itertools.chain(*sorted_kwargs)) return sorted_kwargs_list diff --git a/openedx/core/lib/celery/routers.py b/openedx/core/lib/celery/routers.py index 462ce969b8..bc14f764a1 100644 --- a/openedx/core/lib/celery/routers.py +++ b/openedx/core/lib/celery/routers.py @@ -3,20 +3,20 @@ Custom routers used by both lms and cms when routing tasks to worker queues. For more, see https://celery.readthedocs.io/en/latest/userguide/routing.html#routers """ +from __future__ import absolute_import import logging from abc import ABCMeta, abstractproperty from django.conf import settings +import six log = logging.getLogger(__name__) -class AlternateEnvironmentRouter(object): +class AlternateEnvironmentRouter(six.with_metaclass(ABCMeta, object)): """ A custom Router class for use in routing celery tasks to non-default queues. """ - # this is an abstract base class, implementations must provide alternate_env_tasks - __metaclass__ = ABCMeta @abstractproperty def alternate_env_tasks(self): diff --git a/openedx/core/lib/celery/task_utils.py b/openedx/core/lib/celery/task_utils.py index 10f45c2cb2..694764e964 100644 --- a/openedx/core/lib/celery/task_utils.py +++ b/openedx/core/lib/celery/task_utils.py @@ -1,3 +1,7 @@ +""" + Middleware utilities +""" +from __future__ import absolute_import from contextlib import contextmanager from crum import CurrentRequestUserMiddleware diff --git a/openedx/core/lib/command_utils.py b/openedx/core/lib/command_utils.py index dd0e77676d..452cc951c4 100644 --- a/openedx/core/lib/command_utils.py +++ b/openedx/core/lib/command_utils.py @@ -2,6 +2,7 @@ Useful utilities for management commands. """ +from __future__ import absolute_import from django.core.management.base import CommandError from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey diff --git a/openedx/core/lib/course_tabs.py b/openedx/core/lib/course_tabs.py index 56d4ef1f2e..21642bb48d 100644 --- a/openedx/core/lib/course_tabs.py +++ b/openedx/core/lib/course_tabs.py @@ -1,6 +1,7 @@ """ Tabs for courseware. """ +from __future__ import absolute_import from openedx.core.lib.plugins import PluginManager # Stevedore extension point namespaces @@ -39,6 +40,6 @@ class CourseTabPluginManager(PluginManager): return 0 else: return 1 - tab_types = cls.get_available_plugins().values() + tab_types = list(cls.get_available_plugins().values()) tab_types.sort(cmp=compare_tabs) return tab_types diff --git a/openedx/core/lib/courses.py b/openedx/core/lib/courses.py index 929a4ed815..c3e366bf22 100644 --- a/openedx/core/lib/courses.py +++ b/openedx/core/lib/courses.py @@ -1,6 +1,7 @@ """ Common utility functions related to courses. """ +from __future__ import absolute_import from django import forms from django.conf import settings diff --git a/openedx/core/lib/derived.py b/openedx/core/lib/derived.py index de21fe8a64..73358abd74 100644 --- a/openedx/core/lib/derived.py +++ b/openedx/core/lib/derived.py @@ -4,6 +4,7 @@ via callable methods/lambdas. The derivation time can be controlled to happen af other settings have been set. The derived setting can also be overridden by setting the derived setting to an actual value. """ +from __future__ import absolute_import import six import sys diff --git a/openedx/core/lib/django_require/staticstorage.py b/openedx/core/lib/django_require/staticstorage.py index 1a4d190454..24d3968210 100644 --- a/openedx/core/lib/django_require/staticstorage.py +++ b/openedx/core/lib/django_require/staticstorage.py @@ -2,6 +2,7 @@ :class:`~django_require.staticstorage.OptimizedCachedRequireJsStorage` """ +from __future__ import absolute_import from openedx.core.storage import PipelineForgivingStorage from require.storage import OptimizedFilesMixin diff --git a/openedx/core/lib/edx_api_utils.py b/openedx/core/lib/edx_api_utils.py index c8e17a2be0..0f1fab26a1 100644 --- a/openedx/core/lib/edx_api_utils.py +++ b/openedx/core/lib/edx_api_utils.py @@ -1,6 +1,7 @@ """Helper functions to get data from APIs""" from __future__ import unicode_literals +from __future__ import absolute_import import logging from django.core.cache import cache diff --git a/openedx/core/lib/exceptions.py b/openedx/core/lib/exceptions.py index a140df9911..f1a714a696 100644 --- a/openedx/core/lib/exceptions.py +++ b/openedx/core/lib/exceptions.py @@ -1,6 +1,7 @@ """ Common Purpose Errors """ +from __future__ import absolute_import from django.core.exceptions import ObjectDoesNotExist diff --git a/openedx/core/lib/extract_tar.py b/openedx/core/lib/extract_tar.py index 99c7a9f0ec..b542d9eaee 100644 --- a/openedx/core/lib/extract_tar.py +++ b/openedx/core/lib/extract_tar.py @@ -5,6 +5,7 @@ be, or symlink to a file that is, outside of the directory extracted in. Adapted from: http://stackoverflow.com/questions/10060069/safely-extract-zip-or-tar-using-python """ +from __future__ import absolute_import import logging from os.path import join as joinpath from os.path import abspath, dirname, realpath diff --git a/openedx/core/lib/gating/api.py b/openedx/core/lib/gating/api.py index e137a61ab4..1fad6eac73 100644 --- a/openedx/core/lib/gating/api.py +++ b/openedx/core/lib/gating/api.py @@ -1,6 +1,7 @@ """ API for the gating djangoapp """ +from __future__ import absolute_import import json import logging @@ -19,6 +20,7 @@ from util import milestones_helpers from xblock.completable import XBlockCompletionMode as CompletionMode from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError +import six log = logging.getLogger(__name__) @@ -162,7 +164,7 @@ def get_prerequisites(course_key): milestone = milestones_by_block_id.get(block.location.block_id) if milestone: milestone['block_display_name'] = block.display_name - milestone['block_usage_key'] = unicode(block.location) + milestone['block_usage_key'] = six.text_type(block.location) result.append(milestone) return result @@ -182,7 +184,7 @@ def add_prerequisite(course_key, prereq_content_key): """ milestone = milestones_api.add_milestone( { - 'name': _(u'Gating milestone for {usage_key}').format(usage_key=unicode(prereq_content_key)), + 'name': _(u'Gating milestone for {usage_key}').format(usage_key=six.text_type(prereq_content_key)), 'namespace': "{usage_key}{qualifier}".format( usage_key=prereq_content_key, qualifier=GATING_NAMESPACE_QUALIFIER diff --git a/openedx/core/lib/gating/services.py b/openedx/core/lib/gating/services.py index e00fe60ade..86b30720e6 100644 --- a/openedx/core/lib/gating/services.py +++ b/openedx/core/lib/gating/services.py @@ -1,6 +1,7 @@ """ A wrapper class to communicate with Gating api """ +from __future__ import absolute_import from . import api as gating_api diff --git a/openedx/core/lib/gating/tests/test_api.py b/openedx/core/lib/gating/tests/test_api.py index 2761fb28ae..fe0eadb1bd 100644 --- a/openedx/core/lib/gating/tests/test_api.py +++ b/openedx/core/lib/gating/tests/test_api.py @@ -1,7 +1,7 @@ """ Tests for the gating API """ -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals import unittest @@ -24,6 +24,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from openedx.core.lib.gating import api as gating_api from openedx.core.lib.gating.exceptions import GatingValidationError from student.tests.factories import UserFactory +import six @ddt @@ -78,7 +79,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin): self.generic_milestone = { 'name': 'Test generic milestone', - 'namespace': unicode(self.seq1.location), + 'namespace': six.text_type(self.seq1.location), } @patch('openedx.core.lib.gating.api.log.warning') @@ -148,7 +149,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin): prereqs = gating_api.get_prerequisites(self.course.id) self.assertEqual(len(prereqs), 1) self.assertEqual(prereqs[0]['block_display_name'], self.seq1.display_name) - self.assertEqual(prereqs[0]['block_usage_key'], unicode(self.seq1.location)) + self.assertEqual(prereqs[0]['block_usage_key'], six.text_type(self.seq1.location)) self.assertTrue(gating_api.is_prerequisite(self.course.id, self.seq1.location)) gating_api.remove_prerequisite(self.seq1.location) @@ -165,7 +166,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin): prereq_content_key, min_score, min_completion = gating_api.get_required_content( self.course.id, self.seq2.location ) - self.assertEqual(prereq_content_key, unicode(self.seq1.location)) + self.assertEqual(prereq_content_key, six.text_type(self.seq1.location)) self.assertEqual(min_score, 100) self.assertEqual(min_completion, 100) @@ -194,7 +195,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin): milestone = milestones_api.get_course_content_milestones(self.course.id, self.seq2.location, 'requires')[0] self.assertEqual(gating_api.get_gated_content(self.course, staff), []) - self.assertEqual(gating_api.get_gated_content(self.course, student), [unicode(self.seq2.location)]) + self.assertEqual(gating_api.get_gated_content(self.course, student), [six.text_type(self.seq2.location)]) milestones_api.add_user_milestone({'id': student.id}, milestone) diff --git a/openedx/core/lib/graph_traversals.py b/openedx/core/lib/graph_traversals.py index a45bc24ece..d7810567de 100644 --- a/openedx/core/lib/graph_traversals.py +++ b/openedx/core/lib/graph_traversals.py @@ -109,6 +109,7 @@ to each node's parents. This requires additional storage space, which could be eliminated if DAGs are not supported. """ +from __future__ import absolute_import from collections import deque @@ -219,7 +220,7 @@ def traverse_post_order(start_node, get_children, filter_func=None): # See if there are any additional children for this node. try: - next_child = current.children.next() + next_child = next(current.children) except StopIteration: # Since there are no children left, visit the node and diff --git a/openedx/core/lib/html_to_text.py b/openedx/core/lib/html_to_text.py index fd181dc9bc..3094ab1042 100644 --- a/openedx/core/lib/html_to_text.py +++ b/openedx/core/lib/html_to_text.py @@ -1,4 +1,5 @@ """Provides a function to convert html to plaintext.""" +from __future__ import absolute_import import logging from subprocess import PIPE, Popen diff --git a/openedx/core/lib/json_utils.py b/openedx/core/lib/json_utils.py index 203e64577b..93ad921a9d 100644 --- a/openedx/core/lib/json_utils.py +++ b/openedx/core/lib/json_utils.py @@ -2,9 +2,11 @@ Helpers for json serialization """ +from __future__ import absolute_import import datetime from django.core.serializers.json import DjangoJSONEncoder from opaque_keys.edx.keys import CourseKey, UsageKey +import six class EdxJSONEncoder(DjangoJSONEncoder): @@ -16,7 +18,7 @@ class EdxJSONEncoder(DjangoJSONEncoder): """ def default(self, o): # pylint: disable=method-hidden if isinstance(o, (CourseKey, UsageKey)): - return unicode(o) + return six.text_type(o) elif isinstance(o, datetime.datetime): if o.tzinfo is not None: if o.utcoffset() is None: diff --git a/openedx/core/lib/license/mixin.py b/openedx/core/lib/license/mixin.py index c08261079d..4069b1d3d2 100644 --- a/openedx/core/lib/license/mixin.py +++ b/openedx/core/lib/license/mixin.py @@ -1,6 +1,7 @@ """ License mixin for XBlocks and XModules """ +from __future__ import absolute_import from xblock.core import XBlockMixin from xblock.fields import Scope, String diff --git a/openedx/core/lib/log_utils.py b/openedx/core/lib/log_utils.py index 4011c80cb8..b46c633474 100644 --- a/openedx/core/lib/log_utils.py +++ b/openedx/core/lib/log_utils.py @@ -1,6 +1,7 @@ """ Helper functions for logging. """ +from __future__ import absolute_import import logging log = logging.getLogger(__name__) diff --git a/openedx/core/lib/logsettings.py b/openedx/core/lib/logsettings.py index aa40e15856..c34c4d80d9 100644 --- a/openedx/core/lib/logsettings.py +++ b/openedx/core/lib/logsettings.py @@ -1,5 +1,6 @@ """Get log settings.""" +from __future__ import absolute_import import logging import platform import sys diff --git a/openedx/core/lib/mail_utils.py b/openedx/core/lib/mail_utils.py index 35881bd25a..07da8a532a 100644 --- a/openedx/core/lib/mail_utils.py +++ b/openedx/core/lib/mail_utils.py @@ -2,6 +2,7 @@ Utilities related to mailing. """ +from __future__ import absolute_import import textwrap MAX_LINE_LENGTH = 900 diff --git a/openedx/core/lib/mobile_utils.py b/openedx/core/lib/mobile_utils.py index 4e71112b8a..3aca2e228e 100644 --- a/openedx/core/lib/mobile_utils.py +++ b/openedx/core/lib/mobile_utils.py @@ -2,6 +2,7 @@ Common utilities related to the mobile apps. """ +from __future__ import absolute_import import re from django.conf import settings diff --git a/openedx/core/lib/plugins.py b/openedx/core/lib/plugins.py index 4f1837ad70..3ac70b5c7c 100644 --- a/openedx/core/lib/plugins.py +++ b/openedx/core/lib/plugins.py @@ -1,6 +1,7 @@ """ Adds support for first class plugins that can be added to the edX platform. """ +from __future__ import absolute_import from collections import OrderedDict from stevedore.extension import ExtensionManager diff --git a/openedx/core/lib/request_utils.py b/openedx/core/lib/request_utils.py index 3041c9da9a..805c62f6ab 100644 --- a/openedx/core/lib/request_utils.py +++ b/openedx/core/lib/request_utils.py @@ -1,7 +1,8 @@ """ Utility functions related to HTTP requests """ +from __future__ import absolute_import import logging import re -from urlparse import urlparse +from six.moves.urllib.parse import urlparse # pylint: disable=import-error import crum from django.conf import settings @@ -9,9 +10,9 @@ from django.utils.deprecation import MiddlewareMixin from django.test.client import RequestFactory from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey -from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers try: import newrelic.agent @@ -119,8 +120,8 @@ class CookieMetricsMiddleware(MiddlewareMixin): for name, size in cookie_names_to_size.items(): metric_name = 'cookies.{}.size'.format(name) newrelic.agent.add_custom_parameter(metric_name, size) - log.debug("%s = %d", metric_name, size) + log.debug(u'%s = %d', metric_name, size) total_cookie_size = sum(cookie_names_to_size.values()) newrelic.agent.add_custom_parameter('cookies_total_size', total_cookie_size) - log.debug("cookies_total_size = %d", total_cookie_size) + log.debug(u'cookies_total_size = %d', total_cookie_size) diff --git a/openedx/core/lib/rooted_paths.py b/openedx/core/lib/rooted_paths.py index 5a72fd70c6..97506d6042 100644 --- a/openedx/core/lib/rooted_paths.py +++ b/openedx/core/lib/rooted_paths.py @@ -1,5 +1,6 @@ """Provides rooted_glob, for finding relative glob paths in another director.""" +from __future__ import absolute_import import glob2 diff --git a/openedx/core/lib/tempdir.py b/openedx/core/lib/tempdir.py index 4932f52956..444dd5d727 100644 --- a/openedx/core/lib/tempdir.py +++ b/openedx/core/lib/tempdir.py @@ -1,5 +1,6 @@ """Make temporary directories nicely.""" +from __future__ import absolute_import import atexit import os.path import shutil diff --git a/openedx/core/lib/tests/assertions/events.py b/openedx/core/lib/tests/assertions/events.py index e020419311..32c5e89a5e 100644 --- a/openedx/core/lib/tests/assertions/events.py +++ b/openedx/core/lib/tests/assertions/events.py @@ -1,7 +1,9 @@ """Assertions related to event validation""" +from __future__ import absolute_import import json import pprint +import six def assert_event_matches(expected, actual, tolerate=None): @@ -193,7 +195,7 @@ def parse_event_payload(event): Note that this may simply return the same event unchanged, or return a new copy of the event with the payload parsed. It will never modify the event in place. """ - if 'event' in event and isinstance(event['event'], basestring): + if 'event' in event and isinstance(event['event'], six.string_types): event = event.copy() try: event['event'] = json.loads(event['event']) @@ -217,8 +219,8 @@ def compare_structs(expected, actual, should_strict_compare=None, path=None): differences = [] if isinstance(expected, dict) and isinstance(actual, dict): - expected_keys = frozenset(expected.keys()) - actual_keys = frozenset(actual.keys()) + expected_keys = frozenset(list(expected.keys())) + actual_keys = frozenset(list(actual.keys())) for key in expected_keys - actual_keys: differences.append(u'{0}: not found in actual'.format(_path_to_string(path + [key]))) diff --git a/openedx/core/lib/tests/test_cache_utils.py b/openedx/core/lib/tests/test_cache_utils.py index e1506fac2b..4a69a06032 100644 --- a/openedx/core/lib/tests/test_cache_utils.py +++ b/openedx/core/lib/tests/test_cache_utils.py @@ -2,6 +2,7 @@ """ Tests for cache_utils.py """ +from __future__ import absolute_import from unittest import TestCase import ddt @@ -9,6 +10,7 @@ from mock import Mock from edx_django_utils.cache import RequestCache from openedx.core.lib.cache_utils import request_cached +import six @ddt.ddt @@ -175,7 +177,7 @@ class TestRequestCachedDecorator(TestCase): A dummy function that expects an str and unicode arguments. """ assert isinstance(arg1, str), 'First parameter has to be of type `str`' - assert isinstance(arg2, unicode), 'Second parameter has to be of type `unicode`' + assert isinstance(arg2, six.text_type), 'Second parameter has to be of type `unicode`' return True self.assertTrue(dummy_function('Hello', u'World'), 'Should be callable with ASCII chars') @@ -274,7 +276,7 @@ class TestRequestCachedDecorator(TestCase): """Simple wrapper to let us decorate our mock.""" return to_be_wrapped(*args, **kwargs) - arg_map_function = lambda arg: unicode(arg == 1) + arg_map_function = lambda arg: six.text_type(arg == 1) wrapped = request_cached(arg_map_function=arg_map_function)(mock_wrapper) # This will be a miss, and make an underlying call. diff --git a/openedx/core/lib/tests/test_command_utils.py b/openedx/core/lib/tests/test_command_utils.py index b9ef428fd0..2306aa3696 100644 --- a/openedx/core/lib/tests/test_command_utils.py +++ b/openedx/core/lib/tests/test_command_utils.py @@ -2,6 +2,7 @@ Tests of management command utility code """ +from __future__ import absolute_import from unittest import TestCase import ddt diff --git a/openedx/core/lib/tests/test_course_tab_api.py b/openedx/core/lib/tests/test_course_tab_api.py index 30adff7459..f98b9337e5 100644 --- a/openedx/core/lib/tests/test_course_tab_api.py +++ b/openedx/core/lib/tests/test_course_tab_api.py @@ -2,6 +2,7 @@ Tests for the plugin API """ +from __future__ import absolute_import from django.test import TestCase from openedx.core.lib.plugins import PluginError diff --git a/openedx/core/lib/tests/test_course_tabs.py b/openedx/core/lib/tests/test_course_tabs.py index 07a2564013..f4bf8fff5a 100644 --- a/openedx/core/lib/tests/test_course_tabs.py +++ b/openedx/core/lib/tests/test_course_tabs.py @@ -1,5 +1,6 @@ """ Tests of specific tabs. """ +from __future__ import absolute_import from unittest import TestCase from mock import Mock, patch diff --git a/openedx/core/lib/tests/test_courses.py b/openedx/core/lib/tests/test_courses.py index 50b2ad45c0..a8aa1f9902 100644 --- a/openedx/core/lib/tests/test_courses.py +++ b/openedx/core/lib/tests/test_courses.py @@ -2,6 +2,7 @@ Tests for functionality in openedx/core/lib/courses.py. """ +from __future__ import absolute_import import ddt from django.test.utils import override_settings @@ -9,6 +10,7 @@ from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory +import six from ..courses import course_image_url @@ -28,7 +30,7 @@ class CourseImageTestCase(ModuleStoreTestCase): """Test image URL formatting.""" course = CourseFactory.create() self.verify_url( - unicode(course.id.make_asset_key('asset', course.course_image)), + six.text_type(course.id.make_asset_key('asset', course.course_image)), course_image_url(course) ) @@ -37,7 +39,7 @@ class CourseImageTestCase(ModuleStoreTestCase): course_image = u'before_\N{SNOWMAN}_after.jpg' course = CourseFactory.create(course_image=course_image) self.verify_url( - unicode(course.id.make_asset_key('asset', course_image.replace(u'\N{SNOWMAN}', '_'))), + six.text_type(course.id.make_asset_key('asset', course_image.replace(u'\N{SNOWMAN}', '_'))), course_image_url(course) ) @@ -46,7 +48,7 @@ class CourseImageTestCase(ModuleStoreTestCase): course_image = u'before after.jpg' course = CourseFactory.create(course_image=u'before after.jpg') self.verify_url( - unicode(course.id.make_asset_key('asset', course_image.replace(" ", "_"))), + six.text_type(course.id.make_asset_key('asset', course_image.replace(" ", "_"))), course_image_url(course) ) @@ -69,7 +71,7 @@ class CourseImageTestCase(ModuleStoreTestCase): banner_image = u'banner_image.jpg' course = CourseFactory.create(banner_image=banner_image) self.verify_url( - unicode(course.id.make_asset_key('asset', banner_image)), + six.text_type(course.id.make_asset_key('asset', banner_image)), course_image_url(course, 'banner_image') ) @@ -78,6 +80,6 @@ class CourseImageTestCase(ModuleStoreTestCase): thumbnail_image = u'thumbnail_image.jpg' course = CourseFactory.create(video_thumbnail_image=thumbnail_image) self.verify_url( - unicode(course.id.make_asset_key('asset', thumbnail_image)), + six.text_type(course.id.make_asset_key('asset', thumbnail_image)), course_image_url(course, 'video_thumbnail_image') ) diff --git a/openedx/core/lib/tests/test_derived.py b/openedx/core/lib/tests/test_derived.py index ec6e6532dc..a5fb5f70c8 100644 --- a/openedx/core/lib/tests/test_derived.py +++ b/openedx/core/lib/tests/test_derived.py @@ -2,6 +2,7 @@ Tests for derived.py """ +from __future__ import absolute_import import sys from unittest import TestCase from openedx.core.lib.derived import derived, derived_collection_entry, derive_settings, clear_for_tests diff --git a/openedx/core/lib/tests/test_edx_api_utils.py b/openedx/core/lib/tests/test_edx_api_utils.py index b2c2e842f0..e3f32063ad 100644 --- a/openedx/core/lib/tests/test_edx_api_utils.py +++ b/openedx/core/lib/tests/test_edx_api_utils.py @@ -1,5 +1,6 @@ """Tests covering edX API utilities.""" # pylint: disable=missing-docstring +from __future__ import absolute_import import json import httpretty diff --git a/openedx/core/lib/tests/test_graph_traversals.py b/openedx/core/lib/tests/test_graph_traversals.py index 826d1a05c9..3d044f14d7 100644 --- a/openedx/core/lib/tests/test_graph_traversals.py +++ b/openedx/core/lib/tests/test_graph_traversals.py @@ -2,9 +2,12 @@ Tests for graph traversal generator functions. """ +from __future__ import absolute_import from collections import defaultdict from unittest import TestCase +import six +from six.moves import range from ..graph_traversals import traverse_post_order, traverse_pre_order, traverse_topologically @@ -62,7 +65,7 @@ class TestGraphTraversals(TestCase): will be []. """ result = defaultdict(list) - for parent, children in parent_to_children_map.iteritems(): + for parent, children in six.iteritems(parent_to_children_map): for child in children: result[child].append(parent) return result diff --git a/openedx/core/lib/tests/test_request_utils.py b/openedx/core/lib/tests/test_request_utils.py index 23d89f2e38..b5f3b596b8 100644 --- a/openedx/core/lib/tests/test_request_utils.py +++ b/openedx/core/lib/tests/test_request_utils.py @@ -1,5 +1,6 @@ """Tests for request_utils module.""" +from __future__ import absolute_import import unittest from django.conf import settings diff --git a/openedx/core/lib/tests/test_time_zone_utils.py b/openedx/core/lib/tests/test_time_zone_utils.py index 9f6fcc0019..6939ae1e3b 100644 --- a/openedx/core/lib/tests/test_time_zone_utils.py +++ b/openedx/core/lib/tests/test_time_zone_utils.py @@ -1,5 +1,6 @@ """Tests covering time zone utilities.""" +from __future__ import absolute_import from django.test import TestCase from freezegun import freeze_time from pytz import timezone diff --git a/openedx/core/lib/tests/test_url_utils.py b/openedx/core/lib/tests/test_url_utils.py index ec6bcd6b60..fd7f23b775 100644 --- a/openedx/core/lib/tests/test_url_utils.py +++ b/openedx/core/lib/tests/test_url_utils.py @@ -1,6 +1,7 @@ """ Tests for url_utils module. """ +from __future__ import absolute_import from ddt import data, ddt from django.test import TestCase diff --git a/openedx/core/lib/tests/test_xblock_utils.py b/openedx/core/lib/tests/test_xblock_utils.py index 119ba9ea9a..a093093a77 100644 --- a/openedx/core/lib/tests/test_xblock_utils.py +++ b/openedx/core/lib/tests/test_xblock_utils.py @@ -9,7 +9,6 @@ import ddt from django.test.client import RequestFactory from mock import patch from web_fragments.fragment import Fragment -from six import text_type from opaque_keys.edx.asides import AsideUsageKeyV1, AsideUsageKeyV2 from openedx.core.lib.url_utils import quote_slashes @@ -30,6 +29,7 @@ from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.test_asides import AsideTestType +import six @ddt.ddt @@ -106,7 +106,7 @@ class TestXblockUtils(SharedModuleStoreTestCase): view='baseview', frag=fragment, context={"wrap_xblock_data": {"custom-attribute": "custom-value"}}, - usage_id_serializer=lambda usage_id: quote_slashes(unicode(usage_id)), + usage_id_serializer=lambda usage_id: quote_slashes(six.text_type(usage_id)), request_token=uuid.uuid1().get_hex() ) self.assertIsInstance(test_wrap_output, Fragment) @@ -248,4 +248,4 @@ class TestXBlockAside(SharedModuleStoreTestCase): @XBlockAside.register_temp_plugin(AsideTestType, 'test_aside') def test_get_aside(self): """test get aside success""" - assert get_aside_from_xblock(self.block, text_type("test_aside")) is not None + assert get_aside_from_xblock(self.block, six.text_type("test_aside")) is not None diff --git a/openedx/core/lib/tests/tools.py b/openedx/core/lib/tests/tools.py index f18a0685a3..8ec7376c01 100644 --- a/openedx/core/lib/tests/tools.py +++ b/openedx/core/lib/tests/tools.py @@ -9,6 +9,7 @@ We define the ``__unittest`` symbol in their module namespace so unittest will skip them when printing tracebacks, just as it does for their corresponding methods in ``unittest`` proper. """ +from __future__ import absolute_import import re import unittest diff --git a/openedx/core/lib/time_zone_utils.py b/openedx/core/lib/time_zone_utils.py index 65d516687e..af486749d3 100644 --- a/openedx/core/lib/time_zone_utils.py +++ b/openedx/core/lib/time_zone_utils.py @@ -1,6 +1,7 @@ """ Utilities related to timezones """ +from __future__ import absolute_import from datetime import datetime from pytz import common_timezones, timezone, utc diff --git a/openedx/core/lib/url_utils.py b/openedx/core/lib/url_utils.py index f31d1ab30a..5c9342faf8 100644 --- a/openedx/core/lib/url_utils.py +++ b/openedx/core/lib/url_utils.py @@ -1,6 +1,7 @@ """ Contains common utilities for URL escaping. """ +from __future__ import absolute_import import re diff --git a/openedx/core/lib/xblock_builtin/__init__.py b/openedx/core/lib/xblock_builtin/__init__.py index 539820d0dc..643ebb5255 100644 --- a/openedx/core/lib/xblock_builtin/__init__.py +++ b/openedx/core/lib/xblock_builtin/__init__.py @@ -4,6 +4,7 @@ Helper functions shared by built-in XBlocks. """ +from __future__ import absolute_import from django.conf import settings diff --git a/openedx/core/lib/xblock_builtin/xblock_discussion/setup.py b/openedx/core/lib/xblock_builtin/xblock_discussion/setup.py index b56df214fa..d38057ab07 100644 --- a/openedx/core/lib/xblock_builtin/xblock_discussion/setup.py +++ b/openedx/core/lib/xblock_builtin/xblock_discussion/setup.py @@ -2,6 +2,7 @@ Setup for discussion-forum XBlock. """ +from __future__ import absolute_import import os from setuptools import find_packages, setup diff --git a/openedx/core/lib/xblock_builtin/xblock_discussion/tests.py b/openedx/core/lib/xblock_builtin/xblock_discussion/tests.py index 45d6ebcabf..357158a755 100644 --- a/openedx/core/lib/xblock_builtin/xblock_discussion/tests.py +++ b/openedx/core/lib/xblock_builtin/xblock_discussion/tests.py @@ -1,5 +1,6 @@ """ Tests for DiscussionXBLock""" from __future__ import print_function +from __future__ import absolute_import from collections import namedtuple import ddt import itertools @@ -14,6 +15,7 @@ from openedx.core.lib.xblock_builtin.xblock_discussion.xblock_discussion import from xblock.field_data import DictFieldData from xblock.fields import ScopeIds, UNIQUE_ID, NO_CACHE_VALUE from xblock.runtime import Runtime +from six.moves import range def attribute_pair_repr(self): @@ -37,7 +39,7 @@ def _random_string(): """ Generates random string """ - return ''.join(random.choice(string.lowercase, ) for _ in xrange(12)) + return ''.join(random.choice(string.lowercase, ) for _ in range(12)) def _make_attribute_test_cases(): diff --git a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py index f6e3667474..9cd4e0502e 100644 --- a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py +++ b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py @@ -2,9 +2,11 @@ """ Discussion XBlock """ +from __future__ import absolute_import import logging -import urllib - +import six +from six.moves import urllib +from six.moves.urllib.parse import urlparse # pylint: disable=import-error from django.contrib.staticfiles.storage import staticfiles_storage from django.urls import reverse from django.utils.translation import get_language_bidi @@ -174,7 +176,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): login_msg = '' if not self.django_user.is_authenticated: - qs = urllib.urlencode({ + qs = urllib.parse.urlencode({ 'course_id': self.course_key, 'enrollment_action': 'enroll', 'email_opt_in': False, @@ -252,7 +254,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): """ Applies metadata translations for attributes stored on an inlined XML element. """ - for old_attr, target_attr in cls.metadata_translations.iteritems(): + for old_attr, target_attr in six.iteritems(cls.metadata_translations): if old_attr in node.attrib and hasattr(block, target_attr): setattr(block, target_attr, node.attrib[old_attr]) @@ -274,6 +276,6 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): metadata = cls.load_metadata(definition_xml) cls.apply_policy(metadata, runtime.get_policy(block.scope_ids.usage_id)) - for field_name, value in metadata.iteritems(): + for field_name, value in six.iteritems(metadata): if field_name in block.fields: setattr(block, field_name, value) diff --git a/openedx/core/lib/xblock_pipeline/finder.py b/openedx/core/lib/xblock_pipeline/finder.py index aa1b5e8b34..92f4d02727 100644 --- a/openedx/core/lib/xblock_pipeline/finder.py +++ b/openedx/core/lib/xblock_pipeline/finder.py @@ -1,6 +1,7 @@ """ Django pipeline finder for handling static assets required by XBlocks. """ +from __future__ import absolute_import import os from datetime import datetime diff --git a/openedx/core/lib/xblock_utils/__init__.py b/openedx/core/lib/xblock_utils/__init__.py index 22232397b9..7b230a48bb 100644 --- a/openedx/core/lib/xblock_utils/__init__.py +++ b/openedx/core/lib/xblock_utils/__init__.py @@ -2,24 +2,24 @@ Functions that can are used to modify XBlock fragments for use in the LMS and Studio """ +from __future__ import absolute_import import datetime import json import logging -import markupsafe import re -import static_replace import uuid +import static_replace +import markupsafe from lxml import html, etree from contracts import contract from django.conf import settings -from django.contrib.staticfiles.storage import staticfiles_storage from django.urls import reverse -from pytz import UTC from django.utils.html import escape from django.contrib.auth.models import User +from django.contrib.staticfiles.storage import staticfiles_storage +from pytz import UTC from edxmako.shortcuts import render_to_string -from six import text_type from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.exceptions import InvalidScopeError @@ -32,6 +32,8 @@ from xmodule.vertical_block import VerticalBlock from xmodule.x_module import shim_xmodule_js, XModuleDescriptor, XModule, PREVIEW_VIEWS, STUDIO_VIEW import webpack_loader.utils +import six +from six import text_type log = logging.getLogger(__name__) @@ -142,7 +144,7 @@ def wrap_xblock( 'classes': css_classes, 'display_name': block.display_name_with_default_escaped, # xss-lint: disable=python-deprecated-display-name 'data_attributes': u' '.join(u'data-{}="{}"'.format(markupsafe.escape(key), markupsafe.escape(value)) - for key, value in data.iteritems()), + for key, value in six.iteritems(data)), } if hasattr(frag, 'json_init_args') and frag.json_init_args is not None: @@ -215,7 +217,7 @@ def wrap_xblock_aside( 'content': frag.content, 'classes': css_classes, 'data_attributes': u' '.join(u'data-{}="{}"'.format(markupsafe.escape(key), markupsafe.escape(value)) - for key, value in data.iteritems()), + for key, value in six.iteritems(data)), } if hasattr(frag, 'json_init_args') and frag.json_init_args is not None: @@ -303,7 +305,7 @@ def sanitize_html_id(html_id): return sanitized_html_id -@contract(user=User, block=XBlock, view=basestring, frag=Fragment, context="dict|None") +@contract(user=User, block=XBlock, view=six.string_types[0], frag=Fragment, context="dict|None") def add_staff_markup(user, disable_staff_debug_info, block, view, frag, context): # pylint: disable=unused-argument """ Updates the supplied module with a new get_html function that wraps