diff --git a/cms/djangoapps/contentstore/views/assets.py b/cms/djangoapps/contentstore/views/assets.py index acfb8b7187..353e87e21a 100644 --- a/cms/djangoapps/contentstore/views/assets.py +++ b/cms/djangoapps/contentstore/views/assets.py @@ -7,7 +7,6 @@ import math import re from functools import partial -import six from django.conf import settings from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied @@ -17,13 +16,12 @@ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods, require_POST from opaque_keys.edx.keys import AssetKey, CourseKey from pymongo import ASCENDING, DESCENDING -from six import text_type from common.djangoapps.edxmako.shortcuts import render_to_response -from openedx.core.djangoapps.contentserver.caching import del_cached_content from common.djangoapps.student.auth import has_course_author_access from common.djangoapps.util.date_utils import get_default_time_display from common.djangoapps.util.json_request import JsonResponse +from openedx.core.djangoapps.contentserver.caching import del_cached_content from xmodule.contentstore.content import StaticContent from xmodule.contentstore.django import contentstore from xmodule.exceptions import NotFoundError @@ -206,9 +204,9 @@ def _get_error_if_invalid_parameters(requested_filter): if invalid_filters: error_message = { 'error_code': 'invalid_asset_type_filter', - 'developer_message': u'The asset_type parameter to the request is invalid. ' - u'The {} filters are not described in the settings.FILES_AND_UPLOAD_TYPE_FILTERS ' - u'dictionary.'.format(invalid_filters) + 'developer_message': 'The asset_type parameter to the request is invalid. ' + 'The {} filters are not described in the settings.FILES_AND_UPLOAD_TYPE_FILTERS ' + 'dictionary.'.format(invalid_filters) } return JsonResponse({'error': error_message}, status=400) @@ -414,7 +412,7 @@ def _upload_asset(request, course_key): try: content = update_course_run_asset(course_key, upload_file) except AssetSizeTooLargeException as exception: - return JsonResponse({'error': text_type(exception)}, status=413) + return JsonResponse({'error': str(exception)}, status=413) # readback the saved content - we need the database timestamp readback = contentstore().find(content.location) @@ -436,7 +434,7 @@ def _get_error_if_course_does_not_exist(course_key): # lint-amnesty, pylint: di try: modulestore().get_course(course_key) except ItemNotFoundError: - logging.error(u'Could not find course: %s', course_key) + logging.error('Could not find course: %s', course_key) return HttpResponseBadRequest() @@ -472,8 +470,8 @@ def _get_file_too_large_error_message(filename): """returns formatted error message for large files""" return _( - u'File {filename} exceeds maximum size of ' - u'{maximum_size_in_megabytes} MB.' + 'File {filename} exceeds maximum size of ' + '{maximum_size_in_megabytes} MB.' ).format( filename=filename, maximum_size_in_megabytes=settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB, @@ -585,7 +583,7 @@ def _delete_thumbnail(thumbnail_location, course_key, asset_key): # lint-amnest contentstore().delete(thumbnail_content.get_id()) del_cached_content(thumbnail_location) except Exception: # pylint: disable=broad-except - logging.warning(u'Could not delete thumbnail: %s', thumbnail_location) + logging.warning('Could not delete thumbnail: %s', thumbnail_location) def _get_asset_json(display_name, content_type, date, location, thumbnail_location, locked): @@ -604,5 +602,5 @@ def _get_asset_json(display_name, content_type, date, location, thumbnail_locati 'thumbnail': StaticContent.serialize_asset_key_with_slash(thumbnail_location) if thumbnail_location else None, 'locked': locked, # needed for Backbone delete/update. - 'id': six.text_type(location) + 'id': str(location) } diff --git a/cms/djangoapps/contentstore/views/certificates.py b/cms/djangoapps/contentstore/views/certificates.py index 97ba8ad289..e27d9aad27 100644 --- a/cms/djangoapps/contentstore/views/certificates.py +++ b/cms/djangoapps/contentstore/views/certificates.py @@ -26,7 +26,6 @@ course.certificates: { import json import logging -import six from django.conf import settings from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied @@ -37,7 +36,6 @@ from django.views.decorators.http import require_http_methods from eventtracking import tracker from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import AssetKey, CourseKey -from six import text_type from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.edxmako.shortcuts import render_to_response @@ -87,7 +85,7 @@ def _delete_asset(course_key, asset_key_string): except InvalidKeyError: # Unable to parse the asset key, log and return LOGGER.info( - u"In course %r, unable to parse asset key %r, not attempting to delete signatory.", + "In course %r, unable to parse asset key %r, not attempting to delete signatory.", course_key, asset_key_string, ) @@ -95,7 +93,7 @@ def _delete_asset(course_key, asset_key_string): else: # Unable to parse the asset key, log and return LOGGER.info( - u"In course %r, unable to parse asset key %r, not attempting to delete signatory.", + "In course %r, unable to parse asset key %r, not attempting to delete signatory.", course_key, asset_key_string, ) @@ -123,7 +121,7 @@ class CertificateValidationError(CertificateException): pass # lint-amnesty, pylint: disable=unnecessary-pass -class CertificateManager(object): +class CertificateManager: """ The CertificateManager is responsible for storage, retrieval, and manipulation of Certificates Certificates are not stored in the Django ORM, they are a field/setting on the course descriptor @@ -153,7 +151,7 @@ class CertificateManager(object): # Ensure the schema version meets our expectations if certificate_data.get("version") != CERTIFICATE_SCHEMA_VERSION: raise TypeError( - u"Unsupported certificate schema version: {0}. Expected version: {1}.".format( + "Unsupported certificate schema version: {}. Expected version: {}.".format( certificate_data.get("version"), CERTIFICATE_SCHEMA_VERSION ) @@ -238,13 +236,13 @@ class CertificateManager(object): Deserialize from a JSON representation into a Certificate object. 'value' should be either a Certificate instance, or a valid JSON string """ - if not six.PY2 and isinstance(value, bytes): + if isinstance(value, bytes): value = value.decode('utf-8') # Ensure the schema fieldset meets our expectations for key in ("name", "description", "version"): if key not in value: - raise CertificateValidationError(_(u"Certificate dict {0} missing value key '{1}'").format(value, key)) + raise CertificateValidationError(_("Certificate dict {0} missing value key '{1}'").format(value, key)) # Load up the Certificate data certificate_data = CertificateManager.parse(value) @@ -314,7 +312,7 @@ class CertificateManager(object): tracker.emit(event_name, event_data) -class Certificate(object): +class Certificate: """ The logical representation of an individual course certificate """ @@ -349,7 +347,7 @@ def certificate_activation_handler(request, course_key_string): try: course = _get_course_and_check_access(course_key, request.user) except PermissionDenied: - msg = _(u'PermissionDenied: Failed in authenticating {user}').format(user=request.user) + msg = _('PermissionDenied: Failed in authenticating {user}').format(user=request.user) return JsonResponse({"error": msg}, status=403) data = json.loads(request.body.decode('utf8')) @@ -364,7 +362,7 @@ def certificate_activation_handler(request, course_key_string): store.update_item(course, request.user.id) cert_event_type = 'activated' if is_active else 'deactivated' CertificateManager.track_event(cert_event_type, { - 'course_id': six.text_type(course.id), + 'course_id': str(course.id), }) return HttpResponse(status=200) @@ -387,7 +385,7 @@ def certificates_list_handler(request, course_key_string): try: course = _get_course_and_check_access(course_key, request.user) except PermissionDenied: - msg = _(u'PermissionDenied: Failed in authenticating {user}').format(user=request.user) + msg = _('PermissionDenied: Failed in authenticating {user}').format(user=request.user) return JsonResponse({"error": msg}, status=403) if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): @@ -442,7 +440,7 @@ def certificates_list_handler(request, course_key_string): try: new_certificate = CertificateManager.deserialize_certificate(course, request.body) except CertificateValidationError as err: - return JsonResponse({"error": text_type(err)}, status=400) + return JsonResponse({"error": str(err)}, status=400) if course.certificates.get('certificates') is None: course.certificates['certificates'] = [] course.certificates['certificates'].append(new_certificate.certificate_data) @@ -454,7 +452,7 @@ def certificates_list_handler(request, course_key_string): ) store.update_item(course, request.user.id) CertificateManager.track_event('created', { - 'course_id': six.text_type(course.id), + 'course_id': str(course.id), 'configuration_id': new_certificate.id }) course = _get_course_and_check_access(course_key, request.user) @@ -499,7 +497,7 @@ def certificates_detail_handler(request, course_key_string, certificate_id): try: new_certificate = CertificateManager.deserialize_certificate(course, request.body) except CertificateValidationError as err: - return JsonResponse({"error": text_type(err)}, status=400) + return JsonResponse({"error": str(err)}, status=400) serialized_certificate = CertificateManager.serialize_certificate(new_certificate) cert_event_type = 'created' @@ -511,7 +509,7 @@ def certificates_detail_handler(request, course_key_string, certificate_id): store.update_item(course, request.user.id) CertificateManager.track_event(cert_event_type, { - 'course_id': six.text_type(course.id), + 'course_id': str(course.id), 'configuration_id': serialized_certificate["id"] }) return JsonResponse(serialized_certificate, status=201) @@ -533,7 +531,7 @@ def certificates_detail_handler(request, course_key_string, certificate_id): certificate_id=certificate_id ) CertificateManager.track_event('deleted', { - 'course_id': six.text_type(course.id), + 'course_id': str(course.id), 'configuration_id': certificate_id }) return JsonResponse(status=204) diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py index 01b9d4ac1e..db965ea2d9 100644 --- a/cms/djangoapps/contentstore/views/component.py +++ b/cms/djangoapps/contentstore/views/component.py @@ -4,8 +4,8 @@ Studio component views import logging +from urllib.parse import quote_plus -import six from django.conf import settings from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied @@ -14,7 +14,6 @@ from django.utils.translation import ugettext as _ from django.views.decorators.http import require_GET from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import UsageKey -from six.moves.urllib.parse import quote_plus from xblock.core import XBlock from xblock.django.request import django_to_webob_request, webob_to_django_response from xblock.exceptions import NoSuchHandlerError @@ -22,10 +21,10 @@ from xblock.plugin import PluginMissingError from xblock.runtime import Mixologist from common.djangoapps.edxmako.shortcuts import render_to_response -from openedx.core.lib.xblock_utils import get_aside_from_xblock, is_xblock_aside from common.djangoapps.student.auth import has_course_author_access from common.djangoapps.xblock_django.api import authorable_xblocks, disabled_xblocks from common.djangoapps.xblock_django.models import XBlockStudioConfigurationFlag +from openedx.core.lib.xblock_utils import get_aside_from_xblock, is_xblock_aside from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError @@ -43,7 +42,7 @@ log = logging.getLogger(__name__) # NOTE: This list is disjoint from ADVANCED_COMPONENT_TYPES COMPONENT_TYPES = ['discussion', 'html', 'openassessment', 'problem', 'video'] -ADVANCED_COMPONENT_TYPES = sorted(set(name for name, class_ in XBlock.load_classes()) - set(COMPONENT_TYPES)) +ADVANCED_COMPONENT_TYPES = sorted({name for name, class_ in XBlock.load_classes()} - set(COMPONENT_TYPES)) ADVANCED_PROBLEM_TYPES = settings.ADVANCED_PROBLEM_TYPES @@ -155,10 +154,10 @@ def container_handler(request, usage_key_string): assert unit is not None, "Could not determine unit page" subsection = get_parent_xblock(unit) - assert subsection is not None, "Could not determine parent subsection from unit " + six.text_type( + assert subsection is not None, "Could not determine parent subsection from unit " + str( unit.location) section = get_parent_xblock(subsection) - assert section is not None, "Could not determine ancestor section from unit " + six.text_type(unit.location) + assert section is not None, "Could not determine ancestor section from unit " + str(unit.location) # for the sequence navigator prev_url, next_url = get_sibling_urls(subsection) @@ -270,7 +269,7 @@ def get_component_templates(courselike, library=False): # lint-amnesty, pylint: return { "show_legend": XBlockStudioConfigurationFlag.is_enabled(), "allow_unsupported_xblocks": allow_unsupported, - "documentation_label": _(u"{platform_name} Support Levels:").format(platform_name=settings.PLATFORM_NAME) + "documentation_label": _("{platform_name} Support Levels:").format(platform_name=settings.PLATFORM_NAME) } component_display_names = { @@ -367,7 +366,7 @@ def get_component_templates(courselike, library=False): # lint-amnesty, pylint: try: component_display_name = xblock_type_display_name(component) except PluginMissingError: - log.warning(u'Unable to load xblock type %s to read display_name', component, exc_info=True) + log.warning('Unable to load xblock type %s to read display_name', component, exc_info=True) else: templates_for_category.append( create_template_dict( @@ -425,12 +424,12 @@ def get_component_templates(courselike, library=False): # lint-amnesty, pylint: # prevents any authors from trying to instantiate the # non-existent component type by not showing it in the menu log.warning( - u"Advanced component %s does not exist. It will not be added to the Studio new component menu.", + "Advanced component %s does not exist. It will not be added to the Studio new component menu.", category ) else: log.error( - u"Improper format for course advanced keys! %s", + "Improper format for course advanced keys! %s", course_advanced_keys ) if advanced_component_templates['templates']: @@ -503,7 +502,7 @@ def component_handler(request, usage_key_string, handler, suffix=''): handler_descriptor.xmodule_runtime = StudioEditModuleRuntime(request.user) resp = handler_descriptor.handle(handler, req, suffix) except NoSuchHandlerError: - log.info(u"XBlock %s attempted to access missing handler %r", handler_descriptor, handler, exc_info=True) + log.info("XBlock %s attempted to access missing handler %r", handler_descriptor, handler, exc_info=True) raise Http404 # lint-amnesty, pylint: disable=raise-missing-from # unintentional update to handle any side effects of handle call diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 35e85c0add..57da0c5435 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -1,6 +1,7 @@ """ Views related to operations on course objects """ +# pylint: disable=filter-builtin-not-iterating import copy @@ -12,7 +13,6 @@ import string from collections import defaultdict import django.utils -import six from ccx_keys.locator import CCXLocator from django.conf import settings from django.contrib.auth.decorators import login_required @@ -23,6 +23,7 @@ from django.urls import reverse from django.utils.translation import ugettext as _ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_GET, require_http_methods +from edx_django_utils.monitoring import function_trace from edx_toggles.toggles import LegacyWaffleSwitchNamespace from milestones import api as milestones_api from opaque_keys import InvalidKeyError @@ -30,9 +31,6 @@ from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import BlockUsageLocator from organizations.api import add_organization_course, ensure_organization from organizations.exceptions import InvalidOrganizationException -from six import text_type -from six.moves import filter -from edx_django_utils.monitoring import function_trace from cms.djangoapps.course_creators.views import add_user_with_status_unrequested, get_course_creator_status from cms.djangoapps.models.settings.course_grading import CourseGradingModel @@ -42,6 +40,27 @@ from common.djangoapps.course_action_state.managers import CourseActionStateItem from common.djangoapps.course_action_state.models import CourseRerunState, CourseRerunUIStateManager from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.edxmako.shortcuts import render_to_response +from common.djangoapps.student import auth +from common.djangoapps.student.auth import has_course_author_access, has_studio_read_access, has_studio_write_access +from common.djangoapps.student.roles import ( + CourseCreatorRole, + CourseInstructorRole, + CourseStaffRole, + GlobalStaff, + UserBasedRole +) +from common.djangoapps.util.course import get_link_for_about_page +from common.djangoapps.util.date_utils import get_default_time_display +from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadRequest, expect_json +from common.djangoapps.util.milestones_helpers import ( + is_prerequisite_courses_enabled, + is_valid_course_key, + remove_prerequisite_course, + set_prerequisite_courses +) +from common.djangoapps.util.string_utils import _has_non_ascii_characters +from common.djangoapps.xblock_django.api import deprecated_xblocks +from openedx.core import toggles as core_toggles from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.credit.api import get_credit_requirements, is_credit_course from openedx.core.djangoapps.credit.tasks import update_credit_course_requirements @@ -54,23 +73,6 @@ from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.content_type_gating.partitions import CONTENT_TYPE_GATING_SCHEME from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML from openedx.features.course_experience.waffle import waffle as course_experience_waffle -from common.djangoapps.student import auth -from common.djangoapps.student.auth import has_course_author_access, has_studio_read_access, has_studio_write_access -from common.djangoapps.student.roles import ( - CourseCreatorRole, CourseInstructorRole, CourseStaffRole, GlobalStaff, UserBasedRole -) -from common.djangoapps.util.course import get_link_for_about_page -from common.djangoapps.util.date_utils import get_default_time_display -from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadRequest, expect_json -from common.djangoapps.util.milestones_helpers import ( - is_prerequisite_courses_enabled, - is_valid_course_key, - remove_prerequisite_course, - set_prerequisite_courses -) -from openedx.core import toggles as core_toggles -from common.djangoapps.util.string_utils import _has_non_ascii_characters -from common.djangoapps.xblock_django.api import deprecated_xblocks from xmodule.contentstore.content import StaticContent from xmodule.course_module import DEFAULT_START_DATE, CourseFields from xmodule.error_module import ErrorBlock @@ -112,7 +114,6 @@ from .library import ( should_redirect_to_library_authoring_mfe ) - log = logging.getLogger(__name__) @@ -403,7 +404,7 @@ def _accessible_courses_summary_iter(request, org=None): courses_summary = [] if org == '' else CourseOverview.get_all_courses(orgs=[org]) else: courses_summary = modulestore().get_course_summaries() - courses_summary = six.moves.filter(course_filter, courses_summary) + courses_summary = filter(course_filter, courses_summary) in_process_course_actions = get_in_process_course_actions(request) return courses_summary, in_process_course_actions @@ -430,7 +431,7 @@ def _accessible_courses_iter(request): return has_studio_read_access(request.user, course.id) - courses = six.moves.filter(course_filter, modulestore().get_courses()) + courses = filter(course_filter, modulestore().get_courses()) in_process_course_actions = get_in_process_course_actions(request) return courses, in_process_course_actions @@ -458,7 +459,7 @@ def _accessible_courses_iter_for_tests(request): return has_studio_read_access(request.user, course.id) - courses = six.moves.filter(course_filter, modulestore().get_course_summaries()) + courses = filter(course_filter, modulestore().get_course_summaries()) in_process_course_actions = get_in_process_course_actions(request) return courses, in_process_course_actions @@ -516,7 +517,7 @@ def course_listing(request): """ optimization_enabled = GlobalStaff().has_user(request.user) and \ - LegacyWaffleSwitchNamespace(name=WAFFLE_NAMESPACE).is_enabled(u'enable_global_staff_optimization') + LegacyWaffleSwitchNamespace(name=WAFFLE_NAMESPACE).is_enabled('enable_global_staff_optimization') org = request.GET.get('org', '') if optimization_enabled else None courses_iter, in_process_course_actions = get_courses_accessible_to_user(request, org) @@ -530,27 +531,27 @@ def course_listing(request): Return a dict of the data which the view requires for each unsucceeded course """ return { - u'display_name': uca.display_name, - u'course_key': six.text_type(uca.course_key), - u'org': uca.course_key.org, - u'number': uca.course_key.course, - u'run': uca.course_key.run, - u'is_failed': True if uca.state == CourseRerunUIStateManager.State.FAILED else False, # lint-amnesty, pylint: disable=simplifiable-if-expression - u'is_in_progress': True if uca.state == CourseRerunUIStateManager.State.IN_PROGRESS else False, # lint-amnesty, pylint: disable=simplifiable-if-expression - u'dismiss_link': reverse_course_url( - u'course_notifications_handler', + 'display_name': uca.display_name, + 'course_key': str(uca.course_key), + 'org': uca.course_key.org, + 'number': uca.course_key.course, + 'run': uca.course_key.run, + 'is_failed': uca.state == CourseRerunUIStateManager.State.FAILED, + 'is_in_progress': uca.state == CourseRerunUIStateManager.State.IN_PROGRESS, + 'dismiss_link': reverse_course_url( + 'course_notifications_handler', uca.course_key, kwargs={ - u'action_state_id': uca.id, + 'action_state_id': uca.id, }, - ) if uca.state == CourseRerunUIStateManager.State.FAILED else u'' + ) if uca.state == CourseRerunUIStateManager.State.FAILED else '' } - split_archived = settings.FEATURES.get(u'ENABLE_SEPARATE_ARCHIVED_COURSES', False) + split_archived = settings.FEATURES.get('ENABLE_SEPARATE_ARCHIVED_COURSES', False) active_courses, archived_courses = _process_courses_list(courses_iter, in_process_course_actions, split_archived) in_process_course_actions = [format_in_process_course_view(uca) for uca in in_process_course_actions] - return render_to_response(u'index.html', { + return render_to_response('index.html', { 'courses': active_courses, 'split_studio_home': split_library_view_on_dashboard(), 'archived_courses': archived_courses, @@ -564,8 +565,8 @@ def course_listing(request): 'request_course_creator_url': reverse('request_course_creator'), 'course_creator_status': _get_course_creator_status(user), 'rerun_creator_status': GlobalStaff().has_user(user), - 'allow_unicode_course_id': settings.FEATURES.get(u'ALLOW_UNICODE_COURSE_ID', False), - 'allow_course_reruns': settings.FEATURES.get(u'ALLOW_COURSE_RERUNS', True), + 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False), + 'allow_course_reruns': settings.FEATURES.get('ALLOW_COURSE_RERUNS', True), 'optimization_enabled': optimization_enabled, 'active_tab': 'courses' }) @@ -589,7 +590,7 @@ def library_listing(request): 'course_creator_status': _get_course_creator_status(request.user), 'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False), 'archived_courses': True, - 'allow_course_reruns': settings.FEATURES.get(u'ALLOW_COURSE_RERUNS', True), + 'allow_course_reruns': settings.FEATURES.get('ALLOW_COURSE_RERUNS', True), 'rerun_creator_status': GlobalStaff().has_user(request.user), 'split_studio_home': split_library_view_on_dashboard(), 'active_tab': 'libraries' @@ -604,8 +605,8 @@ def _format_library_for_view(library, request): return { 'display_name': library.display_name, - 'library_key': six.text_type(library.location.library_key), - 'url': reverse_library_url(u'library_handler', six.text_type(library.location.library_key)), + 'library_key': str(library.location.library_key), + 'url': reverse_library_url('library_handler', str(library.location.library_key)), 'org': library.display_org_with_default, 'number': library.display_number_with_default, 'can_edit': has_studio_write_access(request.user, library.location.library_key), @@ -673,7 +674,7 @@ def course_index(request, course_key): reindex_link = None if settings.FEATURES.get('ENABLE_COURSEWARE_INDEX', False): if GlobalStaff().has_user(request.user): - reindex_link = "/course/{course_id}/search_reindex".format(course_id=six.text_type(course_key)) + reindex_link = "/course/{course_id}/search_reindex".format(course_id=str(course_key)) sections = course_module.get_children() course_structure = _course_outline_json(request, course_module) locator_to_show = request.GET.get('show', None) @@ -774,7 +775,7 @@ def _process_courses_list(courses_iter, in_process_course_actions, split_archive """ return { 'display_name': course.display_name, - 'course_key': six.text_type(course.location.course_key), + 'course_key': str(course.location.course_key), 'url': reverse_course_url('course_handler', course.id), 'lms_link': get_lms_link_for_item(course.location), 'rerun_link': _get_rerun_link_for_item(course.id), @@ -875,7 +876,7 @@ def _create_or_rerun_course(request): # existing xml courses this cannot be changed in CourseBlock. # # TODO get rid of defining wiki slug in this org/course/run specific way and reconcile # w/ xmodule.course_module.CourseBlock.__init__ - wiki_slug = u"{0}.{1}.{2}".format(org, course, run) + wiki_slug = f"{org}.{course}.{run}" definition_data = {'wiki_slug': wiki_slug} fields.update(definition_data) @@ -885,17 +886,17 @@ def _create_or_rerun_course(request): destination_course_key = rerun_course(request.user, source_course_key, org, course, run, fields) return JsonResponse({ 'url': reverse_url('course_handler'), - 'destination_course_key': six.text_type(destination_course_key) + 'destination_course_key': str(destination_course_key) }) else: try: new_course = create_new_course(request.user, org, course, run, fields) return JsonResponse({ 'url': reverse_course_url('course_handler', new_course.id), - 'course_key': six.text_type(new_course.id), + 'course_key': str(new_course.id), }) except ValidationError as ex: - return JsonResponse({'error': text_type(ex)}, status=400) + return JsonResponse({'error': str(ex)}, status=400) except DuplicateCourseError: return JsonResponse({ 'ErrMsg': _( @@ -912,7 +913,7 @@ def _create_or_rerun_course(request): }) except InvalidKeyError as error: return JsonResponse({ - "ErrMsg": _(u"Unable to create course '{name}'.\n\n{err}").format(name=display_name, err=text_type(error))} + "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(name=display_name, err=str(error))} ) @@ -997,7 +998,7 @@ def rerun_course(user, source_course_key, org, number, run, fields, background=T fields['video_upload_pipeline'] = {} json_fields = json.dumps(fields, cls=EdxJSONEncoder) - args = [six.text_type(source_course_key), six.text_type(destination_course_key), user.id, json_fields] + args = [str(source_course_key), str(destination_course_key), user.id, json_fields] if background: rerun_course_task.delay(*args) @@ -1306,7 +1307,7 @@ def grading_handler(request, course_key_string, grader_index=None): # update credit course requirements if 'minimum_grade_credit' # field value is changed if 'minimum_grade_credit' in request.json: - update_credit_course_requirements.delay(six.text_type(course_key)) + update_credit_course_requirements.delay(str(course_key)) # None implies update the whole model (cutoffs, graceperiod, and graders) not a specific grader if grader_index is None: @@ -1419,7 +1420,7 @@ def advanced_settings_handler(request, course_key_string): # update the course tabs if required by any setting changes _refresh_course_tabs(request, course_module) except InvalidTabsException as err: - log.exception(text_type(err)) + log.exception(str(err)) response_message = [ { 'message': _('An error occurred while trying to save your tabs'), @@ -1438,7 +1439,7 @@ def advanced_settings_handler(request, course_key_string): # Handle all errors that validation doesn't catch except (TypeError, ValueError, InvalidTabsException) as err: return HttpResponseBadRequest( - django.utils.html.escape(text_type(err)), + django.utils.html.escape(str(err)), content_type="text/plain" ) @@ -1476,7 +1477,7 @@ def validate_textbook_json(textbook): """ if isinstance(textbook, (bytes, bytearray)): # data appears as bytes textbook = textbook.decode('utf-8') - if isinstance(textbook, six.string_types): + if isinstance(textbook, str): try: textbook = json.loads(textbook) except ValueError: @@ -1485,7 +1486,7 @@ def validate_textbook_json(textbook): raise TextbookValidationError("must be JSON object") if not textbook.get("tab_title"): raise TextbookValidationError("must have tab_title") - tid = six.text_type(textbook.get("id", "")) + tid = str(textbook.get("id", "")) if tid and not tid[0].isdigit(): raise TextbookValidationError("textbook ID must start with a digit") return textbook @@ -1544,9 +1545,9 @@ def textbooks_list_handler(request, course_key_string): try: textbooks = validate_textbooks_json(request.body) except TextbookValidationError as err: - return JsonResponse({"error": text_type(err)}, status=400) + return JsonResponse({"error": str(err)}, status=400) - tids = set(t["id"] for t in textbooks if "id" in t) + tids = {t["id"] for t in textbooks if "id" in t} for textbook in textbooks: if "id" not in textbook: tid = assign_textbook_id(textbook, tids) @@ -1563,9 +1564,9 @@ def textbooks_list_handler(request, course_key_string): try: textbook = validate_textbook_json(request.body) except TextbookValidationError as err: - return JsonResponse({"error": text_type(err)}, status=400) + return JsonResponse({"error": str(err)}, status=400) if not textbook.get("id"): - tids = set(t["id"] for t in course.pdf_textbooks if "id" in t) + tids = {t["id"] for t in course.pdf_textbooks if "id" in t} textbook["id"] = assign_textbook_id(textbook, tids) existing = course.pdf_textbooks existing.append(textbook) @@ -1602,7 +1603,7 @@ def textbooks_detail_handler(request, course_key_string, textbook_id): with store.bulk_operations(course_key): course_module = get_course_and_check_access(course_key, request.user) matching_id = [tb for tb in course_module.pdf_textbooks - if six.text_type(tb.get("id")) == six.text_type(textbook_id)] + if str(tb.get("id")) == str(textbook_id)] if matching_id: textbook = matching_id[0] else: @@ -1616,7 +1617,7 @@ def textbooks_detail_handler(request, course_key_string, textbook_id): try: new_textbook = validate_textbook_json(request.body) except TextbookValidationError as err: - return JsonResponse({"error": text_type(err)}, status=400) + return JsonResponse({"error": str(err)}, status=400) new_textbook["id"] = textbook_id if textbook: i = course_module.pdf_textbooks.index(textbook) @@ -1761,7 +1762,7 @@ def group_configurations_list_handler(request, course_key_string): try: new_configuration = GroupConfiguration(request.body, course).get_user_partition() except GroupConfigurationsValidationError as err: - return JsonResponse({"error": text_type(err)}, status=400) + return JsonResponse({"error": str(err)}, status=400) course.user_partitions.append(new_configuration) response = JsonResponse(new_configuration.to_json(), status=201) @@ -1793,7 +1794,7 @@ def group_configurations_detail_handler(request, course_key_string, group_config with store.bulk_operations(course_key): course = get_course_and_check_access(course_key, request.user) matching_id = [p for p in course.user_partitions - if six.text_type(p.id) == six.text_type(group_configuration_id)] + if str(p.id) == str(group_configuration_id)] if matching_id: configuration = matching_id[0] else: @@ -1803,7 +1804,7 @@ def group_configurations_detail_handler(request, course_key_string, group_config try: new_configuration = GroupConfiguration(request.body, course, group_configuration_id).get_user_partition() # lint-amnesty, pylint: disable=line-too-long except GroupConfigurationsValidationError as err: - return JsonResponse({"error": text_type(err)}, status=400) + return JsonResponse({"error": str(err)}, status=400) if configuration: index = course.user_partitions.index(configuration) diff --git a/cms/djangoapps/contentstore/views/entrance_exam.py b/cms/djangoapps/contentstore/views/entrance_exam.py index 110609edb4..56c6309dd7 100644 --- a/cms/djangoapps/contentstore/views/entrance_exam.py +++ b/cms/djangoapps/contentstore/views/entrance_exam.py @@ -7,7 +7,6 @@ Intended to be utilized as an AJAX callback handler, versus a proper view/screen import logging from functools import wraps -import six from django.conf import settings from django.contrib.auth.decorators import login_required from django.http import HttpResponse, HttpResponseBadRequest @@ -17,10 +16,10 @@ from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey, UsageKey from cms.djangoapps.models.settings.course_metadata import CourseMetadata -from openedx.core.djangolib.js_utils import dump_js_escaped_json from common.djangoapps.student.auth import has_course_author_access from common.djangoapps.util import milestones_helpers from openedx.core import toggles as core_toggles +from openedx.core.djangolib.js_utils import dump_js_escaped_json from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError @@ -132,7 +131,7 @@ def _create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct=N return HttpResponse(status=400) # Create the entrance exam item (currently it's just a chapter) - parent_locator = six.text_type(course.location) + parent_locator = str(course.location) created_block = create_xblock( parent_locator=parent_locator, user=request.user, @@ -147,13 +146,13 @@ def _create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct=N metadata = { 'entrance_exam_enabled': True, 'entrance_exam_minimum_score_pct': entrance_exam_minimum_score_pct, - 'entrance_exam_id': six.text_type(created_block.location), + 'entrance_exam_id': str(created_block.location), } CourseMetadata.update_from_dict(metadata, course, request.user) # Create the entrance exam section item. create_xblock( - parent_locator=six.text_type(created_block.location), + parent_locator=str(created_block.location), user=request.user, category='sequential', display_name=_('Entrance Exam - Subsection') @@ -179,7 +178,7 @@ def _get_entrance_exam(request, course_key): try: exam_descriptor = modulestore().get_item(exam_key) return HttpResponse( # lint-amnesty, pylint: disable=http-response-with-content-type-json - dump_js_escaped_json({'locator': six.text_type(exam_descriptor.location)}), + dump_js_escaped_json({'locator': str(exam_descriptor.location)}), status=200, content_type='application/json') except ItemNotFoundError: return HttpResponse(status=404) @@ -248,7 +247,7 @@ def add_entrance_exam_milestone(course_id, x_block): # lint-amnesty, pylint: di if len(milestones): # lint-amnesty, pylint: disable=len-as-condition milestone = milestones[0] else: - description = u'Autogenerated during {} entrance exam creation.'.format(six.text_type(course_id)) + description = 'Autogenerated during {} entrance exam creation.'.format(str(course_id)) milestone = milestones_helpers.add_milestone({ 'name': _('Completed Course Entrance Exam'), 'namespace': milestone_namespace, @@ -256,13 +255,13 @@ def add_entrance_exam_milestone(course_id, x_block): # lint-amnesty, pylint: di }) relationship_types = milestones_helpers.get_milestone_relationship_types() milestones_helpers.add_course_milestone( - six.text_type(course_id), + str(course_id), relationship_types['REQUIRES'], milestone ) milestones_helpers.add_course_content_milestone( - six.text_type(course_id), - six.text_type(x_block.location), + str(course_id), + str(x_block.location), relationship_types['FULFILLS'], milestone ) @@ -279,4 +278,4 @@ def remove_entrance_exam_milestone_reference(request, course_key): for course_child in course_children: if course_child.is_entrance_exam: delete_item(request, course_child.scope_ids.usage_id) - milestones_helpers.remove_content_references(six.text_type(course_child.scope_ids.usage_id)) + milestones_helpers.remove_content_references(str(course_child.scope_ids.usage_id)) diff --git a/cms/djangoapps/contentstore/views/error.py b/cms/djangoapps/contentstore/views/error.py index 82d03f7c92..4506ba51f5 100644 --- a/cms/djangoapps/contentstore/views/error.py +++ b/cms/djangoapps/contentstore/views/error.py @@ -4,8 +4,8 @@ import functools from django.http import HttpResponse, HttpResponseNotFound, HttpResponseServerError from common.djangoapps.edxmako.shortcuts import render_to_response, render_to_string -from openedx.core.djangolib.js_utils import dump_js_escaped_json from common.djangoapps.util.views import fix_crum_request +from openedx.core.djangolib.js_utils import dump_js_escaped_json __all__ = ['not_found', 'server_error', 'render_404', 'render_500'] diff --git a/cms/djangoapps/contentstore/views/export_git.py b/cms/djangoapps/contentstore/views/export_git.py index c392347061..e86943f96a 100644 --- a/cms/djangoapps/contentstore/views/export_git.py +++ b/cms/djangoapps/contentstore/views/export_git.py @@ -6,7 +6,6 @@ the giturl attribute is set. import logging -import six from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.utils.translation import ugettext as _ @@ -34,7 +33,7 @@ def export_git(request, course_key_string): course_module = modulestore().get_course(course_key) failed = False - log.debug(u'export_git course_module=%s', course_module) + log.debug('export_git course_module=%s', course_module) msg = "" if 'action' in request.GET and course_module.giturl: @@ -48,7 +47,7 @@ def export_git(request, course_key_string): msg = _('Course successfully exported to git repository') except git_export_utils.GitExportError as ex: failed = True - msg = six.text_type(ex) + msg = str(ex) return render_to_response('export_git.html', { 'context_course': course_module, diff --git a/cms/djangoapps/contentstore/views/helpers.py b/cms/djangoapps/contentstore/views/helpers.py index 609d8e497e..4ed4ba1414 100644 --- a/cms/djangoapps/contentstore/views/helpers.py +++ b/cms/djangoapps/contentstore/views/helpers.py @@ -2,9 +2,9 @@ Helper methods for Studio views. """ +import urllib from uuid import uuid4 -import six from django.conf import settings from django.http import HttpResponse from django.utils.translation import ugettext as _ @@ -12,8 +12,8 @@ from opaque_keys.edx.keys import UsageKey from xblock.core import XBlock from cms.djangoapps.models.settings.course_grading import CourseGradingModel -from openedx.core.toggles import ENTRANCE_EXAMS from common.djangoapps.edxmako.shortcuts import render_to_string +from openedx.core.toggles import ENTRANCE_EXAMS from xmodule.modulestore.django import modulestore from xmodule.tabs import StaticTab @@ -107,9 +107,9 @@ def xblock_studio_url(xblock, parent_xblock=None): if category == 'course': return reverse_course_url('course_handler', xblock.location.course_key) elif category in ('chapter', 'sequential'): - return u'{url}?show={usage_key}'.format( + return '{url}?show={usage_key}'.format( url=reverse_course_url('course_handler', xblock.location.course_key), - usage_key=six.moves.urllib.parse.quote(six.text_type(xblock.location)) + usage_key=urllib.parse.quote(str(xblock.location)) ) elif category == 'library': library_key = xblock.location.course_key @@ -220,7 +220,7 @@ def create_xblock(parent_locator, user, category, display_name, boilerplate=None # TODO need to fix components that are sending definition_data as strings, instead of as dicts # For now, migrate them into dicts here. - if isinstance(data, six.string_types): + if isinstance(data, str): data = {'data': data} created_block = store.create_child( diff --git a/cms/djangoapps/contentstore/views/import_export.py b/cms/djangoapps/contentstore/views/import_export.py index 0a1f1b809d..c2be964cfb 100644 --- a/cms/djangoapps/contentstore/views/import_export.py +++ b/cms/djangoapps/contentstore/views/import_export.py @@ -25,7 +25,6 @@ from django.views.decorators.http import require_GET, require_http_methods from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryLocator from path import Path as path -from six import text_type from storages.backends.s3boto import S3BotoStorage from storages.backends.s3boto3 import S3Boto3Storage from user_tasks.conf import settings as user_tasks_settings @@ -123,7 +122,7 @@ def _write_chunk(request, courselike_key): course_dir = data_root / subdir filename = request.FILES['course-data'].name - courselike_string = text_type(courselike_key) + filename + courselike_string = str(courselike_key) + filename # Do everything in a try-except block to make sure everything is properly cleaned up. try: # Use sessions to keep info about import progress @@ -143,7 +142,7 @@ def _write_chunk(request, courselike_key): if not course_dir.isdir(): os.mkdir(course_dir) - logging.debug(u'importing course to {0}'.format(temp_filepath)) + logging.debug(f'importing course to {temp_filepath}') # Get upload chunks byte ranges try: @@ -165,7 +164,7 @@ def _write_chunk(request, courselike_key): if size < int(content_range['start']): _save_request_status(request, courselike_string, -1) log.warning( - u"Reported range %s does not match size downloaded so far %s", + "Reported range %s does not match size downloaded so far %s", content_range['start'], size ) @@ -200,19 +199,19 @@ def _write_chunk(request, courselike_key): }] }) - log.info(u"Course import %s: Upload complete", courselike_key) + log.info("Course import %s: Upload complete", courselike_key) with open(temp_filepath, 'rb') as local_file: django_file = File(local_file) - storage_path = course_import_export_storage.save(u'olx_import/' + filename, django_file) + storage_path = course_import_export_storage.save('olx_import/' + filename, django_file) import_olx.delay( - request.user.id, text_type(courselike_key), storage_path, filename, request.LANGUAGE_CODE) + request.user.id, str(courselike_key), storage_path, filename, request.LANGUAGE_CODE) # Send errors to client with stage at which error occurred. except Exception as exception: # pylint: disable=broad-except _save_request_status(request, courselike_string, -1) if course_dir.isdir(): shutil.rmtree(course_dir) - log.info(u"Course import %s: Temp data cleared", courselike_key) + log.info("Course import %s: Temp data cleared", courselike_key) log.exception( "error importing course" @@ -250,12 +249,12 @@ def import_status_handler(request, course_key_string, filename=None): raise PermissionDenied() # The task status record is authoritative once it's been created - args = {u'course_key_string': course_key_string, u'archive_name': filename} + args = {'course_key_string': course_key_string, 'archive_name': filename} name = CourseImportTask.generate_name(args) task_status = UserTaskStatus.objects.filter(name=name) for status_filter in STATUS_FILTERS: task_status = status_filter().filter_queryset(request, task_status, import_status_handler) - task_status = task_status.order_by(u'-created').first() + task_status = task_status.order_by('-created').first() if task_status is None: # The task hasn't been initialized yet; did we store info in the session already? try: @@ -279,7 +278,7 @@ def send_tarball(tarball, size): """ wrapper = FileWrapper(tarball, settings.COURSE_EXPORT_DOWNLOAD_CHUNK_SIZE) response = StreamingHttpResponse(wrapper, content_type='application/x-tgz') - response['Content-Disposition'] = u'attachment; filename=%s' % os.path.basename(tarball.name) + response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(tarball.name) response['Content-Length'] = size return response @@ -377,7 +376,7 @@ def export_status_handler(request, course_key_string): output_url = reverse_course_url('export_output_handler', course_key) elif isinstance(artifact.file.storage, S3BotoStorage): filename = os.path.basename(artifact.file.name) - disposition = u'attachment; filename="{}"'.format(filename) + disposition = f'attachment; filename="{filename}"' output_url = artifact.file.storage.url(artifact.file.name, response_headers={ 'response-content-disposition': disposition, 'response-content-encoding': 'application/octet-stream', @@ -385,7 +384,7 @@ def export_status_handler(request, course_key_string): }) elif isinstance(artifact.file.storage, S3Boto3Storage): filename = os.path.basename(artifact.file.name) - disposition = u'attachment; filename="{}"'.format(filename) + disposition = f'attachment; filename="{filename}"' output_url = artifact.file.storage.url(artifact.file.name, parameters={ 'ResponseContentDisposition': disposition, 'ResponseContentEncoding': 'application/octet-stream', @@ -450,9 +449,9 @@ def _latest_task_status(request, course_key_string, view_func=None): Get the most recent export status update for the specified course/library key. """ - args = {u'course_key_string': course_key_string} + args = {'course_key_string': course_key_string} name = CourseExportTask.generate_name(args) task_status = UserTaskStatus.objects.filter(name=name) for status_filter in STATUS_FILTERS: task_status = status_filter().filter_queryset(request, task_status, view_func) - return task_status.order_by(u'-created').first() + return task_status.order_by('-created').first() diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index 0286e98ee6..3dd7678c19 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -24,7 +24,6 @@ from help_tokens.core import HelpUrlExpert from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryUsageLocator from pytz import UTC -from six import binary_type, text_type from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Scope @@ -34,15 +33,15 @@ from cms.djangoapps.models.settings.course_grading import CourseGradingModel from cms.djangoapps.xblock_config.models import CourseEditLTIFieldsEnabledFlag from cms.lib.xblock.authoring_mixin import VISIBILITY_VIEW from common.djangoapps.edxmako.shortcuts import render_to_string -from openedx.core.lib.gating import api as gating_api -from openedx.core.lib.xblock_utils import hash_resource, request_token, wrap_xblock, wrap_xblock_aside -from openedx.core.djangoapps.bookmarks import api as bookmarks_api from common.djangoapps.static_replace import replace_static_urls from common.djangoapps.student.auth import has_studio_read_access, has_studio_write_access -from openedx.core.toggles import ENTRANCE_EXAMS from common.djangoapps.util.date_utils import get_default_time_display from common.djangoapps.util.json_request import JsonResponse, expect_json from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService +from openedx.core.djangoapps.bookmarks import api as bookmarks_api +from openedx.core.lib.gating import api as gating_api +from openedx.core.lib.xblock_utils import hash_resource, request_token, wrap_xblock, wrap_xblock_aside +from openedx.core.toggles import ENTRANCE_EXAMS from xmodule.course_module import DEFAULT_START_DATE from xmodule.library_tools import LibraryToolsService from xmodule.modulestore import EdxJSONEncoder, ModuleStoreEnum @@ -96,7 +95,7 @@ def _filter_entrance_exam_grader(graders): the grader type for a given section of a course """ if ENTRANCE_EXAMS.is_enabled(): - graders = [grader for grader in graders if grader.get('type') != u'Entrance Exam'] + graders = [grader for grader in graders if grader.get('type') != 'Entrance Exam'] return graders @@ -230,7 +229,7 @@ def xblock_handler(request, usage_key_string): _is_library_component_limit_reached(parent_usage_key)): return JsonResponse( { - 'error': _(u'Libraries cannot have more than {limit} components').format( + 'error': _('Libraries cannot have more than {limit} components').format( limit=settings.MAX_BLOCKS_PER_CONTENT_LIBRARY ) }, @@ -244,8 +243,8 @@ def xblock_handler(request, usage_key_string): request.json.get('display_name'), ) return JsonResponse({ - 'locator': text_type(dest_usage_key), - 'courseKey': text_type(dest_usage_key.course_key) + 'locator': str(dest_usage_key), + 'courseKey': str(dest_usage_key.course_key) }) else: return _create_item(request) @@ -269,7 +268,7 @@ def xblock_handler(request, usage_key_string): ) -class StudioPermissionsService(object): +class StudioPermissionsService: """ Service that can provide information about a user's permissions. @@ -289,7 +288,7 @@ class StudioPermissionsService(object): return has_studio_write_access(self._user, course_key) -class StudioEditModuleRuntime(object): +class StudioEditModuleRuntime: """ An extremely minimal ModuleSystem shim used for XBlock edits and studio_view. (i.e. whenever we're not using PreviewModuleSystem.) This is required to make information @@ -321,7 +320,7 @@ class StudioEditModuleRuntime(object): return None -@require_http_methods(("GET")) +@require_http_methods("GET") @login_required @expect_json def xblock_view_handler(request, usage_key_string, view_name): @@ -349,14 +348,14 @@ def xblock_view_handler(request, usage_key_string, view_name): xblock.runtime.wrappers.append(partial( wrap_xblock, 'StudioRuntime', - usage_id_serializer=text_type, + usage_id_serializer=str, request_token=request_token(request), )) xblock.runtime.wrappers_asides.append(partial( wrap_xblock_aside, 'StudioRuntime', - usage_id_serializer=text_type, + usage_id_serializer=str, request_token=request_token(request), extra_classes=['wrapper-comp-plugins'] )) @@ -371,7 +370,7 @@ def xblock_view_handler(request, usage_key_string, view_name): # dungeon and surface as uneditable, unsaveable, and undeletable # component-goblins. except Exception as exc: # pylint: disable=broad-except - log.debug(u"Unable to render %s for %r", view_name, xblock, exc_info=True) + log.debug("Unable to render %s for %r", view_name, xblock, exc_info=True) fragment = Fragment(render_to_string('html_error.html', {'message': str(exc)})) elif view_name in PREVIEW_VIEWS + container_views: @@ -395,8 +394,8 @@ def xblock_view_handler(request, usage_key_string, view_name): } except ValueError: return HttpResponse( - content=u"Couldn't parse paging parameters: enable_paging: " - u"{0}, page_number: {1}, page_size: {2}".format( + content="Couldn't parse paging parameters: enable_paging: " + "{}, page_number: {}, page_size: {}".format( request.GET.get('enable_paging', 'false'), request.GET.get('page_number', 0), request.GET.get('page_size', 0) @@ -440,7 +439,7 @@ def xblock_view_handler(request, usage_key_string, view_name): hashed_resources[hash_resource(resource)] = resource._asdict() fragment_content = fragment.content - if isinstance(fragment_content, binary_type): + if isinstance(fragment_content, bytes): fragment_content = fragment.content.decode('utf-8') return JsonResponse({ @@ -452,7 +451,7 @@ def xblock_view_handler(request, usage_key_string, view_name): return HttpResponse(status=406) -@require_http_methods(("GET")) +@require_http_methods("GET") @login_required @expect_json def xblock_outline_handler(request, usage_key_string): @@ -480,7 +479,7 @@ def xblock_outline_handler(request, usage_key_string): return Http404 -@require_http_methods(("GET")) +@require_http_methods("GET") @login_required @expect_json def xblock_container_handler(request, usage_key_string): @@ -540,7 +539,7 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None, store.revert_to_published(xblock.location, user.id) # Returning the same sort of result that we do for other save operations. In the future, # we may want to return the full XBlockInfo. - return JsonResponse({'id': text_type(xblock.location)}) + return JsonResponse({'id': str(xblock.location)}) old_metadata = own_metadata(xblock) old_content = xblock.get_explicitly_set_fields_by_scope(Scope.content) @@ -619,8 +618,8 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None, value = field.from_json(value) except ValueError as verr: reason = _("Invalid data") - if text_type(verr): - reason = _(u"Invalid data ({details})").format(details=text_type(verr)) + if str(verr): + reason = _("Invalid data ({details})").format(details=str(verr)) return JsonResponse({"error": reason}, 400) field.write_to(xblock, value) @@ -647,7 +646,7 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None, store.update_item(course, user.id) result = { - 'id': text_type(xblock.location), + 'id': str(xblock.location), 'data': data, 'metadata': own_metadata(xblock) } @@ -712,13 +711,13 @@ def _create_item(request): # Only these categories are supported at this time. if category not in ['html', 'problem', 'video']: return HttpResponseBadRequest( - u"Category '%s' not supported for Libraries" % category, content_type='text/plain' + "Category '%s' not supported for Libraries" % category, content_type='text/plain' ) if _is_library_component_limit_reached(usage_key): return JsonResponse( { - 'error': _(u'Libraries cannot have more than {limit} components').format( + 'error': _('Libraries cannot have more than {limit} components').format( limit=settings.MAX_BLOCKS_PER_CONTENT_LIBRARY ) }, @@ -734,7 +733,7 @@ def _create_item(request): ) return JsonResponse( - {'locator': text_type(created_block.location), 'courseKey': text_type(created_block.location.course_key)} + {'locator': str(created_block.location), 'courseKey': str(created_block.location.course_key)} ) @@ -766,7 +765,7 @@ def is_source_item_in_target_parents(source_item, target_parent): """ target_ancestors = _create_xblock_ancestor_info(target_parent, is_concise=True)['ancestors'] for target_ancestor in target_ancestors: - if text_type(source_item.location) == target_ancestor['id']: + if str(source_item.location) == target_ancestor['id']: return True return False @@ -786,7 +785,7 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non """ # Get the list of all parentable component type XBlocks. parent_component_types = list( - set(name for name, class_ in XBlock.load_classes() if getattr(class_, 'has_children', False)) - + {name for name, class_ in XBlock.load_classes() if getattr(class_, 'has_children', False)} - set(DIRECT_ONLY_CATEGORIES) ) @@ -810,7 +809,7 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non if (valid_move_type.get(target_parent_type, '') != source_type and target_parent_type not in parent_component_types): - error = _(u'You can not move {source_type} into {target_parent_type}.').format( + error = _('You can not move {source_type} into {target_parent_type}.').format( source_type=source_type, target_parent_type=target_parent_type, ) @@ -823,20 +822,20 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non elif target_parent_type == 'split_test': error = _('You can not move an item directly into content experiment.') elif source_index is None: - error = _(u'{source_usage_key} not found in {parent_usage_key}.').format( - source_usage_key=text_type(source_usage_key), - parent_usage_key=text_type(source_parent.location) + error = _('{source_usage_key} not found in {parent_usage_key}.').format( + source_usage_key=str(source_usage_key), + parent_usage_key=str(source_parent.location) ) else: try: target_index = int(target_index) if target_index is not None else None if target_index is not None and len(target_parent.children) < target_index: - error = _(u'You can not move {source_usage_key} at an invalid index ({target_index}).').format( - source_usage_key=text_type(source_usage_key), + error = _('You can not move {source_usage_key} at an invalid index ({target_index}).').format( + source_usage_key=str(source_usage_key), target_index=target_index ) except ValueError: - error = _(u'You must provide target_index ({target_index}) as an integer.').format( + error = _('You must provide target_index ({target_index}) as an integer.').format( target_index=target_index ) if error: @@ -854,16 +853,16 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non ) log.info( - u'MOVE: %s moved from %s to %s at %d index', - text_type(source_usage_key), - text_type(source_parent.location), - text_type(target_parent_usage_key), + 'MOVE: %s moved from %s to %s at %d index', + str(source_usage_key), + str(source_parent.location), + str(target_parent_usage_key), insert_at ) context = { - 'move_source_locator': text_type(source_usage_key), - 'parent_locator': text_type(target_parent_usage_key), + 'move_source_locator': str(source_usage_key), + 'parent_locator': str(target_parent_usage_key), 'source_index': target_index if target_index is not None else source_index } return JsonResponse(context) @@ -895,9 +894,9 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, user, display_ duplicate_metadata['display_name'] = display_name else: if source_item.display_name is None: - duplicate_metadata['display_name'] = _(u"Duplicate of {0}").format(source_item.category) + duplicate_metadata['display_name'] = _("Duplicate of {0}").format(source_item.category) else: - duplicate_metadata['display_name'] = _(u"Duplicate of '{0}'").format(source_item.display_name) + duplicate_metadata['display_name'] = _("Duplicate of '{0}'").format(source_item.display_name) asides_to_create = [] for aside in source_item.runtime.get_asides(source_item): @@ -1000,7 +999,7 @@ def orphan_handler(request, course_key_string): course_usage_key = CourseKey.from_string(course_key_string) if request.method == 'GET': if has_studio_read_access(request.user, course_usage_key): - return JsonResponse([text_type(item) for item in modulestore().get_orphans(course_usage_key)]) + return JsonResponse([str(item) for item in modulestore().get_orphans(course_usage_key)]) else: raise PermissionDenied() if request.method == 'DELETE': @@ -1028,7 +1027,7 @@ def _delete_orphans(course_usage_key, user_id, commit=False): if branch == ModuleStoreEnum.BranchName.published: revision = ModuleStoreEnum.RevisionOption.published_only store.delete_item(itemloc, user_id, revision=revision) - return [text_type(item) for item in items] + return [str(item) for item in items] def _get_xblock(usage_key, user): @@ -1052,7 +1051,7 @@ def _get_xblock(usage_key, user): raise except InvalidLocationError: log.error("Can't find item by location.") - return JsonResponse({"error": "Can't find item by location: " + text_type(usage_key)}, 404) + return JsonResponse({"error": "Can't find item by location: " + str(usage_key)}, 404) def _get_module_info(xblock, rewrite_static_links=True, include_ancestor_info=False, include_publishing_info=False): @@ -1104,7 +1103,7 @@ def _get_gating_info(course, xblock): course.gating_prerequisites = gating_api.get_prerequisites(course.id) info["is_prereq"] = gating_api.is_prerequisite(course.id, xblock.location) info["prereqs"] = [ - p for p in course.gating_prerequisites if text_type(xblock.location) not in p['namespace'] + p for p in course.gating_prerequisites if str(xblock.location) not in p['namespace'] ] prereq, prereq_min_score, prereq_min_completion = gating_api.get_required_content( course.id, @@ -1199,14 +1198,14 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F # Translators: The {pct_sign} here represents the percent sign, i.e., '%' # in many languages. This is used to avoid Transifex's misinterpreting of # '% o'. The percent sign is also translatable as a standalone string. - explanatory_message = _(u'Students must score {score}{pct_sign} or higher to access course materials.').format( + explanatory_message = _('Students must score {score}{pct_sign} or higher to access course materials.').format( score=int(parent_xblock.entrance_exam_minimum_score_pct * 100), # Translators: This is the percent sign. It will be used to represent # a percent value out of 100, e.g. "58%" means "58/100". pct_sign=_('%')) xblock_info = { - 'id': text_type(xblock.location), + 'id': str(xblock.location), 'display_name': xblock.display_name_with_default, 'category': xblock.category, 'has_children': xblock.has_children @@ -1399,7 +1398,7 @@ def add_container_page_publishing_info(xblock, xblock_info): xblock_info["staff_lock_from"] = None -class VisibilityState(object): +class VisibilityState: """ Represents the possible visibility states for an xblock: @@ -1575,6 +1574,6 @@ def _xblock_type_and_display_name(xblock): """ Returns a string representation of the xblock's type and display name """ - return _(u'{section_or_subsection} "{display_name}"').format( + return _('{section_or_subsection} "{display_name}"').format( section_or_subsection=xblock_type_display_name(xblock), display_name=xblock.display_name_with_default) diff --git a/cms/djangoapps/contentstore/views/library.py b/cms/djangoapps/contentstore/views/library.py index 7b912fcc7d..5a85555cdb 100644 --- a/cms/djangoapps/contentstore/views/library.py +++ b/cms/djangoapps/contentstore/views/library.py @@ -19,7 +19,6 @@ from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryLocator, LibraryUsageLocator from organizations.api import ensure_organization from organizations.exceptions import InvalidOrganizationException -from six import text_type from cms.djangoapps.course_creators.views import get_course_creator_status from common.djangoapps.edxmako.shortcuts import render_to_response @@ -123,14 +122,14 @@ def _display_library(library_key_string, request): raise Http404 # This is not a library if not has_studio_read_access(request.user, library_key): log.exception( - u"User %s tried to access library %s without permission", - request.user.username, text_type(library_key) + "User %s tried to access library %s without permission", + request.user.username, str(library_key) ) raise PermissionDenied() library = modulestore().get_library(library_key) if library is None: - log.exception(u"Library %s not found", text_type(library_key)) + log.exception("Library %s not found", str(library_key)) raise Http404 response_format = 'html' @@ -161,7 +160,7 @@ def _list_libraries(request): lib_info = [ { "display_name": lib.display_name, - "library_key": text_type(lib.location.library_key), + "library_key": str(lib.location.library_key), } for lib in libraries if ( @@ -202,12 +201,12 @@ def _create_library(request): except KeyError as error: log.exception("Unable to create library - missing required JSON key.") return JsonResponseBadRequest({ - "ErrMsg": _(u"Unable to create library - missing required field '{field}'").format(field=text_type(error)) + "ErrMsg": _("Unable to create library - missing required field '{field}'").format(field=str(error)) }) except InvalidKeyError as error: log.exception("Unable to create library - invalid key.") return JsonResponseBadRequest({ - "ErrMsg": _(u"Unable to create library '{name}'.\n\n{err}").format(name=display_name, err=text_type(error)) + "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format(name=display_name, err=str(error)) }) except DuplicateCourseError: log.exception("Unable to create library - one already exists with the same key.") @@ -226,7 +225,7 @@ def _create_library(request): ).format(organization_key=org) }) - lib_key_str = text_type(new_lib.location.library_key) + lib_key_str = str(new_lib.location.library_key) return JsonResponse({ 'url': reverse_library_url('library_handler', lib_key_str), 'library_key': lib_key_str, @@ -252,10 +251,10 @@ def library_blocks_view(library, user, response_format): prev_version = library.runtime.course_entry.structure['previous_version'] return JsonResponse({ "display_name": library.display_name, - "library_id": text_type(library.location.library_key), - "version": text_type(library.runtime.course_entry.course_key.version_guid), - "previous_version": text_type(prev_version) if prev_version else None, - "blocks": [text_type(x) for x in children], + "library_id": str(library.location.library_key), + "version": str(library.runtime.course_entry.course_key.version_guid), + "previous_version": str(prev_version) if prev_version else None, + "blocks": [str(x) for x in children], }) can_edit = has_studio_write_access(user, library.location.library_key) @@ -305,7 +304,7 @@ def manage_library_users(request, library_key_string): 'context_library': library, 'users': formatted_users, 'allow_actions': bool(user_perms & STUDIO_EDIT_ROLES), - 'library_key': text_type(library_key), + 'library_key': str(library_key), 'lib_users_url': reverse_library_url('manage_library_users', library_key_string), 'show_children_previews': library.show_children_previews }) diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index 49569ee145..ab301de5ef 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -3,7 +3,6 @@ import logging from functools import partial -import six from django.conf import settings from django.contrib.auth.decorators import login_required from django.http import Http404, HttpResponseBadRequest @@ -16,10 +15,11 @@ from xblock.django.request import django_to_webob_request, webob_to_django_respo from xblock.exceptions import NoSuchHandlerError from xblock.runtime import KvsFieldData -from common.djangoapps import static_replace from cms.djangoapps.xblock_config.models import StudioConfig from cms.lib.xblock.field_data import CmsFieldData +from common.djangoapps import static_replace from common.djangoapps.edxmako.shortcuts import render_to_string +from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService from lms.djangoapps.lms_xblock.field_data import LmsFieldData from openedx.core.lib.license import wrap_with_license from openedx.core.lib.xblock_utils import ( @@ -30,7 +30,6 @@ from openedx.core.lib.xblock_utils import ( wrap_xblock_aside, xblock_local_resource_url ) -from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService from xmodule.contentstore.django import contentstore from xmodule.error_module import ErrorBlock from xmodule.exceptions import NotFoundError, ProcessingError @@ -73,7 +72,7 @@ def preview_handler(request, usage_key_string, handler, suffix=''): resp = instance.handle(handler, req, suffix) except NoSuchHandlerError: - log.exception(u"XBlock %s attempted to access missing handler %r", instance, handler) + log.exception("XBlock %s attempted to access missing handler %r", instance, handler) raise Http404 # lint-amnesty, pylint: disable=raise-missing-from except NotFoundError: @@ -102,7 +101,7 @@ class PreviewModuleSystem(ModuleSystem): # pylint: disable=abstract-method def handler_url(self, block, handler_name, suffix='', query='', thirdparty=False): return reverse('preview_handler', kwargs={ - 'usage_key_string': six.text_type(block.scope_ids.usage_id), + 'usage_key_string': str(block.scope_ids.usage_id), 'handler': handler_name, 'suffix': suffix, }) + '?' + query @@ -121,7 +120,7 @@ class PreviewModuleSystem(ModuleSystem): # pylint: disable=abstract-method # (see https://openedx.atlassian.net/browse/TE-811) return [ aside_type - for aside_type in super(PreviewModuleSystem, self).applicable_aside_types(block) # lint-amnesty, pylint: disable=super-with-arguments + for aside_type in super().applicable_aside_types(block) if aside_type != 'acid_aside' ] @@ -138,7 +137,7 @@ class PreviewModuleSystem(ModuleSystem): # pylint: disable=abstract-method for aside, aside_fn in aside_frag_fns: aside_frag = aside_fn(block, context) - if aside_frag.content != u'': + if aside_frag.content != '': aside_frag_wrapped = self.wrap_aside(block, aside, view_name, aside_frag, context) aside.save() result.add_fragment_resources(aside_frag_wrapped) @@ -167,7 +166,7 @@ def _preview_module_system(request, descriptor, field_data): wrap_xblock, 'PreviewRuntime', display_name_only=display_name_only, - usage_id_serializer=six.text_type, + usage_id_serializer=str, request_token=request_token(request) ), @@ -181,7 +180,7 @@ def _preview_module_system(request, descriptor, field_data): partial( wrap_xblock_aside, 'PreviewRuntime', - usage_id_serializer=six.text_type, + usage_id_serializer=str, request_token=request_token(request) ) ] @@ -285,7 +284,7 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): is_reorderable = _is_xblock_reorderable(xblock, context) selected_groups_label = get_visibility_partition_info(xblock)['selected_groups_label'] if selected_groups_label: - selected_groups_label = _(u'Access restricted to: {list_of_groups}').format(list_of_groups=selected_groups_label) # lint-amnesty, pylint: disable=line-too-long + selected_groups_label = _('Access restricted to: {list_of_groups}').format(list_of_groups=selected_groups_label) # lint-amnesty, pylint: disable=line-too-long course = modulestore().get_course(xblock.location.course_key) template_context = { 'xblock_context': context, @@ -326,6 +325,6 @@ def get_preview_fragment(request, descriptor, context): try: fragment = module.render(preview_view, context) except Exception as exc: # pylint: disable=broad-except - log.warning(u"Unable to render %s for %r", preview_view, module, exc_info=True) + log.warning("Unable to render %s for %r", preview_view, module, exc_info=True) fragment = Fragment(render_to_string('html_error.html', {'message': str(exc)})) return fragment diff --git a/cms/djangoapps/contentstore/views/public.py b/cms/djangoapps/contentstore/views/public.py index b6fd4a5474..90db9ef479 100644 --- a/cms/djangoapps/contentstore/views/public.py +++ b/cms/djangoapps/contentstore/views/public.py @@ -59,7 +59,7 @@ def howitworks(request): return render_to_response('howitworks.html', {}) -@waffle_switch('{}.{}'.format(waffle.WAFFLE_NAMESPACE, waffle.ENABLE_ACCESSIBILITY_POLICY_PAGE)) +@waffle_switch(f'{waffle.WAFFLE_NAMESPACE}.{waffle.ENABLE_ACCESSIBILITY_POLICY_PAGE}') def accessibility(request): """ Display the accessibility accommodation form. diff --git a/cms/djangoapps/contentstore/views/tabs.py b/cms/djangoapps/contentstore/views/tabs.py index b299a760e1..bfc8a4b3b7 100644 --- a/cms/djangoapps/contentstore/views/tabs.py +++ b/cms/djangoapps/contentstore/views/tabs.py @@ -1,9 +1,6 @@ """ Views related to course tabs """ - - -import six from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.http import HttpResponseNotFound @@ -100,7 +97,7 @@ def reorder_tabs_handler(course_item, request): tab = get_tab_by_tab_id_locator(old_tab_list, tab_id_locator) if tab is None: return JsonResponse( - {"error": u"Tab with id_locator '{0}' does not exist.".format(tab_id_locator)}, status=400 + {"error": f"Tab with id_locator '{tab_id_locator}' does not exist."}, status=400 ) new_tab_list.append(tab) @@ -114,7 +111,7 @@ def reorder_tabs_handler(course_item, request): CourseTabList.validate_tabs(new_tab_list) except InvalidTabsException as exception: return JsonResponse( - {"error": u"New list of tabs is not valid: {0}.".format(str(exception))}, status=400 + {"error": "New list of tabs is not valid: {}.".format(str(exception))}, status=400 ) # persist the new order of the tabs @@ -136,7 +133,7 @@ def edit_tab_handler(course_item, request): tab = get_tab_by_tab_id_locator(course_item.tabs, tab_id_locator) if tab is None: return JsonResponse( - {"error": u"Tab with id_locator '{0}' does not exist.".format(tab_id_locator)}, status=400 + {"error": f"Tab with id_locator '{tab_id_locator}' does not exist."}, status=400 ) if 'is_hidden' in request.json: @@ -144,7 +141,7 @@ def edit_tab_handler(course_item, request): tab.is_hidden = request.json['is_hidden'] modulestore().update_item(course_item, request.user.id) else: - raise NotImplementedError(u'Unsupported request to edit tab: {0}'.format(request.json)) + raise NotImplementedError(f'Unsupported request to edit tab: {request.json}') return JsonResponse() @@ -200,7 +197,7 @@ def primitive_delete(course, num): def primitive_insert(course, num, tab_type, name): "Inserts a new tab at the given number (0 based)." validate_args(num, tab_type) - new_tab = CourseTab.from_json({u'type': six.text_type(tab_type), u'name': six.text_type(name)}) + new_tab = CourseTab.from_json({'type': str(tab_type), 'name': str(name)}) tabs = course.tabs tabs.insert(num, new_tab) modulestore().update_item(course, ModuleStoreEnum.UserID.primitive_command) diff --git a/cms/djangoapps/contentstore/views/tests/test_access.py b/cms/djangoapps/contentstore/views/tests/test_access.py index 5b171173c8..531d0f471a 100644 --- a/cms/djangoapps/contentstore/views/tests/test_access.py +++ b/cms/djangoapps/contentstore/views/tests/test_access.py @@ -20,7 +20,7 @@ class RolesTest(TestCase): """ def setUp(self): """ Test case setup """ - super(RolesTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.global_admin = AdminFactory() self.instructor = User.objects.create_user('testinstructor', 'testinstructor+courses@edx.org', 'foo') diff --git a/cms/djangoapps/contentstore/views/tests/test_assets.py b/cms/djangoapps/contentstore/views/tests/test_assets.py index 96ae66cad5..b85770ce18 100644 --- a/cms/djangoapps/contentstore/views/tests/test_assets.py +++ b/cms/djangoapps/contentstore/views/tests/test_assets.py @@ -6,13 +6,12 @@ Unit tests for the asset upload endpoint. import json from datetime import datetime from io import BytesIO +from unittest import mock +from unittest.mock import patch -import mock -import six from ddt import data, ddt from django.conf import settings from django.test.utils import override_settings -from mock import patch from opaque_keys.edx.keys import AssetKey from opaque_keys.edx.locator import CourseLocator from PIL import Image @@ -43,7 +42,7 @@ class AssetsTestCase(CourseTestCase): Parent class for all asset tests. """ def setUp(self): - super(AssetsTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse_course_url('assets_handler', self.course.id) def upload_asset(self, name="asset-1", asset_type='text'): @@ -61,14 +60,14 @@ class AssetsTestCase(CourseTestCase): sample_asset = BytesIO() sample_file_contents = b"This file is generated by python unit test" if asset_type == 'text': - sample_asset.name = '{name}.txt'.format(name=name) + sample_asset.name = f'{name}.txt' sample_asset.write(sample_file_contents) elif asset_type == 'image': image = Image.new("RGB", size=(50, 50), color=(256, 0, 0)) image.save(sample_asset, 'jpeg') - sample_asset.name = '{name}.jpg'.format(name=name) + sample_asset.name = f'{name}.jpg' elif asset_type == 'opendoc': - sample_asset.name = '{name}.odt'.format(name=name) + sample_asset.name = f'{name}.odt' sample_asset.write(sample_file_contents) sample_asset.seek(0) return sample_asset @@ -131,12 +130,12 @@ class BasicAssetsTestCase(AssetsTestCase): course = module_store.get_course(course_id) filename = 'sample_static.html' - html_src_attribute = '"/static/{}"'.format(filename) + html_src_attribute = f'"/static/{filename}"' asset_url = replace_static_urls(html_src_attribute, course_id=course.id) url = asset_url.replace('"', '') base_url = url.replace(filename, '') - self.assertIn("/{}".format(filename), url) + self.assertIn(f"/{filename}", url) resp = self.client.get(url) self.assertEqual(resp.status_code, 200) @@ -146,7 +145,7 @@ class BasicAssetsTestCase(AssetsTestCase): # browser append relative_path with base_url absolute_path = base_url + relative_path - self.assertIn("/{}".format(relative_path), absolute_path) + self.assertIn(f"/{relative_path}", absolute_path) resp = self.client.get(absolute_path) self.assertEqual(resp.status_code, 200) @@ -343,7 +342,7 @@ class UploadTestCase(AssetsTestCase): Unit tests for uploading a file """ def setUp(self): - super(UploadTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse_course_url('assets_handler', self.course.id) def test_happy_path(self): @@ -378,7 +377,7 @@ class DownloadTestCase(AssetsTestCase): Unit tests for downloading a file. """ def setUp(self): - super(DownloadTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse_course_url('assets_handler', self.course.id) # First, upload something. self.asset_name = 'download_test' @@ -430,7 +429,7 @@ class AssetToJsonTestCase(AssetsTestCase): ) self.assertEqual(output["portable_url"], "/static/my_file_name.jpg") self.assertEqual(output["thumbnail"], "/asset-v1:org+class+run+type@thumbnail+block@my_file_name_thumb.jpg") - self.assertEqual(output["id"], six.text_type(location)) + self.assertEqual(output["id"], str(location)) self.assertEqual(output['locked'], True) output = assets._get_asset_json("name", content_type, upload_date, location, None, False) @@ -458,7 +457,7 @@ class LockAssetTestCase(AssetsTestCase): upload_date = datetime(2013, 6, 1, 10, 30, tzinfo=UTC) asset_location = course.id.make_asset_key('asset', 'sample_static.html') url = reverse_course_url( - 'assets_handler', course.id, kwargs={'asset_key_string': six.text_type(asset_location)} + 'assets_handler', course.id, kwargs={'asset_key_string': str(asset_location)} ) resp = self.client.post( @@ -502,7 +501,7 @@ class DeleteAssetTestCase(AssetsTestCase): """ def setUp(self): """ Scaffolding """ - super(DeleteAssetTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse_course_url('assets_handler', self.course.id) # First, upload something. self.asset_name = 'delete_test' @@ -518,7 +517,7 @@ class DeleteAssetTestCase(AssetsTestCase): def test_delete_asset(self): """ Tests the happy path :) """ test_url = reverse_course_url( - 'assets_handler', self.course.id, kwargs={'asset_key_string': six.text_type(self.uploaded_url)}) + 'assets_handler', self.course.id, kwargs={'asset_key_string': str(self.uploaded_url)}) resp = self.client.delete(test_url, HTTP_ACCEPT="application/json") self.assertEqual(resp.status_code, 204) @@ -547,7 +546,7 @@ class DeleteAssetTestCase(AssetsTestCase): mock_asset_key.return_value = thumbnail_location test_url = reverse_course_url( - 'assets_handler', self.course.id, kwargs={'asset_key_string': six.text_type(uploaded_image_url)}) + 'assets_handler', self.course.id, kwargs={'asset_key_string': str(uploaded_image_url)}) resp = self.client.delete(test_url, HTTP_ACCEPT="application/json") self.assertEqual(resp.status_code, 204) @@ -555,7 +554,7 @@ class DeleteAssetTestCase(AssetsTestCase): """ Tests the sad path :( """ test_url = reverse_course_url( 'assets_handler', - self.course.id, kwargs={'asset_key_string': six.text_type("/c4x/edX/toy/asset/invalid.pdf")} + self.course.id, kwargs={'asset_key_string': "/c4x/edX/toy/asset/invalid.pdf"} ) resp = self.client.delete(test_url, HTTP_ACCEPT="application/json") self.assertEqual(resp.status_code, 404) @@ -563,7 +562,7 @@ class DeleteAssetTestCase(AssetsTestCase): def test_delete_asset_with_invalid_thumbnail(self): """ Tests the sad path :( """ test_url = reverse_course_url( - 'assets_handler', self.course.id, kwargs={'asset_key_string': six.text_type(self.uploaded_url)}) + 'assets_handler', self.course.id, kwargs={'asset_key_string': str(self.uploaded_url)}) self.content.thumbnail_location = StaticContent.get_location_from_path('/c4x/edX/toy/asset/invalid') contentstore().save(self.content) resp = self.client.delete(test_url, HTTP_ACCEPT="application/json") diff --git a/cms/djangoapps/contentstore/views/tests/test_certificates.py b/cms/djangoapps/contentstore/views/tests/test_certificates.py index 24ca0b4628..10ad19f03c 100644 --- a/cms/djangoapps/contentstore/views/tests/test_certificates.py +++ b/cms/djangoapps/contentstore/views/tests/test_certificates.py @@ -1,5 +1,3 @@ -#-*- coding: utf-8 -*- - """ Certificates Tests. """ @@ -7,14 +5,12 @@ Certificates Tests. import itertools import json +from unittest import mock import ddt -import mock -import six from django.conf import settings from django.test.utils import override_settings from opaque_keys.edx.keys import AssetKey -from six.moves import range from cms.djangoapps.contentstore.tests.utils import CourseTestCase from cms.djangoapps.contentstore.utils import get_lms_link_for_certificate_web_view, reverse_course_url @@ -33,19 +29,19 @@ FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy() FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True CERTIFICATE_JSON = { - u'name': u'Test certificate', - u'description': u'Test description', - u'is_active': True, - u'version': CERTIFICATE_SCHEMA_VERSION, + 'name': 'Test certificate', + 'description': 'Test description', + 'is_active': True, + 'version': CERTIFICATE_SCHEMA_VERSION, } CERTIFICATE_JSON_WITH_SIGNATORIES = { - u'name': u'Test certificate', - u'description': u'Test description', - u'version': CERTIFICATE_SCHEMA_VERSION, - u'course_title': 'Course Title Override', - u'is_active': True, - u'signatories': [ + 'name': 'Test certificate', + 'description': 'Test description', + 'version': CERTIFICATE_SCHEMA_VERSION, + 'course_title': 'Course Title Override', + 'is_active': True, + 'signatories': [ { "name": "Bob Smith", "title": "The DEAN.", @@ -59,7 +55,7 @@ SIGNATORY_PATH = 'asset-v1:test+CSS101+SP2017+type@asset+block@Signature{}.png' # pylint: disable=no-member -class HelperMethods(object): +class HelperMethods: """ Mixin that provides useful methods for certificate configuration tests. """ @@ -107,7 +103,7 @@ class HelperMethods(object): # pylint: disable=no-member -class CertificatesBaseTestCase(object): +class CertificatesBaseTestCase: """ Mixin with base test cases for the certificates. """ @@ -128,8 +124,8 @@ class CertificatesBaseTestCase(object): bad_jsons = [ # must have name of the certificate { - u'description': 'Test description', - u'version': CERTIFICATE_SCHEMA_VERSION + 'description': 'Test description', + 'version': CERTIFICATE_SCHEMA_VERSION }, # an empty json @@ -155,8 +151,8 @@ class CertificatesBaseTestCase(object): Test invalid json handling. """ # Invalid JSON. - invalid_json = u"{u'name': 'Test Name', u'description': 'Test description'," \ - u" u'version': " + str(CERTIFICATE_SCHEMA_VERSION) + ", []}" + invalid_json = "{u'name': 'Test Name', u'description': 'Test description'," \ + " u'version': " + str(CERTIFICATE_SCHEMA_VERSION) + ", []}" response = self.client.post( self._url(), @@ -174,9 +170,9 @@ class CertificatesBaseTestCase(object): def test_certificate_data_validation(self): #Test certificate schema version json_data_1 = { - u'version': 100, - u'name': u'Test certificate', - u'description': u'Test description' + 'version': 100, + 'name': 'Test certificate', + 'description': 'Test description' } with self.assertRaises(Exception) as context: @@ -189,8 +185,8 @@ class CertificatesBaseTestCase(object): #Test certificate name is missing json_data_2 = { - u'version': CERTIFICATE_SCHEMA_VERSION, - u'description': u'Test description' + 'version': CERTIFICATE_SCHEMA_VERSION, + 'description': 'Test description' } with self.assertRaises(Exception) as context: @@ -212,7 +208,7 @@ class CertificatesListHandlerTestCase( """ Set up CertificatesListHandlerTestCase. """ - super(CertificatesListHandlerTestCase, self).setUp('cms.djangoapps.contentstore.views.certificates.tracker') # lint-amnesty, pylint: disable=super-with-arguments + super().setUp('cms.djangoapps.contentstore.views.certificates.tracker') self.reset_urls() def _url(self): @@ -226,11 +222,11 @@ class CertificatesListHandlerTestCase( Test that you can create a certificate. """ expected = { - u'version': CERTIFICATE_SCHEMA_VERSION, - u'name': u'Test certificate', - u'description': u'Test description', - u'is_active': True, - u'signatories': [] + 'version': CERTIFICATE_SCHEMA_VERSION, + 'name': 'Test certificate', + 'description': 'Test description', + 'is_active': True, + 'signatories': [] } response = self.client.ajax_post( self._url(), @@ -244,7 +240,7 @@ class CertificatesListHandlerTestCase( self.assertEqual(content, expected) self.assert_event_emitted( 'edx.certificate.configuration.created', - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), configuration_id=certificate_id, ) @@ -272,7 +268,7 @@ class CertificatesListHandlerTestCase( @override_settings(LMS_BASE="lms_base_url") def test_lms_link_for_certificate_web_view(self): test_url = "//lms_base_url/certificates/" \ - "course/" + six.text_type(self.course.id) + '?preview=honor' + "course/" + str(self.course.id) + '?preview=honor' link = get_lms_link_for_certificate_web_view( course_key=self.course.id, mode='honor' @@ -403,11 +399,11 @@ class CertificatesListHandlerTestCase( """ self._add_course_certificates(count=2) json_data = { - u'version': CERTIFICATE_SCHEMA_VERSION, - u'name': u'New test certificate', - u'description': u'New test description', - u'is_active': True, - u'signatories': [] + 'version': CERTIFICATE_SCHEMA_VERSION, + 'name': 'New test certificate', + 'description': 'New test description', + 'is_active': True, + 'signatories': [] } response = self.client.post( @@ -437,7 +433,7 @@ class CertificatesDetailHandlerTestCase( """ Set up CertificatesDetailHandlerTestCase. """ - super(CertificatesDetailHandlerTestCase, self).setUp('cms.djangoapps.contentstore.views.certificates.tracker') # lint-amnesty, pylint: disable=super-with-arguments + super().setUp('cms.djangoapps.contentstore.views.certificates.tracker') self.reset_urls() def _url(self, cid=-1): @@ -456,13 +452,13 @@ class CertificatesDetailHandlerTestCase( PUT/POST new certificate. """ expected = { - u'id': 666, - u'version': CERTIFICATE_SCHEMA_VERSION, - u'name': u'Test certificate', - u'description': u'Test description', - u'is_active': True, - u'course_title': u'Course Title Override', - u'signatories': [] + 'id': 666, + 'version': CERTIFICATE_SCHEMA_VERSION, + 'name': 'Test certificate', + 'description': 'Test description', + 'is_active': True, + 'course_title': 'Course Title Override', + 'signatories': [] } response = self.client.put( @@ -476,7 +472,7 @@ class CertificatesDetailHandlerTestCase( self.assertEqual(content, expected) self.assert_event_emitted( 'edx.certificate.configuration.created', - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), configuration_id=666, ) @@ -487,13 +483,13 @@ class CertificatesDetailHandlerTestCase( self._add_course_certificates(count=2) expected = { - u'id': 1, - u'version': CERTIFICATE_SCHEMA_VERSION, - u'name': u'New test certificate', - u'description': u'New test description', - u'is_active': True, - u'course_title': u'Course Title Override', - u'signatories': [] + 'id': 1, + 'version': CERTIFICATE_SCHEMA_VERSION, + 'name': 'New test certificate', + 'description': 'New test description', + 'is_active': True, + 'course_title': 'Course Title Override', + 'signatories': [] } @@ -508,7 +504,7 @@ class CertificatesDetailHandlerTestCase( self.assertEqual(content, expected) self.assert_event_emitted( 'edx.certificate.configuration.modified', - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), configuration_id=1, ) self.reload_course() @@ -516,7 +512,7 @@ class CertificatesDetailHandlerTestCase( # Verify that certificate is properly updated in the course. course_certificates = self.course.certificates['certificates'] self.assertEqual(len(course_certificates), 2) - self.assertEqual(course_certificates[1].get('name'), u'New test certificate') + self.assertEqual(course_certificates[1].get('name'), 'New test certificate') self.assertEqual(course_certificates[1].get('description'), 'New test description') def test_can_edit_certificate_without_is_active(self): @@ -537,13 +533,13 @@ class CertificatesDetailHandlerTestCase( self.save_course() expected = { - u'id': 1, - u'version': CERTIFICATE_SCHEMA_VERSION, - u'name': u'New test certificate', - u'description': u'New test description', - u'is_active': True, - u'course_title': u'Course Title Override', - u'signatories': [] + 'id': 1, + 'version': CERTIFICATE_SCHEMA_VERSION, + 'name': 'New test certificate', + 'description': 'New test description', + 'is_active': True, + 'course_title': 'Course Title Override', + 'signatories': [] } @@ -573,7 +569,7 @@ class CertificatesDetailHandlerTestCase( self.assertEqual(response.status_code, 204) self.assert_event_emitted( 'edx.certificate.configuration.deleted', - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), configuration_id='1', ) self.reload_course() @@ -597,7 +593,7 @@ class CertificatesDetailHandlerTestCase( self.assertEqual(response.status_code, 204) self.assert_event_emitted( 'edx.certificate.configuration.deleted', - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), configuration_id='1', ) self.reload_course() @@ -622,7 +618,7 @@ class CertificatesDetailHandlerTestCase( self.assertEqual(response.status_code, 204) self.assert_event_emitted( 'edx.certificate.configuration.deleted', - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), configuration_id='1', ) self.reload_course() @@ -673,14 +669,14 @@ class CertificatesDetailHandlerTestCase( """ self._add_course_certificates(count=2, signatory_count=1, is_active=True, asset_path_format=signatory_path) cert_data = { - u'id': 1, - u'version': CERTIFICATE_SCHEMA_VERSION, - u'name': u'New test certificate', - u'description': u'New test description', - u'course_title': u'Course Title Override', - u'org_logo_path': '', - u'is_active': False, - u'signatories': [] + 'id': 1, + 'version': CERTIFICATE_SCHEMA_VERSION, + 'name': 'New test certificate', + 'description': 'New test description', + 'course_title': 'Course Title Override', + 'org_logo_path': '', + 'is_active': False, + 'signatories': [] } user = UserFactory() for role in [CourseInstructorRole, CourseStaffRole]: @@ -790,7 +786,7 @@ class CertificatesDetailHandlerTestCase( cert_event_type = 'activated' if is_active else 'deactivated' self.assert_event_emitted( '.'.join(['edx.certificate.configuration', cert_event_type]), - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), ) @ddt.data(*itertools.product([True, False], [C4X_SIGNATORY_PATH, SIGNATORY_PATH])) diff --git a/cms/djangoapps/contentstore/views/tests/test_container_page.py b/cms/djangoapps/contentstore/views/tests/test_container_page.py index f1c82a60e2..f181b2d095 100644 --- a/cms/djangoapps/contentstore/views/tests/test_container_page.py +++ b/cms/djangoapps/contentstore/views/tests/test_container_page.py @@ -5,12 +5,11 @@ Unit tests for the container page. import datetime import re +from unittest.mock import Mock, patch -import six from django.http import Http404 from django.test.client import RequestFactory from django.utils import http -from mock import Mock, patch from pytz import UTC import cms.djangoapps.contentstore.views.component as views @@ -31,7 +30,7 @@ class ContainerPageTestCase(StudioPageTestCase, LibraryTestCase): reorderable_child_view = 'reorderable_container_child_preview' def setUp(self): - super(ContainerPageTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.vertical = self._create_item(self.sequential.location, 'vertical', 'Unit') self.html = self._create_item(self.vertical.location, "html", "HTML") self.child_container = self._create_item(self.vertical.location, 'split_test', 'Split Test') @@ -60,18 +59,18 @@ class ContainerPageTestCase(StudioPageTestCase, LibraryTestCase): self._test_html_content( self.child_container, expected_section_tag=( - u'