diff --git a/lms/djangoapps/courseware/entrance_exams.py b/lms/djangoapps/courseware/entrance_exams.py index ee878cc537..5427e00af5 100644 --- a/lms/djangoapps/courseware/entrance_exams.py +++ b/lms/djangoapps/courseware/entrance_exams.py @@ -2,8 +2,11 @@ This file contains all entrance exam related utils/logic. """ -from courseware.access import has_access +from __future__ import absolute_import + from opaque_keys.edx.keys import UsageKey + +from courseware.access import has_access from student.models import EntranceExamConfiguration from util.milestones_helpers import get_required_content, is_entrance_exams_enabled from xmodule.modulestore.django import modulestore diff --git a/lms/djangoapps/courseware/model_data.py b/lms/djangoapps/courseware/model_data.py index aef0446ea5..5a3fe4f6ba 100644 --- a/lms/djangoapps/courseware/model_data.py +++ b/lms/djangoapps/courseware/model_data.py @@ -21,11 +21,14 @@ UserInfoCache: A cache for Scope.user_info DjangoOrmFieldCache: A base-class for single-row-per-field caches. """ +from __future__ import absolute_import + import json import logging from abc import ABCMeta, abstractmethod from collections import defaultdict, namedtuple +import six from contracts import contract, new_contract from django.db import DatabaseError, IntegrityError, transaction from opaque_keys.edx.asides import AsideUsageKeyV1, AsideUsageKeyV2 @@ -152,12 +155,11 @@ new_contract("DjangoKeyValueStore", DjangoKeyValueStore) new_contract("DjangoKeyValueStore_Key", DjangoKeyValueStore.Key) -class DjangoOrmFieldCache(object): +class DjangoOrmFieldCache(six.with_metaclass(ABCMeta, object)): """ Baseclass for Scope-specific field cache objects that are based on single-row-per-field Django ORM objects. """ - __metaclass__ = ABCMeta def __init__(self): self._cache = {} @@ -542,7 +544,7 @@ class UserStateSummaryCache(DjangoOrmFieldCache): Arguments: field_object: A Django model instance that stores the data for fields in this cache """ - return (field_object.usage_id.map_into_course(self.course_id), field_object.field_name) + return field_object.usage_id.map_into_course(self.course_id), field_object.field_name def _cache_key_for_kvs_key(self, key): """ @@ -551,7 +553,7 @@ class UserStateSummaryCache(DjangoOrmFieldCache): Arguments: key (:class:`~DjangoKeyValueStore.Key`): The key representing the cached field """ - return (key.block_scope_id, key.field_name) + return key.block_scope_id, key.field_name class PreferencesCache(DjangoOrmFieldCache): @@ -605,7 +607,7 @@ class PreferencesCache(DjangoOrmFieldCache): Arguments: field_object: A Django model instance that stores the data for fields in this cache """ - return (field_object.module_type, field_object.field_name) + return field_object.module_type, field_object.field_name def _cache_key_for_kvs_key(self, key): """ @@ -614,7 +616,7 @@ class PreferencesCache(DjangoOrmFieldCache): Arguments: key (:class:`~DjangoKeyValueStore.Key`): The key representing the cached field """ - return (BlockTypeKeyV1(key.block_family, key.block_scope_id), key.field_name) + return BlockTypeKeyV1(key.block_family, key.block_scope_id), key.field_name class UserInfoCache(DjangoOrmFieldCache): @@ -840,7 +842,7 @@ class FieldDataCache(object): saved_fields = [] by_scope = defaultdict(dict) - for key, value in kv_dict.iteritems(): + for key, value in six.iteritems(kv_dict): if key.scope.user == UserScope.ONE and not self.user.is_anonymous: # If we're getting user data, we expect that the key matches the @@ -852,7 +854,7 @@ class FieldDataCache(object): by_scope[key.scope][key] = value - for scope, set_many_data in by_scope.iteritems(): + for scope, set_many_data in six.iteritems(by_scope): try: self.cache[scope].set_many(set_many_data) # If save is successful on these fields, add it to diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 5f41c83d3b..4e1e114d8e 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -2,6 +2,8 @@ Module rendering """ +from __future__ import absolute_import + import hashlib import json import logging @@ -9,15 +11,16 @@ import textwrap from collections import OrderedDict from functools import partial -from completion.models import BlockCompletion +import six from completion import waffle as completion_waffle +from completion.models import BlockCompletion from django.conf import settings from django.contrib.auth.models import User from django.core.cache import cache +from django.http import Http404, HttpResponse, HttpResponseForbidden from django.middleware.csrf import CsrfViewMiddleware from django.template.context_processors import csrf from django.urls import reverse -from django.http import Http404, HttpResponse, HttpResponseForbidden from django.utils.text import slugify from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.csrf import csrf_exempt @@ -26,12 +29,15 @@ from edx_django_utils.monitoring import set_custom_metrics_for_course_key, set_m from edx_proctoring.api import get_attempt_status_summary from edx_proctoring.services import ProctoringService from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication +from edx_when.field_data import DateLookupFieldData +from eventtracking import tracker from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey, UsageKey from requests.auth import HTTPBasicAuth from rest_framework.decorators import api_view from rest_framework.exceptions import APIException from six import text_type +from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.django.request import django_to_webob_request, webob_to_django_response from xblock.exceptions import NoSuchHandlerError, NoSuchViewError @@ -41,7 +47,6 @@ from xblock.runtime import KvsFieldData import static_replace from capa.xqueue_interface import XQueueInterface from courseware.access import get_user_role, has_access -from courseware.access_response import IncorrectPartitionGroupError from courseware.entrance_exams import user_can_skip_entrance_exam, user_has_passed_entrance_exam from courseware.masquerade import ( MasqueradingKeyValueStore, @@ -51,9 +56,9 @@ from courseware.masquerade import ( ) from courseware.model_data import DjangoKeyValueStore, FieldDataCache from edxmako.shortcuts import render_to_string -from eventtracking import tracker from lms.djangoapps.courseware.field_overrides import OverrideFieldData -from lms.djangoapps.grades.api import signals as grades_signals, GradesUtilService +from lms.djangoapps.grades.api import GradesUtilService +from lms.djangoapps.grades.api import signals as grades_signals from lms.djangoapps.lms_xblock.field_data import LmsFieldData from lms.djangoapps.lms_xblock.models import XBlockAsidesConfig from lms.djangoapps.lms_xblock.runtime import LmsModuleSystem @@ -62,30 +67,28 @@ from openedx.core.djangoapps.bookmarks.services import BookmarksService from openedx.core.djangoapps.crawlers.models import CrawlersConfig from openedx.core.djangoapps.credit.services import CreditService from openedx.core.djangoapps.util.user_utils import SystemUser -from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser from openedx.core.djangolib.markup import HTML +from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiveUser from openedx.core.lib.api.view_utils import view_auth_classes from openedx.core.lib.gating.services import GatingService from openedx.core.lib.license import wrap_with_license from openedx.core.lib.url_utils import quote_slashes, unquote_slashes -from openedx.core.lib.xblock_utils import request_token as xblock_request_token from openedx.core.lib.xblock_utils import ( add_staff_markup, + get_aside_from_xblock, + is_xblock_aside, replace_course_urls, replace_jump_to_id_urls, - replace_static_urls, - wrap_xblock, - is_xblock_aside, - get_aside_from_xblock, + replace_static_urls ) +from openedx.core.lib.xblock_utils import request_token as xblock_request_token +from openedx.core.lib.xblock_utils import wrap_xblock from openedx.features.course_duration_limits.access import course_expiration_wrapper from student.models import anonymous_id_for_user, user_by_anonymous_id from student.roles import CourseBetaTesterRole from track import contexts from util import milestones_helpers from util.json_request import JsonResponse -from web_fragments.fragment import Fragment -from xmodule.util.sandboxing import can_execute_unsafe_code, get_python_lib_zip from xblock_django.user_service import DjangoXBlockUserService from xmodule.contentstore.django import contentstore from xmodule.error_module import ErrorDescriptor, NonStaffErrorDescriptor @@ -93,11 +96,9 @@ from xmodule.exceptions import NotFoundError, ProcessingError from xmodule.lti_module import LTIModule from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError +from xmodule.util.sandboxing import can_execute_unsafe_code, get_python_lib_zip from xmodule.x_module import XModuleDescriptor -from edx_when.field_data import DateLookupFieldData - - log = logging.getLogger(__name__) if settings.XQUEUE_INTERFACE.get('basic_auth') is not None: @@ -193,7 +194,7 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_ display_id = slugify(chapter.display_name_with_default_escaped) local_hide_from_toc = False if required_content: - if unicode(chapter.location) not in required_content: + if six.text_type(chapter.location) not in required_content: local_hide_from_toc = True # Skip the current chapter if a hide flag is tripped @@ -268,8 +269,8 @@ def _add_timed_exam_info(user, course, section, section_context): try: timed_exam_attempt_context = get_attempt_status_summary( user.id, - unicode(course.id), - unicode(section.location) + six.text_type(course.id), + six.text_type(section.location) ) except Exception as ex: # pylint: disable=broad-except # safety net in case something blows up in edx_proctoring @@ -1093,14 +1094,14 @@ def get_module_by_usage_id(request, course_id, usage_id, disable_staff_debug_inf 'module': { # xss-lint: disable=python-deprecated-display-name 'display_name': descriptor.display_name_with_default_escaped, - 'usage_key': unicode(descriptor.location), + 'usage_key': six.text_type(descriptor.location), } } # For blocks that are inherited from a content library, we add some additional metadata: if descriptor_orig_usage_key is not None: - tracking_context['module']['original_usage_key'] = unicode(descriptor_orig_usage_key) - tracking_context['module']['original_usage_version'] = unicode(descriptor_orig_version) + tracking_context['module']['original_usage_key'] = six.text_type(descriptor_orig_usage_key) + tracking_context['module']['original_usage_version'] = six.text_type(descriptor_orig_version) unused_masquerade, user = setup_masquerade(request, course_id, has_access(user, 'staff', descriptor, course_id)) field_data_cache = FieldDataCache.cache_for_descriptor_descendents( @@ -1164,7 +1165,7 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, course else: block_usage_key = usage_key instance, tracking_context = get_module_by_usage_id( - request, course_id, unicode(block_usage_key), course=course + request, course_id, six.text_type(block_usage_key), course=course ) # Name the transaction so that we can view XBlock handlers separately in @@ -1263,8 +1264,8 @@ def xblock_view(request, course_id, usage_id, view_name): return JsonResponse({ 'html': fragment.content, - 'resources': hashed_resources.items(), - 'csrf_token': unicode(csrf(request)['csrf_token']), + 'resources': list(hashed_resources.items()), + 'csrf_token': six.text_type(csrf(request)['csrf_token']), }) diff --git a/lms/djangoapps/courseware/student_field_overrides.py b/lms/djangoapps/courseware/student_field_overrides.py index b5545bc0c0..40c938477a 100644 --- a/lms/djangoapps/courseware/student_field_overrides.py +++ b/lms/djangoapps/courseware/student_field_overrides.py @@ -2,6 +2,8 @@ API related to providing field overrides for individual students. This is used by the individual due dates feature. """ +from __future__ import absolute_import + import json from courseware.models import StudentFieldOverride diff --git a/lms/djangoapps/courseware/testutils.py b/lms/djangoapps/courseware/testutils.py index 022fd2bdb4..6e5db3fa78 100644 --- a/lms/djangoapps/courseware/testutils.py +++ b/lms/djangoapps/courseware/testutils.py @@ -2,12 +2,15 @@ Common test utilities for courseware functionality """ +from __future__ import absolute_import + from abc import ABCMeta, abstractmethod from datetime import datetime, timedelta -from urllib import urlencode import ddt +import six from mock import patch +from six.moves.urllib.parse import urlencode # pylint: disable=import-error from lms.djangoapps.courseware.field_overrides import OverrideModulestoreFieldData from lms.djangoapps.courseware.url_helpers import get_redirect_url @@ -19,12 +22,11 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, chec @ddt.ddt -class RenderXBlockTestMixin(object): +class RenderXBlockTestMixin(six.with_metaclass(ABCMeta, object)): """ Mixin for testing the courseware.render_xblock function. It can be used for testing any higher-level endpoint that calls this method. """ - __metaclass__ = ABCMeta # DOM elements that appear in the LMS Courseware, # but are excluded from the xBlock-only rendering. @@ -68,7 +70,7 @@ class RenderXBlockTestMixin(object): usage_key: The course block usage key. This ensures that the positive and negative tests stay in sync. url_encoded_params: URL encoded parameters that should be appended to the requested URL. """ - pass # pragma: no cover + pass # pragma: no cover def login(self): """ @@ -270,6 +272,7 @@ class FieldOverrideTestMixin(object): """ A Mixin helper class for classes that test Field Overrides. """ + def setUp(self): super(FieldOverrideTestMixin, self).setUp() OverrideModulestoreFieldData.provider_classes = None diff --git a/lms/djangoapps/courseware/user_state_client.py b/lms/djangoapps/courseware/user_state_client.py index 4d60cb8ff0..156ee52db2 100644 --- a/lms/djangoapps/courseware/user_state_client.py +++ b/lms/djangoapps/courseware/user_state_client.py @@ -3,14 +3,17 @@ An implementation of :class:`XBlockUserStateClient`, which stores XBlock Scope.u data in a Django ORM model. """ +from __future__ import absolute_import + import itertools import logging from operator import attrgetter from time import time +import six from django.conf import settings -from django.core.paginator import Paginator from django.contrib.auth.models import User +from django.core.paginator import Paginator from django.db import transaction from django.db.utils import IntegrityError from edx_django_utils import monitoring as monitoring_utils @@ -258,7 +261,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient): # process. This seems to happen frequently, and ignoring it is the # best course of action for now log.warning(u"set_many: IntegrityError for student {} - course_id {} - usage key {}".format( - user, repr(unicode(usage_key.course_key)), usage_key + user, repr(six.text_type(usage_key.course_key)), usage_key )) return @@ -281,10 +284,10 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient): # The UPDATE above failed. Log information - but ignore the error. # See https://openedx.atlassian.net/browse/TNL-5365 log.warning(u"set_many: IntegrityError for student {} - course_id {} - usage key {}".format( - user, repr(unicode(usage_key.course_key)), usage_key + user, repr(six.text_type(usage_key.course_key)), usage_key )) log.warning(u"set_many: All {} block keys: {}".format( - len(block_keys_to_state), block_keys_to_state.keys() + len(block_keys_to_state), list(block_keys_to_state.keys()) )) # DataDog and New Relic reporting diff --git a/lms/djangoapps/grades/migrations/0003_coursepersistentgradesflag_persistentgradesenabledflag.py b/lms/djangoapps/grades/migrations/0003_coursepersistentgradesflag_persistentgradesenabledflag.py index 70eb54de5d..f935523f4a 100644 --- a/lms/djangoapps/grades/migrations/0003_coursepersistentgradesflag_persistentgradesenabledflag.py +++ b/lms/djangoapps/grades/migrations/0003_coursepersistentgradesflag_persistentgradesenabledflag.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals -from django.db import migrations, models import django.db.models.deletion from django.conf import settings +from django.db import migrations, models from opaque_keys.edx.django.models import CourseKeyField diff --git a/lms/djangoapps/grades/migrations/0010_auto_20170112_1156.py b/lms/djangoapps/grades/migrations/0010_auto_20170112_1156.py index 39cf1fdf49..6588c002a1 100644 --- a/lms/djangoapps/grades/migrations/0010_auto_20170112_1156.py +++ b/lms/djangoapps/grades/migrations/0010_auto_20170112_1156.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals from django.db import migrations, models