From fb92051dee8549fd4f4c681ac38661ff6792269a Mon Sep 17 00:00:00 2001 From: usamasadiq Date: Thu, 25 Feb 2021 18:15:27 +0500 Subject: [PATCH] refac: ran pyupgrade on lms/djangoapps/badges --- lms/djangoapps/badges/admin.py | 2 +- lms/djangoapps/badges/api/serializers.py | 6 +- lms/djangoapps/badges/api/tests.py | 20 ++-- lms/djangoapps/badges/api/views.py | 13 +-- lms/djangoapps/badges/apps.py | 2 +- lms/djangoapps/badges/backends/badgr.py | 29 +++--- lms/djangoapps/badges/backends/base.py | 4 +- .../backends/tests/test_badgr_backend.py | 19 ++-- .../badges/events/course_complete.py | 19 ++-- .../events/tests/test_course_complete.py | 8 +- .../badges/events/tests/test_course_meta.py | 25 +++-- lms/djangoapps/badges/handlers.py | 4 +- .../badges/migrations/0001_initial.py | 13 +-- .../0002_data__migrate_assertions.py | 7 +- .../0003_schema__add_event_configuration.py | 9 +- lms/djangoapps/badges/models.py | 97 +++++++++---------- lms/djangoapps/badges/service.py | 2 +- lms/djangoapps/badges/tests/factories.py | 21 ++-- lms/djangoapps/badges/tests/test_models.py | 17 ++-- lms/djangoapps/badges/utils.py | 4 +- 20 files changed, 154 insertions(+), 167 deletions(-) diff --git a/lms/djangoapps/badges/admin.py b/lms/djangoapps/badges/admin.py index 0d87f3bb7f..fc8e40d263 100644 --- a/lms/djangoapps/badges/admin.py +++ b/lms/djangoapps/badges/admin.py @@ -3,7 +3,7 @@ Admin registration for Badge Models """ -from config_models.admin import ConfigurationModelAdmin # lint-amnesty, pylint: disable=import-error +from config_models.admin import ConfigurationModelAdmin from django.contrib import admin from lms.djangoapps.badges.models import BadgeClass, CourseCompleteImageConfiguration, CourseEventBadgesConfiguration diff --git a/lms/djangoapps/badges/api/serializers.py b/lms/djangoapps/badges/api/serializers.py index 5639954285..2bcdd740eb 100644 --- a/lms/djangoapps/badges/api/serializers.py +++ b/lms/djangoapps/badges/api/serializers.py @@ -3,7 +3,7 @@ Serializers for Badges """ -from rest_framework import serializers # lint-amnesty, pylint: disable=import-error +from rest_framework import serializers from lms.djangoapps.badges.models import BadgeAssertion, BadgeClass @@ -14,7 +14,7 @@ class BadgeClassSerializer(serializers.ModelSerializer): """ image_url = serializers.ImageField(source='image') - class Meta(object): + class Meta: model = BadgeClass fields = ('slug', 'issuing_component', 'display_name', 'course_id', 'description', 'criteria', 'image_url') @@ -25,6 +25,6 @@ class BadgeAssertionSerializer(serializers.ModelSerializer): """ badge_class = BadgeClassSerializer(read_only=True) - class Meta(object): + class Meta: model = BadgeAssertion fields = ('badge_class', 'image_url', 'assertion_url', 'created') diff --git a/lms/djangoapps/badges/api/tests.py b/lms/djangoapps/badges/api/tests.py index 8a91327b42..5529f83120 100644 --- a/lms/djangoapps/badges/api/tests.py +++ b/lms/djangoapps/badges/api/tests.py @@ -3,18 +3,16 @@ Tests for the badges API views. """ -import six -from ddt import data, ddt, unpack # lint-amnesty, pylint: disable=import-error +from ddt import data, ddt, unpack from django.conf import settings from django.test.utils import override_settings -from six.moves import range -from lms.djangoapps.badges.tests.factories import BadgeAssertionFactory, BadgeClassFactory, RandomBadgeClassFactory -from openedx.core.lib.api.test_utils import ApiTestCase from common.djangoapps.student.tests.factories import UserFactory from common.djangoapps.util.testing import UrlResetMixin -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order -from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order +from lms.djangoapps.badges.tests.factories import BadgeAssertionFactory, BadgeClassFactory, RandomBadgeClassFactory +from openedx.core.lib.api.test_utils import ApiTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory FEATURES_WITH_BADGES_ENABLED = settings.FEATURES.copy() FEATURES_WITH_BADGES_ENABLED['ENABLE_OPENBADGES'] = True @@ -27,7 +25,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase): """ def setUp(self): - super(UserAssertionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.user = UserFactory.create() # Password defined by factory. @@ -37,7 +35,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase): """ Return the URL to look up the current user's assertions. """ - return '/api/badges/v1/assertions/user/{}/'.format(self.user.username) + return f'/api/badges/v1/assertions/user/{self.user.username}/' def check_class_structure(self, badge_class, json_class): """ @@ -48,7 +46,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase): assert badge_class.image.url in json_class['image_url'] assert badge_class.description == json_class['description'] assert badge_class.criteria == json_class['criteria'] - assert (badge_class.course_id and six.text_type(badge_class.course_id)) == json_class['course_id'] + assert (badge_class.course_id and str(badge_class.course_id)) == json_class['course_id'] def check_assertion_structure(self, assertion, json_assertion): """ @@ -65,7 +63,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase): if wildcard: return '*' else: - return six.text_type(badge_class.course_id) + return str(badge_class.course_id) def create_badge_class(self, check_course, **kwargs): """ diff --git a/lms/djangoapps/badges/api/views.py b/lms/djangoapps/badges/api/views.py index f568e99c13..b5b5b9cac4 100644 --- a/lms/djangoapps/badges/api/views.py +++ b/lms/djangoapps/badges/api/views.py @@ -3,12 +3,13 @@ API views for badges """ -from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser # lint-amnesty, pylint: disable=import-error -from opaque_keys import InvalidKeyError # lint-amnesty, pylint: disable=import-error -from opaque_keys.edx.django.models import CourseKeyField # lint-amnesty, pylint: disable=import-error -from opaque_keys.edx.keys import CourseKey # lint-amnesty, pylint: disable=import-error -from rest_framework import generics # lint-amnesty, pylint: disable=import-error -from rest_framework.exceptions import APIException # lint-amnesty, pylint: disable=import-error +from edx_rest_framework_extensions.auth.session.authentication import \ + SessionAuthenticationAllowInactiveUser +from opaque_keys import InvalidKeyError +from opaque_keys.edx.django.models import CourseKeyField +from opaque_keys.edx.keys import CourseKey +from rest_framework import generics +from rest_framework.exceptions import APIException from lms.djangoapps.badges.models import BadgeAssertion from openedx.core.djangoapps.user_api.permissions import is_field_shared_factory diff --git a/lms/djangoapps/badges/apps.py b/lms/djangoapps/badges/apps.py index f76094a905..4380a609b2 100644 --- a/lms/djangoapps/badges/apps.py +++ b/lms/djangoapps/badges/apps.py @@ -12,7 +12,7 @@ class BadgesConfig(AppConfig): """ Application Configuration for Badges. """ - name = u'lms.djangoapps.badges' + name = 'lms.djangoapps.badges' def ready(self): """ diff --git a/lms/djangoapps/badges/backends/badgr.py b/lms/djangoapps/badges/backends/badgr.py index 64e15474cc..829d1d7514 100644 --- a/lms/djangoapps/badges/backends/badgr.py +++ b/lms/djangoapps/badges/backends/badgr.py @@ -7,11 +7,10 @@ import hashlib import logging import mimetypes -import requests # lint-amnesty, pylint: disable=import-error -import six +import requests from django.conf import settings from django.core.exceptions import ImproperlyConfigured -from eventtracking import tracker # lint-amnesty, pylint: disable=import-error +from eventtracking import tracker from lazy import lazy # lint-amnesty, pylint: disable=no-name-in-module from requests.packages.urllib3.exceptions import HTTPError # lint-amnesty, pylint: disable=import-error @@ -29,7 +28,7 @@ class BadgrBackend(BadgeBackend): badges = [] def __init__(self): - super(BadgrBackend, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() if not settings.BADGR_API_TOKEN: raise ImproperlyConfigured("BADGR_API_TOKEN not set.") @@ -38,20 +37,20 @@ class BadgrBackend(BadgeBackend): """ Base URL for all API requests. """ - return "{}/v1/issuer/issuers/{}".format(settings.BADGR_BASE_URL, settings.BADGR_ISSUER_SLUG) + return f"{settings.BADGR_BASE_URL}/v1/issuer/issuers/{settings.BADGR_ISSUER_SLUG}" @lazy def _badge_create_url(self): """ URL for generating a new Badge specification """ - return "{}/badges".format(self._base_url) + return f"{self._base_url}/badges" def _badge_url(self, slug): """ Get the URL for a course's badge in a given mode. """ - return "{}/{}".format(self._badge_create_url, slug) + return f"{self._badge_create_url}/{slug}" def _assertion_url(self, slug): """ @@ -67,7 +66,7 @@ class BadgrBackend(BadgeBackend): if badge_class.issuing_component and badge_class.course_id: # Make this unique to the course, and down to 64 characters. # We don't do this to badges without issuing_component set for backwards compatibility. - slug = hashlib.sha256((slug + six.text_type(badge_class.course_id)).encode('utf-8')).hexdigest() + slug = hashlib.sha256((slug + str(badge_class.course_id)).encode('utf-8')).hexdigest() if len(slug) > MAX_SLUG_LENGTH: # Will be 64 characters. slug = hashlib.sha256(slug).hexdigest() @@ -81,9 +80,9 @@ class BadgrBackend(BadgeBackend): response.raise_for_status() except HTTPError: LOGGER.error( - u"Encountered an error when contacting the Badgr-Server. Request sent to %r with headers %r.\n" - u"and data values %r\n" - u"Response status was %s.\n%s", + "Encountered an error when contacting the Badgr-Server. Request sent to %r with headers %r.\n" + "and data values %r\n" + "Response status was %s.\n%s", response.request.url, response.request.headers, data, response.status_code, response.content @@ -100,8 +99,8 @@ class BadgrBackend(BadgeBackend): content_type, __ = mimetypes.guess_type(image.name) if not content_type: raise ValueError( - u"Could not determine content-type of image! Make sure it is a properly named .png file. " - u"Filename was: {}".format(image.name) + "Could not determine content-type of image! Make sure it is a properly named .png file. " + "Filename was: {}".format(image.name) ) files = {'image': (image.name, image, content_type)} data = { @@ -126,7 +125,7 @@ class BadgrBackend(BadgeBackend): 'badge_slug': assertion.badge_class.slug, 'badge_name': assertion.badge_class.display_name, 'issuing_component': assertion.badge_class.issuing_component, - 'course_id': six.text_type(assertion.badge_class.course_id), + 'course_id': str(assertion.badge_class.course_id), 'enrollment_mode': assertion.badge_class.mode, 'assertion_id': assertion.id, 'assertion_image_url': assertion.image_url, @@ -162,7 +161,7 @@ class BadgrBackend(BadgeBackend): """ Headers to send along with the request-- used for authentication. """ - return {'Authorization': u'Token {}'.format(settings.BADGR_API_TOKEN)} + return {'Authorization': f'Token {settings.BADGR_API_TOKEN}'} def _ensure_badge_created(self, badge_class): """ diff --git a/lms/djangoapps/badges/backends/base.py b/lms/djangoapps/badges/backends/base.py index 7aae363a99..868ef0df74 100644 --- a/lms/djangoapps/badges/backends/base.py +++ b/lms/djangoapps/badges/backends/base.py @@ -5,10 +5,8 @@ Base class for badge backends. from abc import ABCMeta, abstractmethod -import six - -class BadgeBackend(six.with_metaclass(ABCMeta, object)): +class BadgeBackend(metaclass=ABCMeta): """ Defines the interface for badging backends. """ diff --git a/lms/djangoapps/badges/backends/tests/test_badgr_backend.py b/lms/djangoapps/badges/backends/tests/test_badgr_backend.py index 39a09bf428..f970d6f5ef 100644 --- a/lms/djangoapps/badges/backends/tests/test_badgr_backend.py +++ b/lms/djangoapps/badges/backends/tests/test_badgr_backend.py @@ -4,22 +4,21 @@ Tests for BadgrBackend from datetime import datetime +from unittest.mock import Mock, call, patch -import ddt # lint-amnesty, pylint: disable=import-error -import six +import ddt from django.db.models.fields.files import ImageFieldFile from django.test.utils import override_settings -from lazy.lazy import lazy # lint-amnesty, pylint: disable=import-error, no-name-in-module -from mock import Mock, call, patch # lint-amnesty, pylint: disable=import-error +from lazy.lazy import lazy # lint-amnesty, pylint: disable=no-name-in-module +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from common.djangoapps.track.tests import EventTrackingTestCase from lms.djangoapps.badges.backends.badgr import BadgrBackend from lms.djangoapps.badges.models import BadgeAssertion from lms.djangoapps.badges.tests.factories import BadgeClassFactory from openedx.core.lib.tests.assertions.events import assert_event_matches -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from common.djangoapps.track.tests import EventTrackingTestCase -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order -from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory BADGR_SETTINGS = { 'BADGR_API_TOKEN': '12345', @@ -43,7 +42,7 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase): """ Create a course and user to test with. """ - super(BadgrBackendTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Need key to be deterministic to test slugs. self.course = CourseFactory.create( org='edX', course='course_test', run='test_run', display_name='Badged', @@ -182,7 +181,7 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase): 'name': 'edx.badge.assertion.created', 'data': { 'user_id': self.user.id, - 'course_id': six.text_type(self.course.location.course_key), + 'course_id': str(self.course.location.course_key), 'enrollment_mode': 'honor', 'assertion_id': assertion.id, 'badge_name': 'Test Badge', diff --git a/lms/djangoapps/badges/events/course_complete.py b/lms/djangoapps/badges/events/course_complete.py index 945711645f..5551e7330d 100644 --- a/lms/djangoapps/badges/events/course_complete.py +++ b/lms/djangoapps/badges/events/course_complete.py @@ -6,16 +6,13 @@ Helper functions for the course complete event that was originally included with import hashlib import logging -import six - from django.urls import reverse from django.utils.text import slugify from django.utils.translation import ugettext_lazy as _ from lms.djangoapps.badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfiguration from lms.djangoapps.badges.utils import requires_badges_enabled, site_prefix -from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=import-error, wrong-import-order - +from xmodule.modulestore.django import modulestore LOGGER = logging.getLogger(__name__) @@ -35,9 +32,9 @@ def course_slug(course_key, mode): """ # Seven digits should be enough to realistically avoid collisions. That's what git services use. digest = hashlib.sha256( - u"{}{}".format(six.text_type(course_key), six.text_type(mode)).encode('utf-8') + "{}{}".format(str(course_key), str(mode)).encode('utf-8') ).hexdigest()[:7] - base_slug = slugify(six.text_type(course_key) + u'_{}_'.format(mode))[:248] + base_slug = slugify(str(course_key) + f'_{mode}_')[:248] return base_slug + digest @@ -46,14 +43,14 @@ def badge_description(course, mode): Returns a description for the earned badge. """ if course.end: - return _(u'Completed the course "{course_name}" ({course_mode}, {start_date} - {end_date})').format( + return _('Completed the course "{course_name}" ({course_mode}, {start_date} - {end_date})').format( start_date=course.start.date(), end_date=course.end.date(), course_name=course.display_name, course_mode=mode, ) else: - return _(u'Completed the course "{course_name}" ({course_mode})').format( + return _('Completed the course "{course_name}" ({course_mode})').format( course_name=course.display_name, course_mode=mode, ) @@ -64,7 +61,7 @@ def evidence_url(user_id, course_key): Generates a URL to the user's Certificate HTML view, along with a GET variable that will signal the evidence visit event. """ - course_id = six.text_type(course_key) + course_id = str(course_key) # avoid circular import problems from lms.djangoapps.certificates.models import GeneratedCertificate cert = GeneratedCertificate.eligible_certificates.get(user__id=int(user_id), course_id=course_id) @@ -76,8 +73,8 @@ def criteria(course_key): """ Constructs the 'criteria' URL from the course about page. """ - about_path = reverse('about_course', kwargs={'course_id': six.text_type(course_key)}) - return u'{}{}'.format(site_prefix(), about_path) + about_path = reverse('about_course', kwargs={'course_id': str(course_key)}) + return f'{site_prefix()}{about_path}' def get_completion_badge(course_id, user): diff --git a/lms/djangoapps/badges/events/tests/test_course_complete.py b/lms/djangoapps/badges/events/tests/test_course_complete.py index 6506b10de4..73f449e014 100644 --- a/lms/djangoapps/badges/events/tests/test_course_complete.py +++ b/lms/djangoapps/badges/events/tests/test_course_complete.py @@ -4,11 +4,11 @@ Tests for the course completion helper functions. from datetime import datetime from uuid import uuid4 +from common.djangoapps.student.tests.factories import UserFactory from lms.djangoapps.badges.events import course_complete from lms.djangoapps.certificates.models import GeneratedCertificate -from common.djangoapps.student.tests.factories import UserFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order -from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory class CourseCompleteTestCase(ModuleStoreTestCase): @@ -17,7 +17,7 @@ class CourseCompleteTestCase(ModuleStoreTestCase): """ def setUp(self): - super(CourseCompleteTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Need key to be deterministic to test slugs. self.course = CourseFactory.create( org='edX', course='course_test', run='test_run', display_name='Badged', diff --git a/lms/djangoapps/badges/events/tests/test_course_meta.py b/lms/djangoapps/badges/events/tests/test_course_meta.py index e1007b5fcb..d21b166d88 100644 --- a/lms/djangoapps/badges/events/tests/test_course_meta.py +++ b/lms/djangoapps/badges/events/tests/test_course_meta.py @@ -3,19 +3,18 @@ Tests the course meta badging events """ -import six -from six.moves import range, zip -from ddt import data, ddt, unpack # lint-amnesty, pylint: disable=import-error +from unittest.mock import patch + +from ddt import data, ddt, unpack from django.conf import settings from django.test.utils import override_settings -from mock import patch # lint-amnesty, pylint: disable=import-error -from lms.djangoapps.badges.tests.factories import CourseEventBadgesConfigurationFactory, RandomBadgeClassFactory -from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import UserFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order -from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order +from lms.djangoapps.badges.tests.factories import CourseEventBadgesConfigurationFactory, RandomBadgeClassFactory +from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory @ddt @@ -27,7 +26,7 @@ class CourseEnrollmentBadgeTest(ModuleStoreTestCase): """ def setUp(self): - super(CourseEnrollmentBadgeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.badge_classes = [ RandomBadgeClassFactory( issuing_component='openedx__course' @@ -77,7 +76,7 @@ class CourseCompletionBadgeTest(ModuleStoreTestCase): """ def setUp(self): - super(CourseCompletionBadgeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.badge_classes = [ RandomBadgeClassFactory( issuing_component='openedx__course' @@ -131,7 +130,7 @@ class CourseGroupBadgeTest(ModuleStoreTestCase): """ def setUp(self): - super(CourseGroupBadgeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.badge_classes = [ RandomBadgeClassFactory( issuing_component='openedx__course' @@ -145,8 +144,8 @@ class CourseGroupBadgeTest(ModuleStoreTestCase): ] self.courses = [] for _badge_class in self.badge_classes: - self.courses.append([CourseFactory().location.course_key for _i in range(3)]) - lines = [badge_class.slug + ',' + ','.join([six.text_type(course_key) for course_key in keys]) + self.courses.append([CourseFactory().location.course_key for _i in range(3)]) # lint-amnesty, pylint: disable=no-member + lines = [badge_class.slug + ',' + ','.join([str(course_key) for course_key in keys]) for badge_class, keys in zip(self.badge_classes, self.courses)] config = '\r'.join(lines) self.config = CourseEventBadgesConfigurationFactory(course_groups=config) diff --git a/lms/djangoapps/badges/handlers.py b/lms/djangoapps/badges/handlers.py index 4af4c58adb..d65448128a 100644 --- a/lms/djangoapps/badges/handlers.py +++ b/lms/djangoapps/badges/handlers.py @@ -5,10 +5,10 @@ Badges related signal handlers. from django.dispatch import receiver -from lms.djangoapps.badges.events.course_meta import award_enrollment_badge -from lms.djangoapps.badges.utils import badges_enabled from common.djangoapps.student.models import EnrollStatusChange from common.djangoapps.student.signals import ENROLL_STATUS_CHANGE +from lms.djangoapps.badges.events.course_meta import award_enrollment_badge +from lms.djangoapps.badges.utils import badges_enabled @receiver(ENROLL_STATUS_CHANGE) diff --git a/lms/djangoapps/badges/migrations/0001_initial.py b/lms/djangoapps/badges/migrations/0001_initial.py index 2d6e3af68f..edb7dc4cf8 100644 --- a/lms/djangoapps/badges/migrations/0001_initial.py +++ b/lms/djangoapps/badges/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import django.utils.timezone import jsonfield.fields from django.conf import settings @@ -35,13 +32,13 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('slug', models.SlugField(max_length=255, validators=[badges_models.validate_lowercase])), - ('issuing_component', models.SlugField(default=u'', blank=True, validators=[badges_models.validate_lowercase])), + ('issuing_component', models.SlugField(default='', blank=True, validators=[badges_models.validate_lowercase])), ('display_name', models.CharField(max_length=255)), ('course_id', CourseKeyField(default=None, max_length=255, blank=True)), ('description', models.TextField()), ('criteria', models.TextField()), - ('mode', models.CharField(default=u'', max_length=100, blank=True)), - ('image', models.ImageField(upload_to=u'badge_classes', validators=[badges_models.validate_badge_image])), + ('mode', models.CharField(default='', max_length=100, blank=True)), + ('image', models.ImageField(upload_to='badge_classes', validators=[badges_models.validate_badge_image])), ], ), migrations.CreateModel( @@ -49,13 +46,13 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('mode', models.CharField(help_text='The course mode for this badge image. For example, "verified" or "honor".', unique=True, max_length=125)), - ('icon', models.ImageField(help_text='Badge images must be square PNG files. The file size should be under 250KB.', upload_to=u'course_complete_badges', validators=[badges_models.validate_badge_image])), + ('icon', models.ImageField(help_text='Badge images must be square PNG files. The file size should be under 250KB.', upload_to='course_complete_badges', validators=[badges_models.validate_badge_image])), ('default', models.BooleanField(default=False, help_text='Set this value to True if you want this image to be the default image for any course modes that do not have a specified badge image. You can have only one default image.')), ], ), migrations.AlterUniqueTogether( name='badgeclass', - unique_together=set([('slug', 'issuing_component', 'course_id')]), + unique_together={('slug', 'issuing_component', 'course_id')}, ), migrations.AddField( model_name='badgeassertion', diff --git a/lms/djangoapps/badges/migrations/0002_data__migrate_assertions.py b/lms/djangoapps/badges/migrations/0002_data__migrate_assertions.py index 01c185226a..ae6a88cca3 100644 --- a/lms/djangoapps/badges/migrations/0002_data__migrate_assertions.py +++ b/lms/djangoapps/badges/migrations/0002_data__migrate_assertions.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import json import os import time @@ -45,7 +42,7 @@ def forwards(apps, schema_editor): badge_class.image.name = icon.name badge_class.save() classes[(badge.course_id, badge.mode)] = badge_class - if isinstance(badge.data, six.string_types): + if isinstance(badge.data, str): data = badge.data else: data = json.dumps(badge.data) @@ -83,7 +80,7 @@ def backwards(apps, schema_editor): if not badge.badge_class.mode: # Can't preserve old badges without modes. continue - if isinstance(badge.data, six.string_types): + if isinstance(badge.data, str): data = badge.data else: data = json.dumps(badge.data) diff --git a/lms/djangoapps/badges/migrations/0003_schema__add_event_configuration.py b/lms/djangoapps/badges/migrations/0003_schema__add_event_configuration.py index 002a318839..667925fc25 100644 --- a/lms/djangoapps/badges/migrations/0003_schema__add_event_configuration.py +++ b/lms/djangoapps/badges/migrations/0003_schema__add_event_configuration.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import django.db.models.deletion from django.conf import settings from django.db import migrations, models @@ -20,9 +17,9 @@ class Migration(migrations.Migration): ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')), ('enabled', models.BooleanField(default=False, verbose_name='Enabled')), - ('courses_completed', models.TextField(default=u'', help_text="On each line, put the number of completed courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)), - ('courses_enrolled', models.TextField(default=u'', help_text="On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)), - ('course_groups', models.TextField(default=u'', help_text="Each line is a comma-separated list. The first item in each line is the slug of a badge class you have created that has an issuing component of 'openedx__course'. The remaining items in each line are the course keys the learner needs to complete to be awarded the badge. For example: slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second", blank=True)), + ('courses_completed', models.TextField(default='', help_text="On each line, put the number of completed courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)), + ('courses_enrolled', models.TextField(default='', help_text="On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)), + ('course_groups', models.TextField(default='', help_text="Each line is a comma-separated list. The first item in each line is the slug of a badge class you have created that has an issuing component of 'openedx__course'. The remaining items in each line are the course keys the learner needs to complete to be awarded the badge. For example: slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second", blank=True)), ('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')), ], ), diff --git a/lms/djangoapps/badges/models.py b/lms/djangoapps/badges/models.py index 96673197fb..fcfd7c01c9 100644 --- a/lms/djangoapps/badges/models.py +++ b/lms/djangoapps/badges/models.py @@ -5,24 +5,23 @@ Database models for the badges app from importlib import import_module -import six -from config_models.models import ConfigurationModel # lint-amnesty, pylint: disable=import-error +from config_models.models import ConfigurationModel from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.core.exceptions import ValidationError from django.db import models from django.utils.encoding import python_2_unicode_compatible # lint-amnesty, pylint: disable=no-name-in-module from django.utils.translation import ugettext_lazy as _ -from jsonfield import JSONField # lint-amnesty, pylint: disable=import-error +from jsonfield import JSONField from lazy import lazy # lint-amnesty, pylint: disable=no-name-in-module -from model_utils.models import TimeStampedModel # lint-amnesty, pylint: disable=import-error -from opaque_keys import InvalidKeyError # lint-amnesty, pylint: disable=import-error -from opaque_keys.edx.django.models import CourseKeyField # lint-amnesty, pylint: disable=import-error -from opaque_keys.edx.keys import CourseKey # lint-amnesty, pylint: disable=import-error +from model_utils.models import TimeStampedModel +from opaque_keys import InvalidKeyError +from opaque_keys.edx.django.models import CourseKeyField +from opaque_keys.edx.keys import CourseKey from lms.djangoapps.badges.utils import deserialize_count_specs from openedx.core.djangolib.markup import HTML, Text -from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=import-error, wrong-import-order +from xmodule.modulestore.django import modulestore def validate_badge_image(image): @@ -30,9 +29,9 @@ def validate_badge_image(image): Validates that a particular image is small enough to be a badge and square. """ if image.width != image.height: - raise ValidationError(_(u"The badge image must be square.")) + raise ValidationError(_("The badge image must be square.")) if not image.size < (250 * 1024): - raise ValidationError(_(u"The badge image file size must be less than 250KB.")) + raise ValidationError(_("The badge image file size must be less than 250KB.")) def validate_lowercase(string): @@ -40,7 +39,7 @@ def validate_lowercase(string): Validates that a string is lowercase. """ if not string.islower(): - raise ValidationError(_(u"This value must be all lowercase.")) + raise ValidationError(_("This value must be all lowercase.")) class CourseBadgesDisabledError(Exception): @@ -57,17 +56,17 @@ class BadgeClass(models.Model): .. no_pii: """ slug = models.SlugField(max_length=255, validators=[validate_lowercase]) - issuing_component = models.SlugField(max_length=50, default=u'', blank=True, validators=[validate_lowercase]) + issuing_component = models.SlugField(max_length=50, default='', blank=True, validators=[validate_lowercase]) display_name = models.CharField(max_length=255) course_id = CourseKeyField(max_length=255, blank=True, default=None) description = models.TextField() criteria = models.TextField() # Mode a badge was awarded for. Included for legacy/migration purposes. - mode = models.CharField(max_length=100, default=u'', blank=True) - image = models.ImageField(upload_to=u'badge_classes', validators=[validate_badge_image]) + mode = models.CharField(max_length=100, default='', blank=True) + image = models.ImageField(upload_to='badge_classes', validators=[validate_badge_image]) def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned - return HTML(u"").format( + return HTML("").format( slug=HTML(self.slug), issuing_component=HTML(self.issuing_component) ) @@ -138,9 +137,9 @@ class BadgeClass(models.Model): """ self.slug = self.slug and self.slug.lower() self.issuing_component = self.issuing_component and self.issuing_component.lower() - super(BadgeClass, self).save(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().save(**kwargs) - class Meta(object): + class Meta: app_label = "badges" unique_together = (('slug', 'issuing_component', 'course_id'),) verbose_name_plural = "Badge Classes" @@ -161,7 +160,7 @@ class BadgeAssertion(TimeStampedModel): assertion_url = models.URLField() def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned - return HTML(u"<{username} Badge Assertion for {slug} for {issuing_component}").format( + return HTML("<{username} Badge Assertion for {slug} for {issuing_component}").format( username=HTML(self.user.username), slug=HTML(self.badge_class.slug), issuing_component=HTML(self.badge_class.issuing_component), @@ -176,7 +175,7 @@ class BadgeAssertion(TimeStampedModel): return cls.objects.filter(user=user, badge_class__course_id=course_id) return cls.objects.filter(user=user) - class Meta(object): + class Meta: app_label = "badges" @@ -193,29 +192,29 @@ class CourseCompleteImageConfiguration(models.Model): """ mode = models.CharField( max_length=125, - help_text=_(u'The course mode for this badge image. For example, "verified" or "honor".'), + help_text=_('The course mode for this badge image. For example, "verified" or "honor".'), unique=True, ) icon = models.ImageField( # Actual max is 256KB, but need overhead for badge baking. This should be more than enough. help_text=_( - u"Badge images must be square PNG files. The file size should be under 250KB." + "Badge images must be square PNG files. The file size should be under 250KB." ), - upload_to=u'course_complete_badges', + upload_to='course_complete_badges', validators=[validate_badge_image] ) default = models.BooleanField( help_text=_( - u"Set this value to True if you want this image to be the default image for any course modes " - u"that do not have a specified badge image. You can have only one default image." + "Set this value to True if you want this image to be the default image for any course modes " + "that do not have a specified badge image. You can have only one default image." ), default=False, ) def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned - return HTML(u"").format( + return HTML("").format( mode=HTML(self.mode), - default=HTML(u" (default)") if self.default else HTML(u'') + default=HTML(" (default)") if self.default else HTML('') ) def clean(self): @@ -223,7 +222,7 @@ class CourseCompleteImageConfiguration(models.Model): Make sure there's not more than one default. """ if self.default and CourseCompleteImageConfiguration.objects.filter(default=True).exclude(id=self.id): - raise ValidationError(_(u"There can be only one default image.")) + raise ValidationError(_("There can be only one default image.")) @classmethod def image_for_mode(cls, mode): @@ -236,7 +235,7 @@ class CourseCompleteImageConfiguration(models.Model): # Fall back to default, if there is one. return cls.objects.get(default=True).icon - class Meta(object): + class Meta: app_label = "badges" @@ -249,34 +248,34 @@ class CourseEventBadgesConfiguration(ConfigurationModel): .. no_pii: """ courses_completed = models.TextField( - blank=True, default=u'', + blank=True, default='', help_text=_( - u"On each line, put the number of completed courses to award a badge for, a comma, and the slug of a " - u"badge class you have created that has the issuing component 'openedx__course'. " - u"For example: 3,enrolled_3_courses" + "On each line, put the number of completed courses to award a badge for, a comma, and the slug of a " + "badge class you have created that has the issuing component 'openedx__course'. " + "For example: 3,enrolled_3_courses" ) ) courses_enrolled = models.TextField( - blank=True, default=u'', + blank=True, default='', help_text=_( - u"On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a " - u"badge class you have created that has the issuing component 'openedx__course'. " - u"For example: 3,enrolled_3_courses" + "On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a " + "badge class you have created that has the issuing component 'openedx__course'. " + "For example: 3,enrolled_3_courses" ) ) course_groups = models.TextField( - blank=True, default=u'', + blank=True, default='', help_text=_( - u"Each line is a comma-separated list. The first item in each line is the slug of a badge class you " - u"have created that has an issuing component of 'openedx__course'. The remaining items in each line are " - u"the course keys the learner needs to complete to be awarded the badge. For example: " - u"slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second" + "Each line is a comma-separated list. The first item in each line is the slug of a badge class you " + "have created that has an issuing component of 'openedx__course'. The remaining items in each line are " + "the course keys the learner needs to complete to be awarded the badge. For example: " + "slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second" ) ) def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned - return HTML(u"").format( - Text(u"Enabled") if self.enabled else Text(u"Disabled") + return HTML("").format( + Text("Enabled") if self.enabled else Text("Disabled") ) @property @@ -314,28 +313,28 @@ class CourseEventBadgesConfiguration(ConfigurationModel): Verify the settings are parseable. """ errors = {} - error_message = _(u"Please check the syntax of your entry.") + error_message = _("Please check the syntax of your entry.") if 'courses_completed' not in exclude: try: self.completed_settings except (ValueError, InvalidKeyError): - errors['courses_completed'] = [six.text_type(error_message)] + errors['courses_completed'] = [str(error_message)] if 'courses_enrolled' not in exclude: try: self.enrolled_settings except (ValueError, InvalidKeyError): - errors['courses_enrolled'] = [six.text_type(error_message)] + errors['courses_enrolled'] = [str(error_message)] if 'course_groups' not in exclude: store = modulestore() try: for key_list in self.course_group_settings.values(): for course_key in key_list: if not store.get_course(course_key): - ValueError(u"The course {course_key} does not exist.".format(course_key=course_key)) + ValueError(f"The course {course_key} does not exist.") except (ValueError, InvalidKeyError): - errors['course_groups'] = [six.text_type(error_message)] + errors['course_groups'] = [str(error_message)] if errors: raise ValidationError(errors) - class Meta(object): + class Meta: app_label = "badges" diff --git a/lms/djangoapps/badges/service.py b/lms/djangoapps/badges/service.py index bd69914dcd..2870ac7df4 100644 --- a/lms/djangoapps/badges/service.py +++ b/lms/djangoapps/badges/service.py @@ -6,7 +6,7 @@ Badging service for XBlocks from lms.djangoapps.badges.models import BadgeClass -class BadgingService(object): +class BadgingService: """ A class that provides functions for managing badges which XBlocks can use. diff --git a/lms/djangoapps/badges/tests/factories.py b/lms/djangoapps/badges/tests/factories.py index 5042fb8c09..7fca1fe397 100644 --- a/lms/djangoapps/badges/tests/factories.py +++ b/lms/djangoapps/badges/tests/factories.py @@ -5,13 +5,18 @@ Factories for Badge tests from random import random -import factory # lint-amnesty, pylint: disable=import-error +import factory from django.core.files.base import ContentFile -from factory import DjangoModelFactory # lint-amnesty, pylint: disable=import-error -from factory.django import ImageField # lint-amnesty, pylint: disable=import-error +from factory import DjangoModelFactory +from factory.django import ImageField -from lms.djangoapps.badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfiguration, CourseEventBadgesConfiguration # lint-amnesty, pylint: disable=line-too-long from common.djangoapps.student.tests.factories import UserFactory +from lms.djangoapps.badges.models import ( # lint-amnesty, pylint: disable=line-too-long + BadgeAssertion, + BadgeClass, + CourseCompleteImageConfiguration, + CourseEventBadgesConfiguration +) def generate_dummy_image(_unused): @@ -29,7 +34,7 @@ class CourseCompleteImageConfigurationFactory(DjangoModelFactory): """ Factory for BadgeImageConfigurations """ - class Meta(object): + class Meta: model = CourseCompleteImageConfiguration mode = 'honor' @@ -40,7 +45,7 @@ class BadgeClassFactory(DjangoModelFactory): """ Factory for BadgeClass """ - class Meta(object): + class Meta: model = BadgeClass slug = 'test_slug' @@ -63,7 +68,7 @@ class BadgeAssertionFactory(DjangoModelFactory): """ Factory for BadgeAssertions """ - class Meta(object): + class Meta: model = BadgeAssertion user = factory.SubFactory(UserFactory) @@ -77,7 +82,7 @@ class CourseEventBadgesConfigurationFactory(DjangoModelFactory): """ Factory for CourseEventsBadgesConfiguration """ - class Meta(object): + class Meta: model = CourseEventBadgesConfiguration enabled = True diff --git a/lms/djangoapps/badges/tests/test_models.py b/lms/djangoapps/badges/tests/test_models.py index 3e9ae7f7de..e6469dc6a5 100644 --- a/lms/djangoapps/badges/tests/test_models.py +++ b/lms/djangoapps/badges/tests/test_models.py @@ -2,6 +2,9 @@ Tests for the Badges app models. """ + +from unittest.mock import Mock, patch + import pytest from django.core.exceptions import ValidationError from django.core.files.images import ImageFile @@ -9,10 +12,9 @@ from django.core.files.storage import default_storage from django.db.utils import IntegrityError from django.test import TestCase from django.test.utils import override_settings -from mock import Mock, patch # lint-amnesty, pylint: disable=import-error -from path import Path # lint-amnesty, pylint: disable=import-error -from six.moves import range +from path import Path +from common.djangoapps.student.tests.factories import UserFactory from lms.djangoapps.badges.models import ( BadgeAssertion, BadgeClass, @@ -22,9 +24,8 @@ from lms.djangoapps.badges.models import ( ) from lms.djangoapps.badges.tests.factories import BadgeAssertionFactory, BadgeClassFactory, RandomBadgeClassFactory from lms.djangoapps.certificates.tests.test_models import TEST_DATA_ROOT -from common.djangoapps.student.tests.factories import UserFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order -from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory def get_image(name): @@ -60,7 +61,7 @@ class BadgeImageConfigurationTest(TestCase): .full_clean) -class DummyBackend(object): +class DummyBackend: """ Dummy badge backend, used for testing. """ @@ -74,7 +75,7 @@ class BadgeClassTest(ModuleStoreTestCase): """ def setUp(self): - super(BadgeClassTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.addCleanup(self.cleanup_uploads) def cleanup_uploads(self): diff --git a/lms/djangoapps/badges/utils.py b/lms/djangoapps/badges/utils.py index e6ade5f536..150834e04c 100644 --- a/lms/djangoapps/badges/utils.py +++ b/lms/djangoapps/badges/utils.py @@ -10,8 +10,8 @@ def site_prefix(): """ Get the prefix for the site URL-- protocol and server name. """ - scheme = u"https" if settings.HTTPS == "on" else u"http" - return u'{}://{}'.format(scheme, settings.SITE_NAME) + scheme = "https" if settings.HTTPS == "on" else "http" + return f'{scheme}://{settings.SITE_NAME}' def requires_badges_enabled(function):