diff --git a/cms/djangoapps/contentstore/management/commands/git_export.py b/cms/djangoapps/contentstore/management/commands/git_export.py index 1fe60068fb..27f646ea3a 100644 --- a/cms/djangoapps/contentstore/management/commands/git_export.py +++ b/cms/djangoapps/contentstore/management/commands/git_export.py @@ -61,4 +61,4 @@ class Command(BaseCommand): options.get('rdir', None) ) except git_export_utils.GitExportError as ex: - raise CommandError(text_type(ex.message)) + raise CommandError(text_type(ex)) diff --git a/cms/djangoapps/contentstore/push_notification.py b/cms/djangoapps/contentstore/push_notification.py index ed038e07dd..e7ee741c44 100644 --- a/cms/djangoapps/contentstore/push_notification.py +++ b/cms/djangoapps/contentstore/push_notification.py @@ -6,6 +6,7 @@ from logging import exception as log_exception from uuid import uuid4 from django.conf import settings +from six import text_type from contentstore.models import PushNotificationConfig from contentstore.tasks import push_course_update_task @@ -80,4 +81,4 @@ def send_push_course_update(course_key_string, course_subscription_id, course_di ) except ParseError as error: - log_exception(error.message) + log_exception(text_type(error)) diff --git a/cms/djangoapps/contentstore/tests/test_transcripts_utils.py b/cms/djangoapps/contentstore/tests/test_transcripts_utils.py index 603cc23246..84e9a497c9 100644 --- a/cms/djangoapps/contentstore/tests/test_transcripts_utils.py +++ b/cms/djangoapps/contentstore/tests/test_transcripts_utils.py @@ -12,6 +12,7 @@ from django.test.utils import override_settings from django.utils import translation from mock import Mock, patch from nose.plugins.skip import SkipTest +from six import text_type from contentstore.tests.utils import mock_requests_get from xmodule.contentstore.content import StaticContent @@ -425,7 +426,7 @@ class TestGenerateSubsFromSource(TestDownloadYoutubeSubs): with self.assertRaises(transcripts_utils.TranscriptsGenerationException) as cm: transcripts_utils.generate_subs_from_source(youtube_subs, 'BAD_FORMAT', srt_filedata, self.course) - exception_message = cm.exception.message + exception_message = text_type(cm.exception) self.assertEqual(exception_message, "We support only SubRip (*.srt) transcripts format.") def test_fail_bad_subs_filedata(self): @@ -439,7 +440,7 @@ class TestGenerateSubsFromSource(TestDownloadYoutubeSubs): with self.assertRaises(transcripts_utils.TranscriptsGenerationException) as cm: transcripts_utils.generate_subs_from_source(youtube_subs, 'srt', srt_filedata, self.course) - exception_message = cm.exception.message + exception_message = text_type(cm.exception) self.assertEqual(exception_message, "Something wrong with SubRip transcripts file during parsing.") diff --git a/cms/djangoapps/contentstore/views/assets.py b/cms/djangoapps/contentstore/views/assets.py index 472d729c9b..b24b74b9a7 100644 --- a/cms/djangoapps/contentstore/views/assets.py +++ b/cms/djangoapps/contentstore/views/assets.py @@ -13,6 +13,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_POST, require_http_methods from opaque_keys.edx.keys import AssetKey, CourseKey from pymongo import ASCENDING, DESCENDING +from six import text_type from xmodule.contentstore.content import StaticContent from xmodule.contentstore.django import contentstore from xmodule.exceptions import NotFoundError @@ -402,7 +403,7 @@ def _upload_asset(request, course_key): try: content = update_course_run_asset(course_key, upload_file) except AssetSizeTooLargeException as exception: - return JsonResponse({'error': exception.message}, status=413) + return JsonResponse({'error': text_type(exception)}, status=413) # readback the saved content - we need the database timestamp readback = contentstore().find(content.location) diff --git a/cms/djangoapps/contentstore/views/certificates.py b/cms/djangoapps/contentstore/views/certificates.py index f3354ac18b..fd2e17d756 100644 --- a/cms/djangoapps/contentstore/views/certificates.py +++ b/cms/djangoapps/contentstore/views/certificates.py @@ -33,6 +33,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import AssetKey, CourseKey +from six import text_type from contentstore.utils import get_lms_link_for_certificate_web_view, reverse_course_url from contentstore.views.assets import delete_asset @@ -423,7 +424,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": err.message}, status=400) + return JsonResponse({"error": text_type(err)}, status=400) if course.certificates.get('certificates') is None: course.certificates['certificates'] = [] course.certificates['certificates'].append(new_certificate.certificate_data) @@ -480,7 +481,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": err.message}, status=400) + return JsonResponse({"error": text_type(err)}, status=400) serialized_certificate = CertificateManager.serialize_certificate(new_certificate) cert_event_type = 'created' diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 16f13b8a41..b747a8bdc9 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -24,6 +24,7 @@ from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import Location from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace +from six import text_type from contentstore.course_group_config import ( COHORT_SCHEME, @@ -812,7 +813,7 @@ def _create_or_rerun_course(request): 'course_key': unicode(new_course.id), }) except ValidationError as ex: - return JsonResponse({'error': ex.message}, status=400) + return JsonResponse({'error': text_type(ex)}, status=400) except DuplicateCourseError: return JsonResponse({ 'ErrMsg': _( @@ -829,7 +830,7 @@ def _create_or_rerun_course(request): }) except InvalidKeyError as error: return JsonResponse({ - "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(name=display_name, err=error.message)} + "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(name=display_name, err=text_type(error))} ) @@ -1297,7 +1298,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(err.message) + log.exception(text_type(err)) response_message = [ { 'message': _('An error occurred while trying to save your tabs'), @@ -1316,7 +1317,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(err.message), + django.utils.html.escape(text_type(err)), content_type="text/plain" ) @@ -1418,7 +1419,7 @@ def textbooks_list_handler(request, course_key_string): try: textbooks = validate_textbooks_json(request.body) except TextbookValidationError as err: - return JsonResponse({"error": err.message}, status=400) + return JsonResponse({"error": text_type(err)}, status=400) tids = set(t["id"] for t in textbooks if "id" in t) for textbook in textbooks: @@ -1437,7 +1438,7 @@ def textbooks_list_handler(request, course_key_string): try: textbook = validate_textbook_json(request.body) except TextbookValidationError as err: - return JsonResponse({"error": err.message}, status=400) + return JsonResponse({"error": text_type(err)}, status=400) if not textbook.get("id"): tids = set(t["id"] for t in course.pdf_textbooks if "id" in t) textbook["id"] = assign_textbook_id(textbook, tids) @@ -1491,7 +1492,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": err.message}, status=400) + return JsonResponse({"error": text_type(err)}, status=400) new_textbook["id"] = textbook_id if textbook: i = course_module.pdf_textbooks.index(textbook) @@ -1621,7 +1622,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": err.message}, status=400) + return JsonResponse({"error": text_type(err)}, status=400) course.user_partitions.append(new_configuration) response = JsonResponse(new_configuration.to_json(), status=201) @@ -1664,7 +1665,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() except GroupConfigurationsValidationError as err: - return JsonResponse({"error": err.message}, status=400) + return JsonResponse({"error": text_type(err)}, status=400) if configuration: index = course.user_partitions.index(configuration) diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index ff972465fc..1f22a5b77b 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -18,6 +18,7 @@ from django.views.decorators.http import require_http_methods from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryUsageLocator from pytz import UTC +from six import text_type from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Scope @@ -574,8 +575,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 verr.message: - reason = _("Invalid data ({details})").format(details=verr.message) + if text_type(verr): + reason = _("Invalid data ({details})").format(details=text_type(verr)) return JsonResponse({"error": reason}, 400) field.write_to(xblock, value) diff --git a/cms/djangoapps/contentstore/views/library.py b/cms/djangoapps/contentstore/views/library.py index 1f0d497fa9..63080edab5 100644 --- a/cms/djangoapps/contentstore/views/library.py +++ b/cms/djangoapps/contentstore/views/library.py @@ -17,6 +17,7 @@ from django.views.decorators.http import require_http_methods from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryLocator, LibraryUsageLocator +from six import text_type from contentstore.utils import add_instructor, reverse_library_url from contentstore.views.item import create_xblock_info @@ -164,12 +165,12 @@ def _create_library(request): except KeyError as error: log.exception("Unable to create library - missing required JSON key.") return JsonResponseBadRequest({ - "ErrMsg": _("Unable to create library - missing required field '{field}'").format(field=error.message) + "ErrMsg": _("Unable to create library - missing required field '{field}'").format(field=text_type(error)) }) except InvalidKeyError as error: log.exception("Unable to create library - invalid key.") return JsonResponseBadRequest({ - "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format(name=display_name, err=error.message) + "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format(name=display_name, err=text_type(error)) }) except DuplicateCourseError: log.exception("Unable to create library - one already exists with the same key.") diff --git a/cms/djangoapps/contentstore/views/transcripts_ajax.py b/cms/djangoapps/contentstore/views/transcripts_ajax.py index ff238aa18e..247f7e798c 100644 --- a/cms/djangoapps/contentstore/views/transcripts_ajax.py +++ b/cms/djangoapps/contentstore/views/transcripts_ajax.py @@ -18,6 +18,7 @@ from django.http import Http404, HttpResponse from django.utils.translation import ugettext as _ from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import UsageKey +from six import text_type from student.auth import has_course_author_access from util.json_request import JsonResponse @@ -133,7 +134,7 @@ def upload_transcripts(request): response['subs'] = item.sub response['status'] = 'Success' except Exception as ex: - return error_response(response, ex.message) + return error_response(response, text_type(ex)) else: return error_response(response, 'Empty video sources.') @@ -242,7 +243,7 @@ def check_transcripts(request): try: __, videos, item = _validate_transcripts_data(request) except TranscriptsRequestValidationException as e: - return error_response(transcripts_presence, e.message) + return error_response(transcripts_presence, text_type(e)) transcripts_presence['status'] = 'Success' @@ -400,7 +401,7 @@ def choose_transcripts(request): try: data, videos, item = _validate_transcripts_data(request) except TranscriptsRequestValidationException as e: - return error_response(response, e.message) + return error_response(response, text_type(e)) html5_id = data.get('html5_id') # html5_id chosen by user @@ -433,7 +434,7 @@ def replace_transcripts(request): try: __, videos, item = _validate_transcripts_data(request) except TranscriptsRequestValidationException as e: - return error_response(response, e.message) + return error_response(response, text_type(e)) youtube_id = videos['youtube'] if not youtube_id: @@ -442,7 +443,7 @@ def replace_transcripts(request): try: download_youtube_subs(youtube_id, item, settings) except GetTranscriptsFromYouTubeException as e: - return error_response(response, e.message) + return error_response(response, text_type(e)) item.sub = youtube_id item.save_with_metadata(request.user) @@ -504,7 +505,7 @@ def rename_transcripts(request): try: __, videos, item = _validate_transcripts_data(request) except TranscriptsRequestValidationException as e: - return error_response(response, e.message) + return error_response(response, text_type(e)) old_name = item.sub diff --git a/cms/djangoapps/maintenance/views.py b/cms/djangoapps/maintenance/views.py index fe6555008e..4e38dec9c1 100644 --- a/cms/djangoapps/maintenance/views.py +++ b/cms/djangoapps/maintenance/views.py @@ -10,6 +10,7 @@ from django.utils.translation import ugettext as _ from django.views.generic import View from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey +from six import text_type from contentstore.management.commands.utils import get_course_versions from edxmako.shortcuts import render_to_response @@ -169,10 +170,10 @@ class ForcePublishCourseView(MaintenanceBaseView): self.context['msg'] = COURSE_KEY_ERROR_MESSAGES['invalid_course_key'] except ItemNotFoundError as exc: self.context['error'] = True - self.context['msg'] = exc.message + self.context['msg'] = text_type(exc) except ValidationError as exc: self.context['error'] = True - self.context['msg'] = exc.message + self.context['msg'] = text_type(exc) if self.context['error']: return self.render_response() diff --git a/cms/djangoapps/models/settings/course_metadata.py b/cms/djangoapps/models/settings/course_metadata.py index a437539e6e..5aaf9c5f67 100644 --- a/cms/djangoapps/models/settings/course_metadata.py +++ b/cms/djangoapps/models/settings/course_metadata.py @@ -3,6 +3,7 @@ Django module for Course Metadata class -- manages advanced settings and related """ from django.conf import settings from django.utils.translation import ugettext as _ +from six import text_type from xblock.fields import Scope from xblock_django.models import XBlockStudioConfigurationFlag @@ -176,7 +177,7 @@ class CourseMetadata(object): key_values[key] = descriptor.fields[key].from_json(val) except (TypeError, ValueError) as err: raise ValueError(_("Incorrect format for field '{name}'. {detailed_message}").format( - name=model['display_name'], detailed_message=err.message)) + name=model['display_name'], detailed_message=text_type(err))) return cls.update_from_dict(key_values, descriptor, user) @@ -211,7 +212,7 @@ class CourseMetadata(object): key_values[key] = descriptor.fields[key].from_json(val) except (TypeError, ValueError) as err: did_validate = False - errors.append({'message': err.message, 'model': model}) + errors.append({'message': text_type(err), 'model': model}) # If did validate, go ahead and update the metadata if did_validate: diff --git a/common/djangoapps/course_action_state/tests/test_rerun_manager.py b/common/djangoapps/course_action_state/tests/test_rerun_manager.py index 3f5ab762f8..d5b4a22c5c 100644 --- a/common/djangoapps/course_action_state/tests/test_rerun_manager.py +++ b/common/djangoapps/course_action_state/tests/test_rerun_manager.py @@ -4,6 +4,7 @@ Tests specific to the CourseRerunState Model and Manager. from django.test import TestCase from opaque_keys.edx.locations import CourseLocator +from six import text_type from course_action_state.managers import CourseRerunUIStateManager from course_action_state.models import CourseRerunState @@ -103,7 +104,7 @@ class TestCourseRerunStateManager(TestCase): ) self.expected_rerun_state.pop('message') rerun = self.verify_rerun_state() - self.assertIn(exception.message, rerun.message) + self.assertIn(text_type(exception), rerun.message) # dismiss ui and verify self.dismiss_ui_and_verify(rerun) diff --git a/common/djangoapps/django_comment_common/tests.py b/common/djangoapps/django_comment_common/tests.py index c543ec6014..db5a9fc656 100644 --- a/common/djangoapps/django_comment_common/tests.py +++ b/common/djangoapps/django_comment_common/tests.py @@ -1,6 +1,7 @@ from django.test import TestCase from nose.plugins.attrib import attr from opaque_keys.edx.locator import CourseLocator +from six import text_type from django_comment_common.models import Role from models import CourseDiscussionSettings @@ -131,6 +132,6 @@ class CourseDiscussionSettingsTest(ModuleStoreTestCase): set_course_discussion_settings(self.course.id, **{field['name']: invalid_value}) self.assertEqual( - value_error.exception.message, + text_type(value_error.exception), exception_msg_template.format(field['name'], field['type'].__name__) ) diff --git a/common/djangoapps/enrollment/data.py b/common/djangoapps/enrollment/data.py index 004f339218..444db564b4 100644 --- a/common/djangoapps/enrollment/data.py +++ b/common/djangoapps/enrollment/data.py @@ -6,6 +6,7 @@ import logging from django.contrib.auth.models import User from opaque_keys.edx.keys import CourseKey +from six import text_type from enrollment.errors import ( CourseEnrollmentClosedError, @@ -125,14 +126,14 @@ def create_course_enrollment(username, course_id, mode, is_active): enrollment = CourseEnrollment.enroll(user, course_key, check_access=True) return _update_enrollment(enrollment, is_active=is_active, mode=mode) except NonExistentCourseError as err: - raise CourseNotFoundError(err.message) + raise CourseNotFoundError(text_type(err)) except EnrollmentClosedError as err: - raise CourseEnrollmentClosedError(err.message) + raise CourseEnrollmentClosedError(text_type(err)) except CourseFullError as err: - raise CourseEnrollmentFullError(err.message) + raise CourseEnrollmentFullError(text_type(err)) except AlreadyEnrolledError as err: enrollment = get_course_enrollment(username, course_id) - raise CourseEnrollmentExistsError(err.message, enrollment) + raise CourseEnrollmentExistsError(text_type(err), enrollment) def update_course_enrollment(username, course_id, mode=None, is_active=None): diff --git a/common/djangoapps/enrollment/views.py b/common/djangoapps/enrollment/views.py index 3dfdbd7cc3..2d3cd93156 100644 --- a/common/djangoapps/enrollment/views.py +++ b/common/djangoapps/enrollment/views.py @@ -14,6 +14,7 @@ from rest_framework import status from rest_framework.response import Response from rest_framework.throttling import UserRateThrottle from rest_framework.views import APIView +from six import text_type from course_modes.models import CourseMode from enrollment import api @@ -604,7 +605,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): except EnterpriseApiException as error: log.exception("An unexpected error occurred while creating the new EnterpriseCourseEnrollment " "for user [%s] in course run [%s]", username, course_id) - raise CourseEnrollmentError(error.message) + raise CourseEnrollmentError(text_type(error)) kwargs = { 'username': username, 'course_id': unicode(course_id), diff --git a/common/djangoapps/student/management/commands/change_enrollment.py b/common/djangoapps/student/management/commands/change_enrollment.py index efd0e51b6c..e646cf1983 100644 --- a/common/djangoapps/student/management/commands/change_enrollment.py +++ b/common/djangoapps/student/management/commands/change_enrollment.py @@ -6,6 +6,7 @@ from django.core.management.base import BaseCommand, CommandError from django.db import transaction from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey +from six import text_type from student.models import CourseEnrollment, User @@ -135,4 +136,4 @@ class Command(BaseCommand): if len(error_users) > 0: logger.info('The following %i user(s) not saved:', len(error_users)) for user, error in error_users: - logger.info('user: [%s] reason: [%s] %s', user, type(error).__name__, error.message) + logger.info('user: [%s] reason: [%s] %s', user, type(error).__name__, text_type(error)) diff --git a/common/djangoapps/student/management/commands/create_user.py b/common/djangoapps/student/management/commands/create_user.py index 51ecb12043..4bcfe7e4b4 100644 --- a/common/djangoapps/student/management/commands/create_user.py +++ b/common/djangoapps/student/management/commands/create_user.py @@ -5,6 +5,8 @@ from django.contrib.auth.models import User from django.utils import translation from opaque_keys.edx.keys import CourseKey +from six import text_type + from student.forms import AccountCreationForm from student.models import CourseEnrollment, create_comments_service_user from student.views import _do_create_account, AccountValidationError @@ -81,7 +83,7 @@ class Command(TrackedCommand): reg.save() create_comments_service_user(user) except AccountValidationError as e: - print(e.message) + print(text_type(e)) user = User.objects.get(email=options['email']) if course: diff --git a/common/djangoapps/student/management/commands/set_staff.py b/common/djangoapps/student/management/commands/set_staff.py index cf8134c36a..011d3b3f25 100644 --- a/common/djangoapps/student/management/commands/set_staff.py +++ b/common/djangoapps/student/management/commands/set_staff.py @@ -3,6 +3,7 @@ import re from django.contrib.auth.models import User from django.core.management.base import BaseCommand +from six import text_type class Command(BaseCommand): @@ -40,6 +41,7 @@ class Command(BaseCommand): print('Modified {} sucessfully.'.format(user)) except Exception as err: # pylint: disable=broad-except - print("Error modifying user with identifier {}: {}: {}".format(user, type(err).__name__, err.message)) + print("Error modifying user with identifier {}: {}: {}".format(user, type(err).__name__, + text_type(err))) print('Complete!') diff --git a/common/djangoapps/student/management/commands/set_superuser.py b/common/djangoapps/student/management/commands/set_superuser.py index ee65cbd09f..1795d773f3 100644 --- a/common/djangoapps/student/management/commands/set_superuser.py +++ b/common/djangoapps/student/management/commands/set_superuser.py @@ -3,6 +3,7 @@ from __future__ import print_function from django.contrib.auth.models import User from django.core.management.base import BaseCommand +from six import text_type class Command(BaseCommand): @@ -41,6 +42,7 @@ class Command(BaseCommand): print('Modified {} sucessfully.'.format(user)) except Exception as err: # pylint: disable=broad-except - print("Error modifying user with identifier {}: {}: {}".format(user, type(err).__name__, err.message)) + print("Error modifying user with identifier {}: {}: {}".format(user, type(err).__name__, + text_type(err))) print('Complete!') diff --git a/common/djangoapps/student/tests/test_email.py b/common/djangoapps/student/tests/test_email.py index 67478c0eea..d70ddfd2b9 100644 --- a/common/djangoapps/student/tests/test_email.py +++ b/common/djangoapps/student/tests/test_email.py @@ -12,6 +12,7 @@ from django.http import HttpResponse from django.test import override_settings, TestCase, TransactionTestCase from django.test.client import RequestFactory from mock import Mock, patch +from six import text_type from edxmako.shortcuts import render_to_string from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -266,7 +267,7 @@ class EmailChangeRequestTests(EventTestMixin, CacheIsolationTestCase): try: validate_new_email(self.request.user, email) except ValueError as err: - return err.message + return text_type(err) def do_email_change(self, user, email, activation_key=None): """ @@ -275,7 +276,7 @@ class EmailChangeRequestTests(EventTestMixin, CacheIsolationTestCase): try: do_email_change_request(user, email, activation_key) except ValueError as err: - return err.message + return text_type(err) def assertFailedRequest(self, response_data, expected_error): """ diff --git a/common/djangoapps/student/views/management.py b/common/djangoapps/student/views/management.py index 28227b8e03..fa82e83d68 100644 --- a/common/djangoapps/student/views/management.py +++ b/common/djangoapps/student/views/management.py @@ -958,7 +958,7 @@ def create_account(request, post_override=None): try: user = create_account_with_params(request, post_override or request.POST) except AccountValidationError as exc: - return JsonResponse({'success': False, 'value': exc.message, 'field': exc.field}, status=400) + return JsonResponse({'success': False, 'value': text_type(exc), 'field': exc.field}, status=400) except ValidationError as exc: field, error_list = next(iteritems(exc.message_dict)) return JsonResponse( diff --git a/common/djangoapps/third_party_auth/lti.py b/common/djangoapps/third_party_auth/lti.py index 523a01e9fb..c383506712 100644 --- a/common/djangoapps/third_party_auth/lti.py +++ b/common/djangoapps/third_party_auth/lti.py @@ -14,6 +14,7 @@ from oauthlib.oauth1.rfc5849.signature import ( normalize_parameters, sign_hmac_sha1 ) +from six import text_type from social_core.backends.base import BaseAuth from social_core.exceptions import AuthFailed from social_core.utils import sanitize_redirect @@ -185,7 +186,7 @@ class LTIAuthBackend(BaseAuth): if valid: return data except AttributeError as error: - log.error("'{}' not found.".format(error.message)) + log.error("'{}' not found.".format(text_type(error))) return None @classmethod diff --git a/common/djangoapps/third_party_auth/models.py b/common/djangoapps/third_party_auth/models.py index e43c5b2e4f..b2947d4a75 100644 --- a/common/djangoapps/third_party_auth/models.py +++ b/common/djangoapps/third_party_auth/models.py @@ -18,6 +18,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from provider.oauth2.models import Client from provider.utils import long_token +from six import text_type from social_core.backends.base import BaseAuth from social_core.backends.oauth import OAuthAuth from social_core.backends.saml import SAMLAuth @@ -60,7 +61,7 @@ def clean_json(value, of_type): try: value_python = json.loads(value) except ValueError as err: - raise ValidationError("Invalid JSON: {}".format(err.message)) + raise ValidationError("Invalid JSON: {}".format(text_type(err))) if not isinstance(value_python, of_type): raise ValidationError("Expected a JSON {}".format(of_type)) return json.dumps(value_python, indent=4) diff --git a/common/djangoapps/third_party_auth/saml.py b/common/djangoapps/third_party_auth/saml.py index 71a4bc7a2b..35a786e6c5 100644 --- a/common/djangoapps/third_party_auth/saml.py +++ b/common/djangoapps/third_party_auth/saml.py @@ -10,6 +10,7 @@ from django.http import Http404 from django.utils.functional import cached_property from django_countries import countries from onelogin.saml2.settings import OneLogin_Saml2_Settings +from six import text_type from social_core.backends.saml import OID_EDU_PERSON_ENTITLEMENT, SAMLAuth, SAMLIdentityProvider from social_core.exceptions import AuthForbidden @@ -337,7 +338,7 @@ class SapSuccessFactorsIdentityProvider(EdXSAMLIdentityProvider): url=transaction_data['endpoint_url'], company_id=transaction_data['company_id'], user_id=transaction_data['user_id'], - err_msg=err.message, + err_msg=text_type(err), sys_msg=sys_msg, headers=headers, token_data=token_data, diff --git a/common/djangoapps/third_party_auth/tasks.py b/common/djangoapps/third_party_auth/tasks.py index c7a1b8acde..be62d13892 100644 --- a/common/djangoapps/third_party_auth/tasks.py +++ b/common/djangoapps/third_party_auth/tasks.py @@ -14,6 +14,7 @@ from django.utils.timezone import now from lxml import etree from onelogin.saml2.utils import OneLogin_Saml2_Utils from requests import exceptions +from six import text_type from third_party_auth.models import SAMLConfiguration, SAMLProviderConfig, SAMLProviderData @@ -105,11 +106,11 @@ def fetch_saml_metadata(): # RequestException is the base exception for any request related error that "requests" lib raises. # MetadataParseError is raised if there is error in the fetched meta data (e.g. missing @entityID etc.) - log.exception(error.message) + log.exception(text_type(error)) failure_messages.append( "{error_type}: {error_message}\nMetadata Source: {url}\nEntity IDs: \n{entity_ids}.".format( error_type=type(error).__name__, - error_message=error.message, + error_message=text_type(error), url=url, entity_ids="\n".join( ["\t{}: {}".format(count, item) for count, item in enumerate(entity_ids, start=1)], @@ -117,7 +118,7 @@ def fetch_saml_metadata(): ) ) except etree.XMLSyntaxError as error: - log.exception(error.message) + log.exception(text_type(error)) failure_messages.append( "XMLSyntaxError: {error_message}\nMetadata Source: {url}\nEntity IDs: \n{entity_ids}.".format( error_message=str(error.error_log), diff --git a/common/djangoapps/util/tests/test_file.py b/common/djangoapps/util/tests/test_file.py index 1ae7cabc29..44044d819e 100644 --- a/common/djangoapps/util/tests/test_file.py +++ b/common/djangoapps/util/tests/test_file.py @@ -15,6 +15,7 @@ from pytz import UTC from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import CourseLocator +from six import text_type import util.file from util.file import ( @@ -95,7 +96,7 @@ class StoreUploadedFileTestCase(TestCase): """ Helper method to verify exception text. """ - self.assertEqual(expected_message, error.exception.message) + self.assertEqual(expected_message, text_type(error.exception)) def test_error_conditions(self): """ diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index 29cc634b13..2b9cf89747 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -50,6 +50,7 @@ import bleach import html5lib import pyparsing from lxml import etree +from six import text_type import xqueue_interface from calc.preview import latex_preview @@ -251,7 +252,7 @@ class InputTypeBase(object): except Exception as err: # Something went wrong: add xml to message, but keep the traceback msg = u"Error in xml '{x}': {err} ".format( - x=etree.tostring(xml), err=err.message) + x=etree.tostring(xml), err=text_type(err)) raise Exception, msg, sys.exc_info()[2] @classmethod diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 1873b32345..993b8dc0f2 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1601,14 +1601,14 @@ class NumericalResponse(LoncapaResponse): except UndefinedVariable as undef_var: raise StudentInputError( _(u"You may not use variables ({bad_variables}) in numerical problems.").format( - bad_variables=undef_var.message, + bad_variables=text_type(undef_var), ) ) except ValueError as val_err: - if 'factorial' in val_err.message: + if 'factorial' in text_type(val_err): # This is thrown when fact() or factorial() is used in an answer # that evaluates on negative and/or non-integer inputs - # ve.message will be: `factorial() only accepts integral values` or + # text_type(ve) will be: `factorial() only accepts integral values` or # `factorial() not defined for negative values` raise StudentInputError( _("Factorial function evaluated outside its domain:" @@ -2038,7 +2038,7 @@ class StringResponse(LoncapaResponse): except Exception as err: msg = u'[courseware.capa.responsetypes.stringresponse] {error}: {message}'.format( error=_('error'), - message=err.message + message=text_type(err) ) log.error(msg, exc_info=True) raise ResponseError(msg) @@ -2511,7 +2511,7 @@ class CustomResponse(LoncapaResponse): # Notify student with a student input error _, _, traceback_obj = sys.exc_info() - raise ResponseError(err.message, traceback_obj) + raise ResponseError(text_type(err), traceback_obj) #----------------------------------------------------------------------------- @@ -3106,13 +3106,13 @@ class FormulaResponse(LoncapaResponse): cgi.escape(answer) ) raise StudentInputError( - _("Invalid input: {bad_input} not permitted in answer.").format(bad_input=err.message) + _("Invalid input: {bad_input} not permitted in answer.").format(bad_input=text_type(err)) ) except ValueError as err: - if 'factorial' in err.message: + if 'factorial' in text_type(err): # This is thrown when fact() or factorial() is used in a formularesponse answer # that tests on negative and/or non-integer inputs - # err.message will be: `factorial() only accepts integral values` or + # text_type(err) will be: `factorial() only accepts integral values` or # `factorial() not defined for negative values` log.debug( ('formularesponse: factorial function used in response ' diff --git a/common/lib/capa/capa/safe_exec/safe_exec.py b/common/lib/capa/capa/safe_exec/safe_exec.py index cf7863b058..25cd603e35 100644 --- a/common/lib/capa/capa/safe_exec/safe_exec.py +++ b/common/lib/capa/capa/safe_exec/safe_exec.py @@ -5,6 +5,7 @@ from codejail.safe_exec import not_safe_exec as codejail_not_safe_exec from codejail.safe_exec import json_safe, SafeExecException from . import lazymod from dogapi import dog_stats_api +from six import text_type import hashlib @@ -143,7 +144,7 @@ def safe_exec( python_path=python_path, extra_files=extra_files, slug=slug, ) except SafeExecException as e: - emsg = e.message + emsg = text_type(e) else: emsg = None diff --git a/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py b/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py index 068fcea908..4011fee6bf 100644 --- a/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py +++ b/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py @@ -8,6 +8,7 @@ import textwrap import unittest from nose.plugins.skip import SkipTest +from six import text_type from capa.safe_exec import safe_exec, update_hash from codejail.safe_exec import SafeExecException @@ -69,7 +70,7 @@ class TestSafeExec(unittest.TestCase): g = {} with self.assertRaises(SafeExecException) as cm: safe_exec("1/0", g) - self.assertIn("ZeroDivisionError", cm.exception.message) + self.assertIn("ZeroDivisionError", text_type(cm.exception)) class TestSafeOrNot(unittest.TestCase): @@ -81,8 +82,8 @@ class TestSafeOrNot(unittest.TestCase): g = {} with self.assertRaises(SafeExecException) as cm: safe_exec("import os; files = os.listdir('/')", g) - self.assertIn("OSError", cm.exception.message) - self.assertIn("Permission denied", cm.exception.message) + assert "OSError" in text_type(cm.exception) + assert "Permission denied" in text_type(cm.exception) def test_can_do_something_forbidden_if_run_unsafely(self): g = {} diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index 02f87c7d9c..676746a56f 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -15,6 +15,7 @@ import zipfile import mock from pytz import UTC +from six import text_type import requests from capa.tests.helpers import new_loncapa_problem, test_capa_system, load_fixture @@ -798,7 +799,7 @@ class StringResponseTest(ResponseTest): # pylint: disable=missing-docstring problem = self.build_problem(answer="a2", case_sensitive=False, regexp=True, additional_answers=['?\\d?']) with self.assertRaises(Exception) as cm: self.assert_grade(problem, "a3", "correct") - exception_message = cm.exception.message + exception_message = text_type(cm.exception) self.assertIn("nothing to repeat", exception_message) def test_hints(self): diff --git a/common/lib/xmodule/xmodule/capa_base.py b/common/lib/xmodule/xmodule/capa_base.py index 82b2858335..8729ac038a 100644 --- a/common/lib/xmodule/xmodule/capa_base.py +++ b/common/lib/xmodule/xmodule/capa_base.py @@ -544,7 +544,7 @@ class CapaMixin(ScorableXBlockMixin, CapaFields): `err` is the Exception encountered while rendering the problem HTML. """ - log.exception(err.message) + log.exception(text_type(err)) # TODO (vshnayder): another switch on DEBUG. if self.runtime.DEBUG: @@ -553,7 +553,7 @@ class CapaMixin(ScorableXBlockMixin, CapaFields): u'Failed to generate HTML for problem {url}'.format( url=cgi.escape(text_type(self.location))) ) - msg += u'

Error:

{msg}

'.format(msg=cgi.escape(err.message)) + msg += u'

Error:

{msg}

'.format(msg=cgi.escape(text_type(err))) msg += u'

{tb}

'.format(tb=cgi.escape(traceback.format_exc())) html = msg @@ -1258,7 +1258,7 @@ class CapaMixin(ScorableXBlockMixin, CapaFields): self.set_score(self.score_from_lcp()) if self.runtime.DEBUG: - msg = u"Error checking problem: {}".format(err.message) + msg = u"Error checking problem: {}".format(text_type(err)) msg += u'\nTraceback:\n{}'.format(traceback.format_exc()) return {'success': msg} raise diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 673d7c1ac1..e5b0e05c10 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -16,6 +16,7 @@ from openedx.core.djangoapps.video_pipeline.models import VideoUploadsEnabledByD from openedx.core.lib.license import LicenseMixin from path import Path as path from pytz import utc +from six import text_type from xblock.fields import Scope, List, String, Dict, Boolean, Integer, Float from xmodule import course_metadata_utils @@ -943,7 +944,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor, LicenseMixin): if not getattr(self, "tabs", []): CourseTabList.initialize_default(self) except InvalidTabsException as err: - raise type(err)('{msg} For course: {course_id}'.format(msg=err.message, course_id=unicode(self.id))) + raise type(err)('{msg} For course: {course_id}'.format(msg=text_type(err), course_id=unicode(self.id))) self.set_default_certificate_available_date() diff --git a/common/lib/xmodule/xmodule/exceptions.py b/common/lib/xmodule/xmodule/exceptions.py index d1f05171da..f9a0ad597c 100644 --- a/common/lib/xmodule/xmodule/exceptions.py +++ b/common/lib/xmodule/xmodule/exceptions.py @@ -45,9 +45,6 @@ class HeartbeatFailure(Exception): Raised when heartbeat fails. """ - def __unicode__(self, *args, **kwargs): - return self.message - def __init__(self, msg, service): """ In addition to a msg, provide the name of the service. diff --git a/common/lib/xmodule/xmodule/fields.py b/common/lib/xmodule/xmodule/fields.py index d022340107..ffe707833d 100644 --- a/common/lib/xmodule/xmodule/fields.py +++ b/common/lib/xmodule/xmodule/fields.py @@ -5,6 +5,7 @@ import time import dateutil.parser from pytz import UTC +from six import text_type from xblock.fields import JSONField from xblock.scorable import Score @@ -175,7 +176,7 @@ class RelativeTime(JSONField): except ValueError as e: raise ValueError( "Incorrect RelativeTime value {!r} was set in XML or serialized. " - "Original parse message is {}".format(value, e.message) + "Original parse message is {}".format(value, text_type(e)) ) return datetime.timedelta( hours=obj_time.tm_hour, diff --git a/common/lib/xmodule/xmodule/lti_2_util.py b/common/lib/xmodule/xmodule/lti_2_util.py index 27c6a22952..e57a6bdbfb 100644 --- a/common/lib/xmodule/xmodule/lti_2_util.py +++ b/common/lib/xmodule/xmodule/lti_2_util.py @@ -12,6 +12,7 @@ import urllib import mock from oauthlib.oauth1 import Client +from six import text_type from webob import Response from xblock.core import XBlock @@ -290,8 +291,8 @@ class LTI20ModuleMixin(object): try: self.verify_oauth_body_sign(request, content_type=LTI_2_0_JSON_CONTENT_TYPE) except (ValueError, LTIError) as err: - log.info("[LTI]: v2.0 result service -- OAuth body verification failed: {}".format(err.message)) - raise LTIError(err.message) + log.info("[LTI]: v2.0 result service -- OAuth body verification failed: {}".format(text_type(err))) + raise LTIError(text_type(err)) def parse_lti_2_0_result_json(self, json_str): """ @@ -360,7 +361,7 @@ class LTI20ModuleMixin(object): log.info("[LTI] {}".format(msg)) raise LTIError(msg) except (TypeError, ValueError) as err: - msg = "Could not convert resultScore to float: {}".format(err.message) + msg = "Could not convert resultScore to float: {}".format(text_type(err)) log.info("[LTI] {}".format(msg)) raise LTIError(msg) diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py index fdf6f1b98a..15aae2db56 100644 --- a/common/lib/xmodule/xmodule/lti_module.py +++ b/common/lib/xmodule/xmodule/lti_module.py @@ -734,7 +734,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} try: imsx_messageIdentifier, sourcedId, score, action = self.parse_grade_xml_body(request.body) except Exception as e: - error_message = "Request body XML parsing error: " + escape(e.message) + error_message = "Request body XML parsing error: " + escape(text_type(e)) log.debug("[LTI]: " + error_message) failure_values['imsx_description'] = error_message return Response(response_xml_template.format(**failure_values), content_type="application/xml") @@ -744,7 +744,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} self.verify_oauth_body_sign(request) except (ValueError, LTIError) as e: failure_values['imsx_messageIdentifier'] = escape(imsx_messageIdentifier) - error_message = "OAuth verification error: " + escape(e.message) + error_message = "OAuth verification error: " + escape(text_type(e)) failure_values['imsx_description'] = error_message log.debug("[LTI]: " + error_message) return Response(response_xml_template.format(**failure_values), content_type="application/xml") diff --git a/common/lib/xmodule/xmodule/modulestore/draft_and_published.py b/common/lib/xmodule/xmodule/modulestore/draft_and_published.py index 82701418e7..409ec9c721 100644 --- a/common/lib/xmodule/xmodule/modulestore/draft_and_published.py +++ b/common/lib/xmodule/xmodule/modulestore/draft_and_published.py @@ -6,6 +6,7 @@ import threading import logging from abc import ABCMeta, abstractmethod from contextlib import contextmanager +from six import text_type from . import ModuleStoreEnum, BulkOperationsMixin from .exceptions import ItemNotFoundError @@ -157,7 +158,7 @@ class ModuleStoreDraftAndPublished(BranchSettingMixin, BulkOperationsMixin): old_parent_item = self.get_item(old_parent_location) # pylint: disable=no-member new_parent_item = self.get_item(new_parent_location) # pylint: disable=no-member except ItemNotFoundError as exception: - log.error('Unable to find the item : %s', exception.message) + log.error('Unable to find the item : %s', text_type(exception)) return # Remove item from the list of children of old parent. diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index 4d8ba9b00f..81c29787aa 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -880,7 +880,7 @@ class CapaModuleTest(unittest.TestCase): ' File "", line 65, in check_func\\n' 'Exception: test error\\n\' with status code: 1',) except ResponseError as err: - mock_grade.side_effect = exception_class(err.message) + mock_grade.side_effect = exception_class(six.text_type(err)) get_request_dict = {CapaFactory.input_key(): '3.14'} result = module.submit_problem(get_request_dict) diff --git a/common/lib/xmodule/xmodule/tests/test_graders.py b/common/lib/xmodule/xmodule/tests/test_graders.py index aab9e65ab1..e7d1475850 100644 --- a/common/lib/xmodule/xmodule/tests/test_graders.py +++ b/common/lib/xmodule/xmodule/tests/test_graders.py @@ -8,6 +8,7 @@ from datetime import datetime, timedelta import ddt from pytz import UTC from lms.djangoapps.grades.scores import compute_percent +from six import text_type from xmodule import graders from xmodule.graders import ( AggregatedScore, ProblemScore, ShowCorrectness, aggregate_scores @@ -321,7 +322,7 @@ class GraderTest(unittest.TestCase): def test_grader_with_invalid_conf(self, invalid_conf, expected_error_message): with self.assertRaises(ValueError) as error: graders.grader_from_conf([invalid_conf]) - self.assertIn(expected_error_message, error.exception.message) + self.assertIn(expected_error_message, text_type(error.exception)) @ddt.ddt diff --git a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py index 3318f5670d..e49ae981c9 100644 --- a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py +++ b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py @@ -12,6 +12,7 @@ from pysrt import SubRipTime, SubRipItem, SubRipFile from pysrt.srtexc import Error from lxml import etree from HTMLParser import HTMLParser +from six import text_type from xmodule.exceptions import NotFoundError from xmodule.contentstore.content import StaticContent @@ -226,7 +227,7 @@ def generate_subs_from_source(speed_subs, subs_type, subs_filedata, item, langua srt_subs_obj = SubRipFile.from_string(subs_filedata) except Exception as ex: msg = _("Something wrong with SubRip transcripts file during parsing. Inner message is {error_message}").format( - error_message=ex.message + error_message=text_type(ex) ) raise TranscriptsGenerationException(msg) if not srt_subs_obj: @@ -459,7 +460,7 @@ def generate_sjson_for_all_speeds(item, user_filename, result_subs_dict, lang): srt_transcripts = contentstore().find(Transcript.asset_location(item.location, user_filename)) except NotFoundError as ex: raise TranscriptException(_("{exception_message}: Can't find uploaded transcripts: {user_filename}").format( - exception_message=ex.message, + exception_message=text_type(ex), user_filename=user_filename )) @@ -612,7 +613,7 @@ class Transcript(object): error_handling=SubRipFile.ERROR_RAISE ) except Error as ex: # Base exception from pysrt - raise TranscriptsGenerationException(ex.message) + raise TranscriptsGenerationException(text_type(ex)) return generate_sjson_from_srt(srt_subs) diff --git a/common/lib/xmodule/xmodule/video_module/video_handlers.py b/common/lib/xmodule/xmodule/video_module/video_handlers.py index 224da13f48..2212ed6e9d 100644 --- a/common/lib/xmodule/xmodule/video_module/video_handlers.py +++ b/common/lib/xmodule/xmodule/video_module/video_handlers.py @@ -291,7 +291,7 @@ class VideoStudentViewHandlers(object): except (TypeError, TranscriptException, NotFoundError) as ex: # Catching `TranscriptException` because its also getting raised at places # when transcript is not found in contentstore. - log.debug(ex.message) + log.debug(six.text_type(ex)) # Try to return static URL redirection as last resort # if no translation is required response = self.get_static_transcript(request, transcripts) @@ -313,7 +313,7 @@ class VideoStudentViewHandlers(object): return response except (UnicodeDecodeError, TranscriptsGenerationException) as ex: - log.info(ex.message) + log.info(six.text_type(ex)) response = Response(status=404) else: response = Response(transcript, headerlist=[('Content-Language', language)]) diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 6a554b14a5..84ae3349ce 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -14,6 +14,7 @@ from pkg_resources import ( resource_string, resource_isdir, ) +from six import text_type from web_fragments.fragment import Fragment from webob import Response from webob.multidict import MultiDict @@ -420,8 +421,8 @@ class XModuleMixin(XModuleFields, XBlock): result[field.name] = field.read_json(self) except TypeError as exception: exception_message = "{message}, Block-location:{location}, Field-name:{field_name}".format( - message=exception.message, - location=unicode(self.location), + message=text_type(exception), + location=text_type(self.location), field_name=field.name ) raise TypeError(exception_message) diff --git a/lms/djangoapps/commerce/api/v0/views.py b/lms/djangoapps/commerce/api/v0/views.py index 1d2db22b2f..99acb87226 100644 --- a/lms/djangoapps/commerce/api/v0/views.py +++ b/lms/djangoapps/commerce/api/v0/views.py @@ -8,6 +8,7 @@ from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.status import HTTP_406_NOT_ACCEPTABLE, HTTP_409_CONFLICT from rest_framework.views import APIView +from six import text_type from course_modes.models import CourseMode from courseware import courses @@ -54,7 +55,7 @@ class BasketsView(APIView): courses.get_course(course_key) except (InvalidKeyError, ValueError)as ex: log.exception(u'Unable to locate course matching %s.', course_id) - return False, None, ex.message + return False, None, text_type(ex) return True, course_key, None diff --git a/lms/djangoapps/completion/api/v1/views.py b/lms/djangoapps/completion/api/v1/views.py index 48096b3109..5c0cd03e5a 100644 --- a/lms/djangoapps/completion/api/v1/views.py +++ b/lms/djangoapps/completion/api/v1/views.py @@ -11,6 +11,7 @@ from rest_framework import status from opaque_keys.edx.keys import CourseKey, UsageKey from opaque_keys import InvalidKeyError +from six import text_type from lms.djangoapps.completion.models import BlockCompletion from openedx.core.djangoapps.content.course_structures.models import CourseStructure @@ -126,11 +127,11 @@ class CompletionBatchView(APIView): }, status=status.HTTP_400_BAD_REQUEST) except ObjectDoesNotExist as exc: return Response({ - "detail": exc.message, + "detail": text_type(exc), }, status=status.HTTP_404_NOT_FOUND) except DatabaseError as exc: return Response({ - "detail": exc.message, + "detail": text_type(exc), }, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return Response({"detail": _("ok")}, status=status.HTTP_200_OK) diff --git a/lms/djangoapps/course_api/blocks/views.py b/lms/djangoapps/course_api/blocks/views.py index 05e80f7ceb..8684e03d08 100644 --- a/lms/djangoapps/course_api/blocks/views.py +++ b/lms/djangoapps/course_api/blocks/views.py @@ -7,6 +7,7 @@ from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from rest_framework.generics import ListAPIView from rest_framework.response import Response +from six import text_type from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes from xmodule.modulestore.django import modulestore @@ -215,7 +216,7 @@ class BlocksView(DeveloperErrorViewMixin, ListAPIView): ) ) except ItemNotFoundError as exception: - raise Http404("Block not found: {}".format(exception.message)) + raise Http404("Block not found: {}".format(text_type(exception))) @view_auth_classes() diff --git a/lms/djangoapps/courseware/courseware_access_exception.py b/lms/djangoapps/courseware/courseware_access_exception.py index d3a47d0c12..931782f98c 100644 --- a/lms/djangoapps/courseware/courseware_access_exception.py +++ b/lms/djangoapps/courseware/courseware_access_exception.py @@ -10,9 +10,8 @@ class CoursewareAccessException(Http404): """ def __init__(self, access_response): - super(CoursewareAccessException, self).__init__() + super(CoursewareAccessException, self).__init__("Course not found.") self.access_response = access_response - self.message = "Course not found." def to_json(self): """ diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py index ef277557b8..de5b7c5d66 100644 --- a/lms/djangoapps/courseware/tests/test_courses.py +++ b/lms/djangoapps/courseware/tests/test_courses.py @@ -13,6 +13,7 @@ from django.core.urlresolvers import reverse from django.test.client import RequestFactory from django.test.utils import override_settings from nose.plugins.attrib import attr +from six import text_type from courseware.courses import ( course_open_for_self_enrollment, @@ -78,7 +79,7 @@ class CoursesTest(ModuleStoreTestCase): with self.assertRaises(CoursewareAccessException) as error: course_access_func(user, 'load', course.id) - self.assertEqual(error.exception.message, "Course not found.") + self.assertEqual(text_type(error.exception), "Course not found.") self.assertEqual(error.exception.access_response.error_code, "not_visible_to_user") self.assertFalse(error.exception.access_response.has_access) diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 348e65fb06..675e6f95e4 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -1518,7 +1518,7 @@ def financial_assistance_request(request): return HttpResponseBadRequest(u'Could not parse request course key.') except KeyError as err: # Thrown if fields are missing - return HttpResponseBadRequest(u'The field {} is required.'.format(err.message)) + return HttpResponseBadRequest(u'The field {} is required.'.format(text_type(err))) zendesk_submitted = _record_feedback_in_zendesk( legal_name, diff --git a/lms/djangoapps/dashboard/git_import.py b/lms/djangoapps/dashboard/git_import.py index 2472b37430..347cfdec54 100644 --- a/lms/djangoapps/dashboard/git_import.py +++ b/lms/djangoapps/dashboard/git_import.py @@ -33,7 +33,7 @@ class GitImportError(Exception): def __init__(self, message=None): if message is None: - message = self.message + message = self.MESSAGE super(GitImportError, self).__init__(message) diff --git a/lms/djangoapps/dashboard/tests/test_sysadmin.py b/lms/djangoapps/dashboard/tests/test_sysadmin.py index 2b03fb289e..10a65e27c7 100644 --- a/lms/djangoapps/dashboard/tests/test_sysadmin.py +++ b/lms/djangoapps/dashboard/tests/test_sysadmin.py @@ -153,7 +153,7 @@ class TestSysAdminMongoCourseImport(SysadminBaseTestCase): # Create git loaded course response = self._add_edx4edx() - self.assertIn(GitImportErrorNoDir(settings.GIT_REPO_DIR).message, + self.assertIn(text_type(GitImportErrorNoDir(settings.GIT_REPO_DIR)), response.content.decode('UTF-8')) def test_mongo_course_add_delete(self): diff --git a/lms/djangoapps/django_comment_client/middleware.py b/lms/djangoapps/django_comment_client/middleware.py index 9dce7bc012..84d033566e 100644 --- a/lms/djangoapps/django_comment_client/middleware.py +++ b/lms/djangoapps/django_comment_client/middleware.py @@ -1,6 +1,8 @@ import json import logging +from six import text_type + from django_comment_client.utils import JsonError from lms.lib.comment_client import CommentClientRequestError @@ -19,7 +21,7 @@ class AjaxExceptionMiddleware(object): """ if isinstance(exception, CommentClientRequestError) and request.is_ajax(): try: - return JsonError(json.loads(exception.message), exception.status_code) + return JsonError(json.loads(text_type(exception)), exception.status_code) except ValueError: - return JsonError(exception.message, exception.status_code) + return JsonError(text_type(exception), exception.status_code) return None diff --git a/lms/djangoapps/django_comment_client/tests/test_middleware.py b/lms/djangoapps/django_comment_client/tests/test_middleware.py index 4849cfa3d0..80803bea7e 100644 --- a/lms/djangoapps/django_comment_client/tests/test_middleware.py +++ b/lms/djangoapps/django_comment_client/tests/test_middleware.py @@ -3,6 +3,7 @@ import json import django.http from django.test import TestCase from nose.plugins.attrib import attr +from six import text_type import django_comment_client.middleware as middleware import lms.lib.comment_client @@ -26,7 +27,7 @@ class AjaxExceptionTestCase(TestCase): self.assertIsInstance(response1, middleware.JsonError) self.assertEqual(self.exception1.status_code, response1.status_code) self.assertEqual( - {"errors": json.loads(self.exception1.message)}, + {"errors": json.loads(text_type(self.exception1))}, json.loads(response1.content) ) @@ -34,7 +35,7 @@ class AjaxExceptionTestCase(TestCase): self.assertIsInstance(response2, middleware.JsonError) self.assertEqual(self.exception2.status_code, response2.status_code) self.assertEqual( - {"errors": [self.exception2.message]}, + {"errors": [text_type(self.exception2)]}, json.loads(response2.content) ) diff --git a/lms/djangoapps/edxnotes/views.py b/lms/djangoapps/edxnotes/views.py index 1c0a889ae2..5d90040276 100644 --- a/lms/djangoapps/edxnotes/views.py +++ b/lms/djangoapps/edxnotes/views.py @@ -10,6 +10,7 @@ from django.core.urlresolvers import reverse from django.http import Http404, HttpResponse from django.views.decorators.http import require_GET from opaque_keys.edx.keys import CourseKey +from six import text_type from courseware.courses import get_course_with_access from courseware.model_data import FieldDataCache @@ -165,7 +166,7 @@ def notes(request, course_id): text=text ) except (EdxNotesParseError, EdxNotesServiceUnavailable) as err: - return JsonResponseBadRequest({"error": err.message}, status=500) + return JsonResponseBadRequest({"error": text_type(err)}, status=500) return HttpResponse(json.dumps(notes_info, cls=NoteJSONEncoder), content_type="application/json") diff --git a/lms/djangoapps/grades/course_grade_factory.py b/lms/djangoapps/grades/course_grade_factory.py index 275b450d38..455417bc6b 100644 --- a/lms/djangoapps/grades/course_grade_factory.py +++ b/lms/djangoapps/grades/course_grade_factory.py @@ -5,6 +5,7 @@ from collections import namedtuple from logging import getLogger import dogstats_wrapper as dog_stats_api +from six import text_type from openedx.core.djangoapps.signals.signals import COURSE_GRADE_CHANGED, COURSE_GRADE_NOW_PASSED @@ -126,7 +127,7 @@ class CourseGradeFactory(object): 'Cannot grade student %s in course %s because of exception: %s', user.id, course_data.course_key, - exc.message + text_type(exc) ) return self.GradeResult(user, None, exc) diff --git a/lms/djangoapps/grades/tests/test_course_grade_factory.py b/lms/djangoapps/grades/tests/test_course_grade_factory.py index c762899bb1..ecde6b7521 100644 --- a/lms/djangoapps/grades/tests/test_course_grade_factory.py +++ b/lms/djangoapps/grades/tests/test_course_grade_factory.py @@ -8,6 +8,8 @@ from django.conf import settings from lms.djangoapps.grades.config.tests.utils import persistent_grades_feature_flags from mock import patch from openedx.core.djangoapps.content.block_structure.factory import BlockStructureFactory +from six import text_type + from student.tests.factories import UserFactory from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -342,7 +344,7 @@ class TestGradeIteration(SharedModuleStoreTestCase): with self.assertNumQueries(4): all_course_grades, all_errors = self._course_grades_and_errors_for(self.course, self.students) self.assertEqual( - {student: all_errors[student].message for student in all_errors}, + {student: text_type(all_errors[student]) for student in all_errors}, { student3: "Error for student3.", student4: "Error for student4.", diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index c431e17607..0fb7cd0461 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -2091,7 +2091,7 @@ def rescore_problem(request, course_id): only_if_higher, ) except NotImplementedError as exc: - return HttpResponseBadRequest(exc.message) + return HttpResponseBadRequest(text_type(exc)) elif all_students: try: @@ -2101,7 +2101,7 @@ def rescore_problem(request, course_id): only_if_higher, ) except NotImplementedError as exc: - return HttpResponseBadRequest(exc.message) + return HttpResponseBadRequest(text_type(exc)) else: return HttpResponseBadRequest() @@ -2157,10 +2157,10 @@ def override_problem_score(request, course_id): score, ) except NotImplementedError as exc: # if we try to override the score of a non-scorable block, catch it here - return _create_error_response(request, exc.message) + return _create_error_response(request, text_type(exc)) except ValueError as exc: - return _create_error_response(request, exc.message) + return _create_error_response(request, text_type(exc)) response_payload['task'] = TASK_SUBMISSION_OK return JsonResponse(response_payload) @@ -2951,14 +2951,14 @@ def certificate_exception_view(request, course_id): try: certificate_exception, student = parse_request_data_and_get_user(request, course_key) except ValueError as error: - return JsonResponse({'success': False, 'message': error.message}, status=400) + return JsonResponse({'success': False, 'message': text_type(error)}, status=400) # Add new Certificate Exception for the student passed in request data if request.method == 'POST': try: exception = add_certificate_exception(course_key, student, certificate_exception) except ValueError as error: - return JsonResponse({'success': False, 'message': error.message}, status=400) + return JsonResponse({'success': False, 'message': text_type(error)}, status=400) return JsonResponse(exception) # Remove Certificate Exception for the student passed in request data @@ -2966,7 +2966,7 @@ def certificate_exception_view(request, course_id): try: remove_certificate_exception(course_key, student) except ValueError as error: - return JsonResponse({'success': False, 'message': error.message}, status=400) + return JsonResponse({'success': False, 'message': text_type(error)}, status=400) return JsonResponse({}, status=204) @@ -3264,14 +3264,14 @@ def certificate_invalidation_view(request, course_id): certificate_invalidation_data = parse_request_data(request) certificate = validate_request_data_and_get_certificate(certificate_invalidation_data, course_key) except ValueError as error: - return JsonResponse({'message': error.message}, status=400) + return JsonResponse({'message': text_type(error)}, status=400) # Invalidate certificate of the given student for the course course if request.method == 'POST': try: certificate_invalidation = invalidate_certificate(request, certificate, certificate_invalidation_data) except ValueError as error: - return JsonResponse({'message': error.message}, status=400) + return JsonResponse({'message': text_type(error)}, status=400) return JsonResponse(certificate_invalidation) # Re-Validate student certificate for the course course @@ -3279,7 +3279,7 @@ def certificate_invalidation_view(request, course_id): try: re_validate_certificate(request, course_key, certificate) except ValueError as error: - return JsonResponse({'message': error.message}, status=400) + return JsonResponse({'message': text_type(error)}, status=400) return JsonResponse({}, status=204) diff --git a/lms/djangoapps/instructor_task/api_helper.py b/lms/djangoapps/instructor_task/api_helper.py index abdadcb5b9..eb61b67f87 100644 --- a/lms/djangoapps/instructor_task/api_helper.py +++ b/lms/djangoapps/instructor_task/api_helper.py @@ -256,8 +256,8 @@ def _handle_instructor_task_failure(instructor_task, error): """ Do required operations if task creation was not complete. """ - log.info("instructor task (%s) failed, result: %s", instructor_task.task_id, error.message) - _update_instructor_task_state(instructor_task, FAILURE, error.message) + log.info("instructor task (%s) failed, result: %s", instructor_task.task_id, text_type(error)) + _update_instructor_task_state(instructor_task, FAILURE, text_type(error)) raise QueueConnectionError() diff --git a/lms/djangoapps/instructor_task/models.py b/lms/djangoapps/instructor_task/models.py index 23920fe94a..5e69eede10 100644 --- a/lms/djangoapps/instructor_task/models.py +++ b/lms/djangoapps/instructor_task/models.py @@ -149,7 +149,7 @@ class InstructorTask(models.Model): Truncation is indicated by adding "..." to the end of the value. """ tag = '...' - task_progress = {'exception': type(exception).__name__, 'message': unicode(exception.message)} + task_progress = {'exception': type(exception).__name__, 'message': text_type(exception)} if traceback_string is not None: # truncate any traceback that goes into the InstructorTask model: task_progress['traceback'] = traceback_string diff --git a/lms/djangoapps/instructor_task/tasks_helper/grades.py b/lms/djangoapps/instructor_task/tasks_helper/grades.py index a82d2e5bef..cea887f75b 100644 --- a/lms/djangoapps/instructor_task/tasks_helper/grades.py +++ b/lms/djangoapps/instructor_task/tasks_helper/grades.py @@ -10,6 +10,7 @@ from time import time from lazy import lazy from pytz import UTC +from six import text_type from courseware.courses import get_course_by_id from instructor_analytics.basic import list_problem_responses @@ -435,7 +436,7 @@ class CourseGradeReport(object): ): if not course_grade: # An empty gradeset means we failed to grade a student. - error_rows.append([user.id, user.username, error.message]) + error_rows.append([user.id, user.username, text_type(error)]) else: success_rows.append( [user.id, user.email, user.username] + @@ -485,7 +486,7 @@ class ProblemGradeReport(object): task_progress.attempted += 1 if not course_grade: - err_msg = error.message + err_msg = text_type(error) # There was an error grading this student. if not err_msg: err_msg = u'Unknown error' diff --git a/lms/djangoapps/notification_prefs/views.py b/lms/djangoapps/notification_prefs/views.py index 7f6416d302..181947f835 100644 --- a/lms/djangoapps/notification_prefs/views.py +++ b/lms/djangoapps/notification_prefs/views.py @@ -19,6 +19,7 @@ from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponse from django.views.decorators.http import require_GET, require_POST +from six import text_type from edxmako.shortcuts import render_to_response from notification_prefs import NOTIFICATION_PREF_KEY @@ -185,7 +186,7 @@ def set_subscription(request, token, subscribe): # pylint: disable=unused-argum except UnicodeDecodeError: raise Http404("base64url") except UsernameDecryptionException as exn: - raise Http404(exn.message) + raise Http404(text_type(exn)) except User.DoesNotExist: raise Http404("username") diff --git a/lms/djangoapps/shoppingcart/management/commands/retire_order.py b/lms/djangoapps/shoppingcart/management/commands/retire_order.py index a48925b28d..495809bd5f 100644 --- a/lms/djangoapps/shoppingcart/management/commands/retire_order.py +++ b/lms/djangoapps/shoppingcart/management/commands/retire_order.py @@ -4,6 +4,7 @@ marked as "purchased" in the db """ from django.core.management.base import BaseCommand +from six import text_type from shoppingcart.exceptions import InvalidStatusToRetire, UnexpectedOrderItemStatus from shoppingcart.models import Order @@ -36,7 +37,7 @@ class Command(BaseCommand): order.retire() except (UnexpectedOrderItemStatus, InvalidStatusToRetire) as err: print "Did not retire order {order}: {message}".format( - order=order.id, message=err.message + order=order.id, message=text_type(err) ) else: print "retired order {order_id} from status {old_status} to status {new_status}".format( diff --git a/lms/djangoapps/shoppingcart/processors/CyberSource.py b/lms/djangoapps/shoppingcart/processors/CyberSource.py index 305d3ffd7c..1133b6311b 100644 --- a/lms/djangoapps/shoppingcart/processors/CyberSource.py +++ b/lms/djangoapps/shoppingcart/processors/CyberSource.py @@ -30,6 +30,7 @@ from textwrap import dedent from django.conf import settings from django.utils.translation import ugettext as _ +from six import text_type from edxmako.shortcuts import render_to_string from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -283,7 +284,7 @@ def get_processor_exception_html(exception): ) formatted = msg.format( error_message='{msg}'.format( - msg=exception.message, + msg=text_type(exception), ), email=payment_support_email, ) @@ -298,7 +299,7 @@ def get_processor_exception_html(exception): ) formatted = msg.format( error_message='{msg}'.format( - msg=exception.message, + msg=text_type(exception), ), email=payment_support_email, ) @@ -316,7 +317,7 @@ def get_processor_exception_html(exception): ) formatted = msg.format( error_message='{msg}'.format( - msg=exception.message, + msg=text_type(exception), ), email=payment_support_email, ) diff --git a/lms/djangoapps/shoppingcart/processors/CyberSource2.py b/lms/djangoapps/shoppingcart/processors/CyberSource2.py index 5a3aadd736..e12d7aa123 100644 --- a/lms/djangoapps/shoppingcart/processors/CyberSource2.py +++ b/lms/djangoapps/shoppingcart/processors/CyberSource2.py @@ -35,6 +35,7 @@ from textwrap import dedent from django.conf import settings from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_noop +from six import text_type from edxmako.shortcuts import render_to_string from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -503,7 +504,7 @@ def _get_processor_exception_html(exception): u"The specific error message is: {msg} " u"Your credit card may possibly have been charged. Contact us with payment-specific questions at {email}." ).format( - msg=u'{msg}'.format(msg=exception.message), + msg=u'{msg}'.format(msg=text_type(exception)), email=payment_support_email ) ) @@ -514,7 +515,7 @@ def _get_processor_exception_html(exception): u"The specific error message is: {msg}. " u"Your credit card has probably been charged. Contact us with payment-specific questions at {email}." ).format( - msg=u'{msg}'.format(msg=exception.message), + msg=u'{msg}'.format(msg=text_type(exception)), email=payment_support_email ) ) @@ -527,7 +528,7 @@ def _get_processor_exception_html(exception): u"We apologize that we cannot verify whether the charge went through and take further action on your order. " u"Your credit card may possibly have been charged. Contact us with payment-specific questions at {email}." ).format( - msg=u'{msg}'.format(msg=exception.message), + msg=u'{msg}'.format(msg=text_type(exception)), email=payment_support_email ) ) diff --git a/lms/djangoapps/support/tests/test_views.py b/lms/djangoapps/support/tests/test_views.py index 05cf547969..a67886668c 100644 --- a/lms/djangoapps/support/tests/test_views.py +++ b/lms/djangoapps/support/tests/test_views.py @@ -296,7 +296,7 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase self.assert_enrollment(CourseMode.VERIFIED) @ddt.data( - ({}, r"The field '\w+' is required."), + ({}, r"The field \"'\w+'\" is required."), # The double quoting goes away in Django 2.0.1 ({'course_id': 'bad course key'}, 'Could not parse course key.'), ({ 'course_id': 'course-v1:TestX+T101+2015', diff --git a/lms/djangoapps/support/views/enrollments.py b/lms/djangoapps/support/views/enrollments.py index 5bed96e696..c5b716e79a 100644 --- a/lms/djangoapps/support/views/enrollments.py +++ b/lms/djangoapps/support/views/enrollments.py @@ -11,6 +11,7 @@ from django.views.generic import View from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from rest_framework.generics import GenericAPIView +from six import text_type from course_modes.models import CourseMode from edxmako.shortcuts import render_to_response @@ -89,7 +90,7 @@ class EnrollmentSupportListView(GenericAPIView): if new_mode == CourseMode.CREDIT_MODE: return HttpResponseBadRequest(u'Enrollment cannot be changed to credit mode.') except KeyError as err: - return HttpResponseBadRequest(u'The field {} is required.'.format(err.message)) + return HttpResponseBadRequest(u'The field {} is required.'.format(text_type(err))) except InvalidKeyError: return HttpResponseBadRequest(u'Could not parse course key.') except (CourseEnrollment.DoesNotExist, User.DoesNotExist): @@ -113,7 +114,7 @@ class EnrollmentSupportListView(GenericAPIView): ) return JsonResponse(ManualEnrollmentSerializer(instance=manual_enrollment).data) except CourseModeNotFoundError as err: - return HttpResponseBadRequest(err.message) + return HttpResponseBadRequest(text_type(err)) @staticmethod def include_verified_mode_info(enrollment_data, course_key): diff --git a/lms/lib/comment_client/utils.py b/lms/lib/comment_client/utils.py index 36fd1cf98f..062989c7d2 100644 --- a/lms/lib/comment_client/utils.py +++ b/lms/lib/comment_client/utils.py @@ -142,11 +142,7 @@ def perform_request(method, url, data_or_params=None, raw=False, class CommentClientError(Exception): - def __init__(self, msg): - self.message = msg - - def __str__(self): - return repr(self.message) + pass class CommentClientRequestError(CommentClientError): diff --git a/openedx/core/djangoapps/content/block_structure/management/commands/generate_course_blocks.py b/openedx/core/djangoapps/content/block_structure/management/commands/generate_course_blocks.py index 147025c793..4d7bef61ef 100644 --- a/openedx/core/djangoapps/content/block_structure/management/commands/generate_course_blocks.py +++ b/openedx/core/djangoapps/content/block_structure/management/commands/generate_course_blocks.py @@ -4,6 +4,7 @@ Command to load course blocks. import logging from django.core.management.base import BaseCommand +from six import text_type from xmodule.modulestore.django import modulestore import openedx.core.djangoapps.content.block_structure.api as api @@ -136,7 +137,7 @@ class Command(BaseCommand): log.exception( u'BlockStructure: An error occurred while generating course blocks for %s: %s', unicode(course_key), - ex.message, + text_type(ex), ) def _generate_for_course(self, options, course_key): diff --git a/openedx/core/djangoapps/content/course_overviews/models.py b/openedx/core/djangoapps/content/course_overviews/models.py index 53520611aa..824c6c7f83 100644 --- a/openedx/core/djangoapps/content/course_overviews/models.py +++ b/openedx/core/djangoapps/content/course_overviews/models.py @@ -13,6 +13,7 @@ from django.template import defaultfilters from ccx_keys.locator import CCXLocator from model_utils.models import TimeStampedModel +from six import text_type from config_models.models import ConfigurationModel from lms.djangoapps import django_comment_client @@ -528,7 +529,7 @@ class CourseOverview(TimeStampedModel): log.exception( 'An error occurred while generating course overview for %s: %s', unicode(course_key), - ex.message, + text_type(ex), ) log.info('Finished generating course overviews.') diff --git a/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py b/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py index 5d2e164a28..2e09ecf154 100644 --- a/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py +++ b/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py @@ -51,6 +51,6 @@ class Command(BaseCommand): update_course_structure.apply(args=[text_type(course_key)]) except Exception as ex: log.exception('An error occurred while generating course structure for %s: %s', - text_type(course_key), ex.message) + text_type(course_key), text_type(ex)) log.info('Finished generating course structures.') diff --git a/openedx/core/djangoapps/content/course_structures/tasks.py b/openedx/core/djangoapps/content/course_structures/tasks.py index aa56ff01cf..bccf529c55 100644 --- a/openedx/core/djangoapps/content/course_structures/tasks.py +++ b/openedx/core/djangoapps/content/course_structures/tasks.py @@ -6,6 +6,8 @@ import logging from celery.task import task from opaque_keys.edx.keys import CourseKey +from six import text_type + from xmodule.modulestore.django import modulestore @@ -78,7 +80,7 @@ def update_course_structure(course_key): try: structure = _generate_course_structure(course_key) except Exception as ex: - log.exception('An error occurred while generating course structure: %s', ex.message) + log.exception('An error occurred while generating course structure: %s', text_type(ex)) raise structure_json = json.dumps(structure['structure']) diff --git a/openedx/core/djangoapps/contentserver/middleware.py b/openedx/core/djangoapps/contentserver/middleware.py index 8f6fe3eea8..5eda4a9091 100644 --- a/openedx/core/djangoapps/contentserver/middleware.py +++ b/openedx/core/djangoapps/contentserver/middleware.py @@ -12,6 +12,7 @@ except ImportError: from django.http import ( HttpResponse, HttpResponseNotModified, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotFound, HttpResponsePermanentRedirect) +from six import text_type from student.models import CourseEnrollment from xmodule.assetstore.assetmgr import AssetManager @@ -132,18 +133,18 @@ class StaticContentServer(object): except ValueError as exception: # If the header field is syntactically invalid it should be ignored. log.exception( - u"%s in Range header: %s for content: %s", exception.message, header_value, unicode(loc) + u"%s in Range header: %s for content: %s", text_type(exception), header_value, unicode(loc) ) else: if unit != 'bytes': # Only accept ranges in bytes - log.warning(u"Unknown unit in Range header: %s for content: %s", header_value, unicode(loc)) + log.warning(u"Unknown unit in Range header: %s for content: %s", header_value, text_type(loc)) elif len(ranges) > 1: # According to Http/1.1 spec content for multiple ranges should be sent as a multipart message. # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16 # But we send back the full content. log.warning( - u"More than 1 ranges in Range header: %s for content: %s", header_value, unicode(loc) + u"More than 1 ranges in Range header: %s for content: %s", header_value, text_type(loc) ) else: first, last = ranges[0] @@ -161,7 +162,8 @@ class StaticContentServer(object): newrelic.agent.add_custom_parameter('contentserver.ranged', True) else: log.warning( - u"Cannot satisfy ranges in Range header: %s for content: %s", header_value, unicode(loc) + u"Cannot satisfy ranges in Range header: %s for content: %s", + header_value, text_type(loc) ) return HttpResponse(status=416) # Requested Range Not Satisfiable diff --git a/openedx/core/djangoapps/course_groups/tests/test_cohorts.py b/openedx/core/djangoapps/course_groups/tests/test_cohorts.py index cee543f396..5eb8084ad3 100644 --- a/openedx/core/djangoapps/course_groups/tests/test_cohorts.py +++ b/openedx/core/djangoapps/course_groups/tests/test_cohorts.py @@ -12,6 +12,8 @@ from django.db import IntegrityError from django.http import Http404 from django.test import TestCase from opaque_keys.edx.locator import CourseLocator +from six import text_type + from student.models import CourseEnrollment from student.tests.factories import UserFactory from xmodule.modulestore.django import modulestore @@ -720,7 +722,7 @@ class TestCohorts(ModuleStoreTestCase): with self.assertRaises(ValueError) as value_error: cohorts.set_course_cohorted(course.id, 'not a boolean') - self.assertEqual("Cohorted must be a boolean", value_error.exception.message) + self.assertEqual("Cohorted must be a boolean", text_type(value_error.exception)) @attr(shard=2) diff --git a/openedx/core/djangoapps/credit/views.py b/openedx/core/djangoapps/credit/views.py index 0dce4a102e..06ab088fba 100644 --- a/openedx/core/djangoapps/credit/views.py +++ b/openedx/core/djangoapps/credit/views.py @@ -18,6 +18,7 @@ from rest_framework.authentication import SessionAuthentication from rest_framework.exceptions import ValidationError from rest_framework.response import Response from rest_framework_oauth.authentication import OAuth2Authentication +from six import text_type from openedx.core.djangoapps.credit.api import create_credit_request from openedx.core.djangoapps.credit.exceptions import ( @@ -101,7 +102,7 @@ class CreditProviderRequestCreateView(views.APIView): credit_request = create_credit_request(course_key, provider.provider_id, username) return Response(credit_request) except CreditApiBadRequest as ex: - raise InvalidCreditRequest(ex.message) + raise InvalidCreditRequest(text_type(ex)) class CreditProviderCallbackView(views.APIView): diff --git a/openedx/core/djangoapps/profile_images/exceptions.py b/openedx/core/djangoapps/profile_images/exceptions.py index ca63fced8b..2977a75900 100644 --- a/openedx/core/djangoapps/profile_images/exceptions.py +++ b/openedx/core/djangoapps/profile_images/exceptions.py @@ -1,6 +1,7 @@ """ Exceptions related to the handling of profile images. """ +from six import text_type class ImageValidationError(Exception): @@ -12,4 +13,4 @@ class ImageValidationError(Exception): """ Translate the developer-facing exception message for API clients. """ - return self.message + return text_type(self) diff --git a/openedx/core/djangoapps/profile_images/tests/test_images.py b/openedx/core/djangoapps/profile_images/tests/test_images.py index 40e3474092..17c3e40db5 100644 --- a/openedx/core/djangoapps/profile_images/tests/test_images.py +++ b/openedx/core/djangoapps/profile_images/tests/test_images.py @@ -14,6 +14,7 @@ import mock from nose.plugins.attrib import attr import piexif from PIL import Image +from six import text_type from openedx.core.djangolib.testing.utils import skip_unless_lms from ..exceptions import ImageValidationError @@ -48,7 +49,7 @@ class TestValidateUploadedImage(TestCase): if expected_failure_message is not None: with self.assertRaises(ImageValidationError) as ctx: validate_uploaded_image(uploaded_file) - self.assertEqual(ctx.exception.message, expected_failure_message) + self.assertEqual(text_type(ctx.exception), expected_failure_message) else: validate_uploaded_image(uploaded_file) self.assertEqual(uploaded_file.tell(), 0) @@ -107,7 +108,7 @@ class TestValidateUploadedImage(TestCase): ) with self.assertRaises(ImageValidationError) as ctx: validate_uploaded_image(uploaded_file) - self.assertEqual(ctx.exception.message, file_upload_bad_ext) + self.assertEqual(text_type(ctx.exception), file_upload_bad_ext) def test_content_type(self): """ @@ -121,7 +122,7 @@ class TestValidateUploadedImage(TestCase): with make_uploaded_file(extension=".jpeg", content_type="image/gif") as uploaded_file: with self.assertRaises(ImageValidationError) as ctx: validate_uploaded_image(uploaded_file) - self.assertEqual(ctx.exception.message, file_upload_bad_mimetype) + self.assertEqual(text_type(ctx.exception), file_upload_bad_mimetype) @attr(shard=2) diff --git a/openedx/core/djangoapps/profile_images/views.py b/openedx/core/djangoapps/profile_images/views.py index 43bb324022..a907f34f7a 100644 --- a/openedx/core/djangoapps/profile_images/views.py +++ b/openedx/core/djangoapps/profile_images/views.py @@ -12,6 +12,7 @@ from rest_framework import permissions, status from rest_framework.parsers import FormParser, MultiPartParser from rest_framework.response import Response from rest_framework.views import APIView +from six import text_type from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_image_names, set_has_profile_image from openedx.core.djangoapps.user_api.errors import UserNotFound @@ -145,7 +146,7 @@ class ProfileImageView(DeveloperErrorViewMixin, APIView): validate_uploaded_image(uploaded_file) except ImageValidationError as error: return Response( - {"developer_message": error.message, "user_message": error.user_message}, + {"developer_message": text_type(error), "user_message": error.user_message}, status=status.HTTP_400_BAD_REQUEST, ) diff --git a/openedx/core/djangoapps/safe_sessions/middleware.py b/openedx/core/djangoapps/safe_sessions/middleware.py index 2b8869e405..7ba898af03 100644 --- a/openedx/core/djangoapps/safe_sessions/middleware.py +++ b/openedx/core/djangoapps/safe_sessions/middleware.py @@ -67,6 +67,7 @@ from django.contrib.sessions.middleware import SessionMiddleware from django.core import signing from django.http import HttpResponse from django.utils.crypto import get_random_string +from six import text_type from openedx.core.lib.mobile_utils import is_request_from_mobile_app @@ -186,7 +187,7 @@ class SafeCookieData(object): log.error( "SafeCookieData signature error for cookie data {0!r}: {1}".format( # pylint: disable=logging-format-interpolation unicode(self), - sig_error.message, + text_type(sig_error), ) ) return False diff --git a/openedx/core/djangoapps/user_api/accounts/api.py b/openedx/core/djangoapps/user_api/accounts/api.py index 35c54a2185..8d491589d4 100644 --- a/openedx/core/djangoapps/user_api/accounts/api.py +++ b/openedx/core/djangoapps/user_api/accounts/api.py @@ -13,6 +13,7 @@ from django.core.validators import validate_email, ValidationError from django.http import HttpResponseForbidden from openedx.core.djangoapps.user_api.preferences.api import update_user_preferences from openedx.core.djangoapps.user_api.errors import PreferenceValidationError, AccountValidationError +from six import text_type from student.models import User, UserProfile, Registration from student import forms as student_forms @@ -168,8 +169,8 @@ def update_account_settings(requesting_user, update, username=None): student_views.validate_new_email(existing_user, new_email) except ValueError as err: field_errors["email"] = { - "developer_message": u"Error thrown from validate_new_email: '{}'".format(err.message), - "user_message": err.message + "developer_message": u"Error thrown from validate_new_email: '{}'".format(text_type(err)), + "user_message": text_type(err) } # If the user asked to change full name, validate it @@ -245,7 +246,7 @@ def update_account_settings(requesting_user, update, username=None): raise err except Exception as err: raise errors.AccountUpdateError( - u"Error thrown when saving account updates: '{}'".format(err.message) + u"Error thrown when saving account updates: '{}'".format(text_type(err)) ) # And try to send the email change request if necessary. @@ -256,8 +257,8 @@ def update_account_settings(requesting_user, update, username=None): student_views.do_email_change_request(existing_user, new_email) except ValueError as err: raise errors.AccountUpdateError( - u"Error thrown from do_email_change_request: '{}'".format(err.message), - user_message=err.message + u"Error thrown from do_email_change_request: '{}'".format(text_type(err)), + user_message=text_type(err) ) @@ -552,7 +553,7 @@ def _validate(validation_func, err, *args): try: validation_func(*args) except err as validation_err: - return validation_err.message + return text_type(validation_err) return '' @@ -582,8 +583,10 @@ def _validate_username(username): # `validate_username` provides a proper localized message, however the API needs only the English # message by convention. student_forms.validate_username(username) - except (UnicodeError, errors.AccountDataBadType, errors.AccountDataBadLength, ValidationError) as username_err: - raise errors.AccountUsernameInvalid(username_err.message) + except (UnicodeError, errors.AccountDataBadType, errors.AccountDataBadLength) as username_err: + raise errors.AccountUsernameInvalid(text_type(username_err)) + except ValidationError as validation_err: + raise errors.AccountUsernameInvalid(validation_err.message) def _validate_email(email): @@ -605,8 +608,10 @@ def _validate_email(email): _validate_length(email, accounts.EMAIL_MIN_LENGTH, accounts.EMAIL_MAX_LENGTH, accounts.EMAIL_BAD_LENGTH_MSG) validate_email.message = accounts.EMAIL_INVALID_MSG.format(email=email) validate_email(email) - except (UnicodeError, errors.AccountDataBadType, errors.AccountDataBadLength, ValidationError) as invalid_email_err: - raise errors.AccountEmailInvalid(invalid_email_err.message) + except (UnicodeError, errors.AccountDataBadType, errors.AccountDataBadLength) as invalid_email_err: + raise errors.AccountEmailInvalid(text_type(invalid_email_err)) + except ValidationError as validation_err: + raise errors.AccountEmailInvalid(validation_err.message) def _validate_confirm_email(confirm_email, email): @@ -650,7 +655,7 @@ def _validate_password(password, username=None): _validate_password_works_with_username(password, username) except (errors.AccountDataBadType, errors.AccountDataBadLength) as invalid_password_err: - raise errors.AccountPasswordInvalid(invalid_password_err.message) + raise errors.AccountPasswordInvalid(text_type(invalid_password_err)) def _validate_country(country): diff --git a/openedx/core/djangoapps/user_api/accounts/serializers.py b/openedx/core/djangoapps/user_api/accounts/serializers.py index 5516a1e363..ceb69d0257 100644 --- a/openedx/core/djangoapps/user_api/accounts/serializers.py +++ b/openedx/core/djangoapps/user_api/accounts/serializers.py @@ -9,6 +9,7 @@ from django.contrib.auth.models import User from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse +from six import text_type from lms.djangoapps.badges.utils import badges_enabled from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -313,8 +314,8 @@ class AccountLegacyProfileSerializer(serializers.HyperlinkedModelSerializer, Rea # If we have encountered any validation errors, return them to the user. raise errors.AccountValidationError({ 'social_links': { - "developer_message": u"Error thrown from adding new social link: '{}'".format(err.message), - "user_message": err.message + "developer_message": u"Error thrown from adding new social link: '{}'".format(text_type(err)), + "user_message": text_type(err) } }) diff --git a/openedx/core/djangoapps/user_api/preferences/api.py b/openedx/core/djangoapps/user_api/preferences/api.py index ec96abcb74..5408018349 100644 --- a/openedx/core/djangoapps/user_api/preferences/api.py +++ b/openedx/core/djangoapps/user_api/preferences/api.py @@ -14,6 +14,8 @@ from django.utils.translation import ugettext_noop from openedx.core.lib.time_zone_utils import get_display_time_zone from pytz import common_timezones, common_timezones_set, country_timezones +from six import text_type + from student.models import User, UserProfile from ..errors import ( UserAPIInternalError, UserAPIRequestError, UserNotFound, UserNotAuthorized, @@ -266,7 +268,7 @@ def update_email_opt_in(user, org, opt_in): if hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY: _track_update_email_opt_in(user.id, org, opt_in) except IntegrityError as err: - log.warn(u"Could not update organization wide preference due to IntegrityError: {}".format(err.message)) + log.warning(u"Could not update organization wide preference due to IntegrityError: {}".format(text_type(err))) def _track_update_email_opt_in(user_id, organization, opt_in): diff --git a/openedx/core/djangoapps/user_api/tests/test_helpers.py b/openedx/core/djangoapps/user_api/tests/test_helpers.py index d5babff60c..f55459a864 100644 --- a/openedx/core/djangoapps/user_api/tests/test_helpers.py +++ b/openedx/core/djangoapps/user_api/tests/test_helpers.py @@ -9,6 +9,8 @@ from django import forms from django.http import HttpRequest, HttpResponse from django.test import TestCase from nose.tools import raises +from six import text_type + from ..helpers import ( intercept_errors, shim_student_view, FormDescription, InvalidFieldError @@ -66,7 +68,7 @@ class InterceptErrorsTest(TestCase): try: intercepted_function(raise_error=FakeInputException) except FakeOutputException as ex: - actual_message = re.sub(r'line \d+', 'line XXX', ex.message, flags=re.MULTILINE) + actual_message = re.sub(r'line \d+', 'line XXX', text_type(ex), flags=re.MULTILINE) self.assertEqual(actual_message, expected_log_msg) # Verify that the error logger is called diff --git a/openedx/core/djangoapps/user_api/validation/tests/test_views.py b/openedx/core/djangoapps/user_api/validation/tests/test_views.py index 4796cc8f60..0e77e49004 100644 --- a/openedx/core/djangoapps/user_api/validation/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/validation/tests/test_views.py @@ -9,6 +9,7 @@ import ddt from django.conf import settings from django.contrib.auth.models import User from django.core.urlresolvers import reverse +from six import text_type from openedx.core.djangoapps.user_api import accounts from openedx.core.djangoapps.user_api.accounts.tests import testutils @@ -140,7 +141,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_confirm_email_doesnt_equal_email(self, confirm_email): self.assertValidationDecision( {'email': 'user@email.com', 'confirm_email': confirm_email}, - {'email': '', 'confirm_email': accounts.REQUIRED_FIELD_CONFIRM_EMAIL_MSG} + {'email': '', 'confirm_email': text_type(accounts.REQUIRED_FIELD_CONFIRM_EMAIL_MSG)} ) @ddt.data( @@ -150,7 +151,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_username_bad_length_validation_decision(self, username): self.assertValidationDecision( {'username': username}, - {'username': accounts.USERNAME_BAD_LENGTH_MSG} + {'username': text_type(accounts.USERNAME_BAD_LENGTH_MSG)} ) @unittest.skipUnless(settings.FEATURES.get("ENABLE_UNICODE_USERNAME"), "Unicode usernames disabled.") @@ -158,7 +159,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_username_invalid_unicode_validation_decision(self, username): self.assertValidationDecision( {'username': username}, - {'username': accounts.USERNAME_INVALID_CHARS_UNICODE} + {'username': text_type(accounts.USERNAME_INVALID_CHARS_UNICODE)} ) @unittest.skipIf(settings.FEATURES.get("ENABLE_UNICODE_USERNAME"), "Unicode usernames enabled.") @@ -166,31 +167,31 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_username_invalid_ascii_validation_decision(self, username): self.assertValidationDecision( {'username': username}, - {"username": accounts.USERNAME_INVALID_CHARS_ASCII} + {"username": text_type(accounts.USERNAME_INVALID_CHARS_ASCII)} ) def test_password_empty_validation_decision(self): self.assertValidationDecision( {'password': ''}, - {"password": accounts.PASSWORD_EMPTY_MSG} + {"password": text_type(accounts.PASSWORD_EMPTY_MSG)} ) def test_password_bad_min_length_validation_decision(self): password = 'p' * (accounts.PASSWORD_MIN_LENGTH - 1) self.assertValidationDecision( {'password': password}, - {"password": accounts.PASSWORD_BAD_MIN_LENGTH_MSG} + {"password": text_type(accounts.PASSWORD_BAD_MIN_LENGTH_MSG)} ) def test_password_bad_max_length_validation_decision(self): password = 'p' * (accounts.PASSWORD_MAX_LENGTH + 1) self.assertValidationDecision( {'password': password}, - {"password": accounts.PASSWORD_BAD_MAX_LENGTH_MSG} + {"password": text_type(accounts.PASSWORD_BAD_MAX_LENGTH_MSG)} ) def test_password_equals_username_validation_decision(self): self.assertValidationDecision( {"username": "somephrase", "password": "somephrase"}, - {"username": "", "password": accounts.PASSWORD_CANT_EQUAL_USERNAME_MSG} + {"username": "", "password": text_type(accounts.PASSWORD_CANT_EQUAL_USERNAME_MSG)} ) diff --git a/openedx/core/djangoapps/user_api/views.py b/openedx/core/djangoapps/user_api/views.py index e7341eb69a..de05b435a0 100644 --- a/openedx/core/djangoapps/user_api/views.py +++ b/openedx/core/djangoapps/user_api/views.py @@ -14,6 +14,7 @@ from opaque_keys.edx.keys import CourseKey from rest_framework import authentication, generics, status, viewsets from rest_framework.exceptions import ParseError from rest_framework.views import APIView +from six import text_type import accounts from django_comment_common.models import Role @@ -150,7 +151,7 @@ class RegistrationView(APIView): user = create_account_with_params(request, data) except AccountValidationError as err: errors = { - err.field: [{"user_message": err.message}] + err.field: [{"user_message": text_type(err)}] } return JsonResponse(errors, status=409) except ValidationError as err: diff --git a/openedx/core/lib/api/view_utils.py b/openedx/core/lib/api/view_utils.py index 0ee5c63a42..ed552ae11c 100644 --- a/openedx/core/lib/api/view_utils.py +++ b/openedx/core/lib/api/view_utils.py @@ -12,6 +12,7 @@ from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.request import clone_request from rest_framework.response import Response +from six import text_type from openedx.core.lib.api.authentication import ( OAuth2AuthenticationAllowInactiveUser, @@ -66,7 +67,7 @@ class DeveloperErrorViewMixin(object): if isinstance(exc, APIException): return self.make_error_response(exc.status_code, exc.detail) elif isinstance(exc, Http404) or isinstance(exc, ObjectDoesNotExist): - return self.make_error_response(404, exc.message or "Not found.") + return self.make_error_response(404, text_type(exc) or "Not found.") elif isinstance(exc, ValidationError): return self.make_validation_error_response(exc) else: diff --git a/openedx/core/lib/command_utils.py b/openedx/core/lib/command_utils.py index e68a3e6ba1..85e8f433c0 100644 --- a/openedx/core/lib/command_utils.py +++ b/openedx/core/lib/command_utils.py @@ -5,6 +5,7 @@ Useful utilities for management commands. from django.core.management.base import CommandError from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey +from six import text_type def get_mutually_exclusive_required_option(options, *selections): @@ -45,4 +46,4 @@ def parse_course_keys(course_key_strings): try: return [CourseKey.from_string(course_key_string) for course_key_string in course_key_strings] except InvalidKeyError as error: - raise CommandError('Invalid key specified: {}'.format(error.message)) + raise CommandError('Invalid key specified: {}'.format(text_type(error))) diff --git a/scripts/xblock/xblock_counts.py b/scripts/xblock/xblock_counts.py index c58036c861..41eb39a46c 100644 --- a/scripts/xblock/xblock_counts.py +++ b/scripts/xblock/xblock_counts.py @@ -6,6 +6,7 @@ import sys from datetime import datetime import requests +from six import text_type # Keys for the CSV and JSON interpretation PAGINATION_KEY = 'pagination' @@ -164,10 +165,10 @@ def _get_block_types_from_json_file(xblock_json_file): type_set = set() try: json_data = json.loads(json_file.read()) - except ValueError, e: + except ValueError as e: print 'xBlock configuration file does not match the expected layout and is ' \ 'missing "data" list: %s' % xblock_json_file - sys.exit(e.message) + sys.exit(text_type(e)) if 'data' in json_data: xblock_type_list = json_data['data'] for xblock in xblock_type_list: