diff --git a/common/djangoapps/student/admin.py b/common/djangoapps/student/admin.py index 3ec615134d..88bcaf4d64 100644 --- a/common/djangoapps/student/admin.py +++ b/common/djangoapps/student/admin.py @@ -61,7 +61,7 @@ User = get_user_model() # pylint:disable=invalid-name COURSE_ENROLLMENT_ADMIN_SWITCH = WaffleSwitch('student.courseenrollment_admin', __name__) -class _Check(object): +class _Check: """ A method decorator that pre-emptively returns false if a feature is disabled. Otherwise, it returns the return value of the decorated method. @@ -128,7 +128,7 @@ class DisableEnrollmentAdminMixin: class CourseAccessRoleForm(forms.ModelForm): """Form for adding new Course Access Roles view the Django Admin Panel.""" - class Meta(object): + class Meta: model = CourseAccessRole fields = '__all__' @@ -152,7 +152,7 @@ class CourseAccessRoleForm(forms.ModelForm): org_name = self.cleaned_data.get('course_id').org if org.lower() != org_name.lower(): raise forms.ValidationError( - u"Org name {} is not valid. Valid name is {}.".format( + "Org name {} is not valid. Valid name is {}.".format( org, org_name ) ) @@ -168,7 +168,7 @@ class CourseAccessRoleForm(forms.ModelForm): user = User.objects.get(email=email) except Exception: raise forms.ValidationError( # lint-amnesty, pylint: disable=raise-missing-from - u"Email does not exist. Could not find {email}. Please re-enter email address".format( + "Email does not exist. Could not find {email}. Please re-enter email address".format( email=email ) ) @@ -179,7 +179,7 @@ class CourseAccessRoleForm(forms.ModelForm): """ Checking the course already exists in db. """ - cleaned_data = super(CourseAccessRoleForm, self).clean() # lint-amnesty, pylint: disable=super-with-arguments + cleaned_data = super().clean() if not self.errors: if CourseAccessRole.objects.filter( user=cleaned_data.get("email"), @@ -192,7 +192,7 @@ class CourseAccessRoleForm(forms.ModelForm): return cleaned_data def __init__(self, *args, **kwargs): - super(CourseAccessRoleForm, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) if self.instance.user_id: self.fields['email'].initial = self.instance.user.email @@ -219,14 +219,14 @@ class CourseAccessRoleAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.user = form.cleaned_data['email'] - super(CourseAccessRoleAdmin, self).save_model(request, obj, form, change) # lint-amnesty, pylint: disable=super-with-arguments + super().save_model(request, obj, form, change) @admin.register(LinkedInAddToProfileConfiguration) class LinkedInAddToProfileConfigurationAdmin(admin.ModelAdmin): """Admin interface for the LinkedIn Add to Profile configuration. """ - class Meta(object): + class Meta: model = LinkedInAddToProfileConfiguration @@ -243,7 +243,7 @@ class CourseEnrollmentForm(forms.ModelForm): raise forms.ValidationError("Cannot make a valid CourseKey from id {}!".format(args_copy['course'])) # lint-amnesty, pylint: disable=raise-missing-from args = [args_copy] - super(CourseEnrollmentForm, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) if self.data.get('course'): try: @@ -259,15 +259,15 @@ class CourseEnrollmentForm(forms.ModelForm): try: course_key = CourseKey.from_string(course_id) except InvalidKeyError: - raise forms.ValidationError("Cannot make a valid CourseKey from id {}!".format(course_id)) # lint-amnesty, pylint: disable=raise-missing-from + raise forms.ValidationError(f"Cannot make a valid CourseKey from id {course_id}!") # lint-amnesty, pylint: disable=raise-missing-from if not modulestore().has_course(course_key): - raise forms.ValidationError("Cannot find course with id {} in the modulestore".format(course_id)) + raise forms.ValidationError(f"Cannot find course with id {course_id} in the modulestore") return course_key def save(self, *args, **kwargs): # lint-amnesty, pylint: disable=signature-differs, unused-argument - course_enrollment = super(CourseEnrollmentForm, self).save(commit=False) # lint-amnesty, pylint: disable=super-with-arguments + course_enrollment = super().save(commit=False) user = self.cleaned_data['user'] course_overview = self.cleaned_data['course'] enrollment = CourseEnrollment.get_or_create_enrollment(user, course_overview.id) @@ -290,7 +290,7 @@ class CourseEnrollmentAdmin(DisableEnrollmentAdminMixin, admin.ModelAdmin): form = CourseEnrollmentForm def get_search_results(self, request, queryset, search_term): - qs, use_distinct = super(CourseEnrollmentAdmin, self).get_search_results(request, queryset, search_term) # lint-amnesty, pylint: disable=super-with-arguments + qs, use_distinct = super().get_search_results(request, queryset, search_term) # annotate each enrollment with whether the username was an # exact match for the search term @@ -305,7 +305,7 @@ class CourseEnrollmentAdmin(DisableEnrollmentAdminMixin, admin.ModelAdmin): return qs, use_distinct def queryset(self, request): - return super(CourseEnrollmentAdmin, self).queryset(request).select_related('user') # lint-amnesty, pylint: disable=no-member, super-with-arguments + return super().queryset(request).select_related('user') # lint-amnesty, pylint: disable=no-member, super-with-arguments class UserProfileInline(admin.StackedInline): @@ -331,7 +331,7 @@ class UserChangeForm(BaseUserChangeForm): last_name = forms.CharField(max_length=30, required=False) def __init__(self, *args, **kwargs): - super(UserChangeForm, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) if not settings.FEATURES.get('ENABLE_CHANGE_USER_PASSWORD_ADMIN'): self.fields["password"] = ReadOnlyPasswordHashField( @@ -353,7 +353,7 @@ class UserAdmin(BaseUserAdmin): Allows editing the users while skipping the username check, so we can have Unicode username with no problems. The username is marked read-only when editing existing users regardless of `ENABLE_UNICODE_USERNAME`, to simplify the bokchoy tests. # lint-amnesty, pylint: disable=line-too-long """ - django_readonly = super(UserAdmin, self).get_readonly_fields(request, obj) # lint-amnesty, pylint: disable=super-with-arguments + django_readonly = super().get_readonly_fields(request, obj) if obj: return django_readonly + ('username',) return django_readonly @@ -367,7 +367,7 @@ class UserAttributeAdmin(admin.ModelAdmin): raw_id_fields = ('user',) search_fields = ('name', 'value', 'user__username',) - class Meta(object): + class Meta: model = UserAttribute @@ -377,7 +377,7 @@ class CourseEnrollmentAllowedAdmin(admin.ModelAdmin): list_display = ('email', 'course_id', 'auto_enroll',) search_fields = ('email', 'course_id',) - class Meta(object): + class Meta: model = CourseEnrollmentAllowed @@ -395,35 +395,35 @@ class LoginFailuresAdmin(admin.ModelAdmin): """ Only enabled if feature is enabled. """ - return super(LoginFailuresAdmin, self).has_module_permission(request) # lint-amnesty, pylint: disable=super-with-arguments + return super().has_module_permission(request) @_Check.is_enabled(LoginFailures.is_feature_enabled) def has_view_permission(self, request, obj=None): """ Only enabled if feature is enabled. """ - return super(LoginFailuresAdmin, self).has_view_permission(request, obj) # lint-amnesty, pylint: disable=super-with-arguments + return super().has_view_permission(request, obj) @_Check.is_enabled(LoginFailures.is_feature_enabled) def has_delete_permission(self, request, obj=None): """ Only enabled if feature is enabled. """ - return super(LoginFailuresAdmin, self).has_delete_permission(request, obj) # lint-amnesty, pylint: disable=super-with-arguments + return super().has_delete_permission(request, obj) @_Check.is_enabled(LoginFailures.is_feature_enabled) def has_change_permission(self, request, obj=None): """ Only enabled if feature is enabled. """ - return super(LoginFailuresAdmin, self).has_change_permission(request, obj) # lint-amnesty, pylint: disable=super-with-arguments + return super().has_change_permission(request, obj) @_Check.is_enabled(LoginFailures.is_feature_enabled) def has_add_permission(self, request): """ Only enabled if feature is enabled. """ - return super(LoginFailuresAdmin, self).has_add_permission(request) # lint-amnesty, pylint: disable=super-with-arguments + return super().has_add_permission(request) def unlock_student_accounts(self, request, queryset): """ @@ -456,13 +456,13 @@ class LoginFailuresAdmin(admin.ModelAdmin): self.unlock_student(request, object_id=object_id) url = reverse('admin:student_loginfailures_changelist', current_app=self.admin_site.name) return HttpResponseRedirect(url) - return super(LoginFailuresAdmin, self).change_view(request, object_id, form_url, extra_context) # lint-amnesty, pylint: disable=super-with-arguments + return super().change_view(request, object_id, form_url, extra_context) def get_actions(self, request): """ Get actions for model admin and remove delete action. """ - actions = super(LoginFailuresAdmin, self).get_actions(request) # lint-amnesty, pylint: disable=super-with-arguments + actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions @@ -480,7 +480,7 @@ class LoginFailuresAdmin(admin.ModelAdmin): class AllowedAuthUserForm(forms.ModelForm): """Model Form for AllowedAuthUser model's admin interface.""" - class Meta(object): + class Meta: model = AllowedAuthUser fields = ('site', 'email', ) @@ -499,7 +499,7 @@ class AllowedAuthUserForm(forms.ModelForm): ) elif email_domain != allowed_site_email_domain: raise forms.ValidationError( - _("Email doesn't have {domain_name} domain name.".format(domain_name=allowed_site_email_domain)) # lint-amnesty, pylint: disable=translation-of-non-string + _(f"Email doesn't have {allowed_site_email_domain} domain name.") # lint-amnesty, pylint: disable=translation-of-non-string ) elif not User.objects.filter(email=email).exists(): raise forms.ValidationError(_("User with this email doesn't exist in system.")) @@ -515,7 +515,7 @@ class AllowedAuthUserAdmin(admin.ModelAdmin): search_fields = ('email',) ordering = ('-created',) - class Meta(object): + class Meta: model = AllowedAuthUser @@ -526,7 +526,7 @@ class CourseEnrollmentCelebrationAdmin(DisableEnrollmentAdminMixin, admin.ModelA list_display = ('id', 'course', 'user', 'celebrate_first_section') search_fields = ('enrollment__course__id', 'enrollment__user__username') - class Meta(object): + class Meta: model = CourseEnrollmentCelebration def course(self, obj): diff --git a/common/djangoapps/student/api.py b/common/djangoapps/student/api.py index dfcd35cdf6..b3cd963d6e 100644 --- a/common/djangoapps/student/api.py +++ b/common/djangoapps/student/api.py @@ -69,7 +69,7 @@ def create_manual_enrollment_audit( know about model level code. """ if transition_state not in TRANSITION_STATES: - raise ValueError("State `{}` not in allow states: `{}`".format(transition_state, TRANSITION_STATES)) + raise ValueError(f"State `{transition_state}` not in allow states: `{TRANSITION_STATES}`") User = get_user_model() try: diff --git a/common/djangoapps/student/apps.py b/common/djangoapps/student/apps.py index 92ef89cb84..e1ec51afca 100644 --- a/common/djangoapps/student/apps.py +++ b/common/djangoapps/student/apps.py @@ -22,6 +22,6 @@ class StudentConfig(AppConfig): # problems in testing, we mock it here so that the mock impacts all tests. if os.environ.get('DISABLE_COURSEENROLLMENT_HISTORY', False): import common.djangoapps.student.models as student_models - from mock import MagicMock + from unittest.mock import MagicMock student_models.CourseEnrollment.history = MagicMock() diff --git a/common/djangoapps/student/helpers.py b/common/djangoapps/student/helpers.py index 81f39a7ce6..332c1ca162 100644 --- a/common/djangoapps/student/helpers.py +++ b/common/djangoapps/student/helpers.py @@ -214,7 +214,7 @@ def check_verify_status_by_course(user, course_enrollments): } if recent_verification_datetime: - for key, value in iteritems(status_by_course): # pylint: disable=unused-variable + for key, value in status_by_course.items(): # pylint: disable=unused-variable status_by_course[key]['verification_good_until'] = recent_verification_datetime.strftime("%m/%d/%Y") return status_by_course @@ -270,8 +270,8 @@ def get_next_url_for_login_page(request, include_host=False): redirect_to = reverse(login_redirect_url) except NoReverseMatch: log.warning( - u'Default redirect after login doesn\'t exist: %(login_redirect_url)r. ' - u'Check the value set on DEFAULT_REDIRECT_AFTER_LOGIN configuration variable.', + 'Default redirect after login doesn\'t exist: %(login_redirect_url)r. ' + 'Check the value set on DEFAULT_REDIRECT_AFTER_LOGIN configuration variable.', {"login_redirect_url": login_redirect_url} ) @@ -283,7 +283,7 @@ def get_next_url_for_login_page(request, include_host=False): elif settings.ROOT_URLCONF == 'cms.urls': redirect_to = reverse('home') scheme = "https" if settings.HTTPS == "on" else "http" - root_url = '{}://{}'.format(scheme, settings.CMS_BASE) + root_url = f'{scheme}://{settings.CMS_BASE}' if any(param in request_params for param in POST_AUTH_PARAMS): # Before we redirect to next/dashboard, we need to handle auto-enrollment: @@ -351,14 +351,14 @@ def _get_redirect_to(request_host, request_headers, request_params, request_is_h ) if not safe_redirect: log.warning( - u"Unsafe redirect parameter detected after login page: '%(redirect_to)s'", + "Unsafe redirect parameter detected after login page: '%(redirect_to)s'", {"redirect_to": redirect_to} ) redirect_to = None elif not accepts_text_html: log.info( - u"Redirect to non html content '%(content_type)s' detected from '%(user_agent)s'" - u" after login page: '%(redirect_to)s'", + "Redirect to non html content '%(content_type)s' detected from '%(user_agent)s'" + " after login page: '%(redirect_to)s'", { "redirect_to": redirect_to, "content_type": header_accept, "user_agent": request_headers.get('HTTP_USER_AGENT', '') @@ -367,13 +367,13 @@ def _get_redirect_to(request_host, request_headers, request_params, request_is_h redirect_to = None elif mime_type: log.warning( - u"Redirect to url path with specified filed type '%(mime_type)s' not allowed: '%(redirect_to)s'", + "Redirect to url path with specified filed type '%(mime_type)s' not allowed: '%(redirect_to)s'", {"redirect_to": redirect_to, "mime_type": mime_type} ) redirect_to = None elif settings.STATIC_URL in redirect_to: log.warning( - u"Redirect to static content detected after login page: '%(redirect_to)s'", + "Redirect to static content detected after login page: '%(redirect_to)s'", {"redirect_to": redirect_to} ) redirect_to = None @@ -383,7 +383,7 @@ def _get_redirect_to(request_host, request_headers, request_params, request_is_h for theme in themes: if theme.theme_dir_name in next_path: log.warning( - u"Redirect to theme content detected after login page: '%(redirect_to)s'", + "Redirect to theme content detected after login page: '%(redirect_to)s'", {"redirect_to": redirect_to} ) redirect_to = None @@ -421,7 +421,7 @@ def authenticate_new_user(request, username, password): backend = load_backend(NEW_USER_AUTH_BACKEND) user = backend.authenticate(request=request, username=username, password=password) if not user: - log.warning("Unable to authenticate user: {username}".format(username=username)) + log.warning(f"Unable to authenticate user: {username}") user.backend = NEW_USER_AUTH_BACKEND return user @@ -431,7 +431,7 @@ class AccountValidationError(Exception): Used in account creation views to raise exceptions with details about specific invalid fields """ def __init__(self, message, field, error_code=None): - super(AccountValidationError, self).__init__(message) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(message) self.field = field self.error_code = error_code @@ -549,7 +549,7 @@ def _cert_info(user, course_overview, cert_status): status_dict['status'] = 'unavailable' elif 'download_url' not in cert_status: log.warning( - u"User %s has a downloadable cert for %s, but no download url", + "User %s has a downloadable cert for %s, but no download url", user.username, course_overview.id ) @@ -587,7 +587,7 @@ def _cert_info(user, course_overview, cert_status): if all(grade is None for grade in grades_input) else max(filter(lambda x: x is not None, grades_input)) ) - status_dict['grade'] = text_type(max_grade) + status_dict['grade'] = str(max_grade) return status_dict @@ -681,7 +681,7 @@ def do_create_account(form, custom_form=None): try: profile.save() except Exception: - log.exception("UserProfile creation failed for user {id}.".format(id=user.id)) + log.exception(f"UserProfile creation failed for user {user.id}.") raise return user, profile, registration diff --git a/common/djangoapps/student/middleware.py b/common/djangoapps/student/middleware.py index f39c062694..5e28ae8df7 100644 --- a/common/djangoapps/student/middleware.py +++ b/common/djangoapps/student/middleware.py @@ -33,7 +33,7 @@ class UserStandingMiddleware(MiddlewareMixin): 'this was done in error, please contact us at ' '{support_email}' )).format( - support_email=HTML(u'{address}').format( + support_email=HTML('{address}').format( address=settings.DEFAULT_FEEDBACK_EMAIL, subject_line=_('Disabled Account'), ), diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py index 3cb38adea0..57949d8fbc 100644 --- a/common/djangoapps/student/models.py +++ b/common/djangoapps/student/models.py @@ -54,7 +54,6 @@ from opaque_keys.edx.keys import CourseKey from pytz import UTC, timezone from simple_history.models import HistoricalRecords from six import text_type -from six.moves import range from slumber.exceptions import HttpClientError, HttpServerError from user_util import user_util @@ -100,7 +99,7 @@ SessionStore = import_module(settings.SESSION_ENGINE).SessionStore # pylint: di # ENROLL signal used for free enrollment only -class EnrollStatusChange(object): +class EnrollStatusChange: """ Possible event types for ENROLL_STATUS_CHANGE signal """ @@ -117,14 +116,14 @@ class EnrollStatusChange(object): # complete a paid course purchase paid_complete = 'paid_complete' -UNENROLLED_TO_ALLOWEDTOENROLL = u'from unenrolled to allowed to enroll' -ALLOWEDTOENROLL_TO_ENROLLED = u'from allowed to enroll to enrolled' -ENROLLED_TO_ENROLLED = u'from enrolled to enrolled' -ENROLLED_TO_UNENROLLED = u'from enrolled to unenrolled' -UNENROLLED_TO_ENROLLED = u'from unenrolled to enrolled' -ALLOWEDTOENROLL_TO_UNENROLLED = u'from allowed to enroll to enrolled' -UNENROLLED_TO_UNENROLLED = u'from unenrolled to unenrolled' -DEFAULT_TRANSITION_STATE = u'N/A' +UNENROLLED_TO_ALLOWEDTOENROLL = 'from unenrolled to allowed to enroll' +ALLOWEDTOENROLL_TO_ENROLLED = 'from allowed to enroll to enrolled' +ENROLLED_TO_ENROLLED = 'from enrolled to enrolled' +ENROLLED_TO_UNENROLLED = 'from enrolled to unenrolled' +UNENROLLED_TO_ENROLLED = 'from unenrolled to enrolled' +ALLOWEDTOENROLL_TO_UNENROLLED = 'from allowed to enroll to enrolled' +UNENROLLED_TO_UNENROLLED = 'from unenrolled to unenrolled' +DEFAULT_TRANSITION_STATE = 'N/A' SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE = 30 TRANSITION_STATES = ( @@ -229,9 +228,9 @@ def anonymous_id_for_user(user, course_id, save='DEPRECATED'): # include the secret key as a salt, and to make the ids unique across different LMS installs. hasher = hashlib.shake_128() hasher.update(settings.SECRET_KEY.encode('utf8')) - hasher.update(text_type(user.id).encode('utf8')) + hasher.update(str(user.id).encode('utf8')) if course_id: - hasher.update(text_type(course_id).encode('utf-8')) + hasher.update(str(course_id).encode('utf-8')) anonymous_user_id = hasher.hexdigest(16) # pylint: disable=too-many-function-args try: @@ -305,7 +304,7 @@ def is_username_retired(username): UserRetirementStatus.objects.filter(original_username=username).exists() except ProgrammingError as exc: # Check the error message to make sure it's what we expect - if "user_api_userretirementstatus" in text_type(exc): + if "user_api_userretirementstatus" in str(exc): return User.objects.filter(username__in=list(locally_hashed_usernames)).exists() raise @@ -426,7 +425,7 @@ def get_potentially_retired_user_by_username(username): # We should have, at most, a retired username and an active one with a username # differing only by case. If there are more we need to disambiguate them by hand. - raise Exception('Expected 1 or 2 Users, received {}'.format(text_type(potential_users))) + raise Exception('Expected 1 or 2 Users, received {}'.format(str(potential_users))) def get_potentially_retired_user_by_username_and_hash(username, hashed_username): @@ -456,11 +455,11 @@ class UserStanding(models.Model): .. no_pii: """ - ACCOUNT_DISABLED = u"disabled" - ACCOUNT_ENABLED = u"enabled" + ACCOUNT_DISABLED = "disabled" + ACCOUNT_ENABLED = "enabled" USER_STANDING_CHOICES = ( - (ACCOUNT_DISABLED, u"Account Disabled"), - (ACCOUNT_ENABLED, u"Account Enabled"), + (ACCOUNT_DISABLED, "Account Disabled"), + (ACCOUNT_ENABLED, "Account Enabled"), ) user = models.OneToOneField(User, db_index=True, related_name='standing', on_delete=models.CASCADE) @@ -494,9 +493,9 @@ class UserProfile(models.Model): .. pii_retirement: local_api """ # cache key format e.g user..profile.country = 'SG' - PROFILE_COUNTRY_CACHE_KEY = u"user.{user_id}.profile.country" + PROFILE_COUNTRY_CACHE_KEY = "user.{user_id}.profile.country" - class Meta(object): + class Meta: db_table = "auth_userprofile" permissions = (("can_deactivate_users", "Can deactivate, but NOT delete users"),) @@ -507,7 +506,7 @@ class UserProfile(models.Model): name = models.CharField(blank=True, max_length=255, db_index=True) meta = models.TextField(blank=True) # JSON dictionary for future expansion - courseware = models.CharField(blank=True, max_length=255, default=u'course.xml') + courseware = models.CharField(blank=True, max_length=255, default='course.xml') # Language is deprecated and no longer used. Old rows exist that have # user-entered free form text values (ex. "English"), some of which have @@ -525,10 +524,10 @@ class UserProfile(models.Model): VALID_YEARS = list(range(this_year, this_year - 120, -1)) year_of_birth = models.IntegerField(blank=True, null=True, db_index=True) GENDER_CHOICES = ( - (u'm', ugettext_noop(u'Male')), - (u'f', ugettext_noop(u'Female')), + ('m', ugettext_noop('Male')), + ('f', ugettext_noop('Female')), # Translators: 'Other' refers to the student's gender - (u'o', ugettext_noop(u'Other/Prefer Not to Say')) + ('o', ugettext_noop('Other/Prefer Not to Say')) ) gender = models.CharField( blank=True, null=True, max_length=6, db_index=True, choices=GENDER_CHOICES @@ -539,17 +538,17 @@ class UserProfile(models.Model): # ('p_se', 'Doctorate in science or engineering'), # ('p_oth', 'Doctorate in another field'), LEVEL_OF_EDUCATION_CHOICES = ( - (u'p', ugettext_noop(u'Doctorate')), - (u'm', ugettext_noop(u"Master's or professional degree")), - (u'b', ugettext_noop(u"Bachelor's degree")), - (u'a', ugettext_noop(u"Associate degree")), - (u'hs', ugettext_noop(u"Secondary/high school")), - (u'jhs', ugettext_noop(u"Junior secondary/junior high/middle school")), - (u'el', ugettext_noop(u"Elementary/primary school")), + ('p', ugettext_noop('Doctorate')), + ('m', ugettext_noop("Master's or professional degree")), + ('b', ugettext_noop("Bachelor's degree")), + ('a', ugettext_noop("Associate degree")), + ('hs', ugettext_noop("Secondary/high school")), + ('jhs', ugettext_noop("Junior secondary/junior high/middle school")), + ('el', ugettext_noop("Elementary/primary school")), # Translators: 'None' refers to the student's level of education - (u'none', ugettext_noop(u"No formal education")), + ('none', ugettext_noop("No formal education")), # Translators: 'Other' refers to the student's level of education - (u'other', ugettext_noop(u"Other education")) + ('other', ugettext_noop("Other education")) ) level_of_education = models.CharField( blank=True, null=True, max_length=6, db_index=True, @@ -558,7 +557,7 @@ class UserProfile(models.Model): mailing_address = models.TextField(blank=True, null=True) city = models.TextField(blank=True, null=True) country = CountryField(blank=True, null=True) - COUNTRY_WITH_STATES = u'US' + COUNTRY_WITH_STATES = 'US' STATE_CHOICES = ( ('AL', 'Alabama'), ('AK', 'Alaska'), @@ -900,7 +899,7 @@ class Registration(models.Model): .. no_pii: """ - class Meta(object): + class Meta: db_table = "auth_registration" user = models.OneToOneField(User, on_delete=models.CASCADE) @@ -945,7 +944,7 @@ class PendingEmailChange(DeletableByUserValue, models.Model): """ user = models.OneToOneField(User, unique=True, db_index=True, on_delete=models.CASCADE) new_email = models.CharField(blank=True, max_length=255, db_index=True) - activation_key = models.CharField((u'activation key'), max_length=32, unique=True, db_index=True) + activation_key = models.CharField(('activation key'), max_length=32, unique=True, db_index=True) def request_change(self, email): """Request a change to a user's email. @@ -975,7 +974,7 @@ class PendingSecondaryEmailChange(DeletableByUserValue, models.Model): """ user = models.OneToOneField(User, unique=True, db_index=True, on_delete=models.CASCADE) new_secondary_email = models.CharField(blank=True, max_length=255, db_index=True) - activation_key = models.CharField((u'activation key'), max_length=32, unique=True, db_index=True) + activation_key = models.CharField(('activation key'), max_length=32, unique=True, db_index=True) EVENT_NAME_ENROLLMENT_ACTIVATED = 'edx.course.enrollment.activated' @@ -1072,7 +1071,7 @@ class LoginFailures(models.Model): def __str__(self): """Str -> Username: count - date.""" - return u'{username}: {count} - {date}'.format( + return '{username}: {count} - {date}'.format( username=self.user.username, count=self.failure_count, date=self.lockout_until.isoformat() if self.lockout_until else '-' @@ -1116,7 +1115,7 @@ class CourseEnrollmentManager(models.Manager): """ max_enrollments = settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS") - enrollment_number = super(CourseEnrollmentManager, self).get_queryset().filter( # lint-amnesty, pylint: disable=super-with-arguments + enrollment_number = super().get_queryset().filter( course_id=course_id, is_active=1 )[:max_enrollments + 1].count() @@ -1145,7 +1144,7 @@ class CourseEnrollmentManager(models.Manager): admins = CourseInstructorRole(course_locator).users_with_role() coaches = CourseCcxCoachRole(course_locator).users_with_role() - return super(CourseEnrollmentManager, self).get_queryset().filter( # lint-amnesty, pylint: disable=super-with-arguments + return super().get_queryset().filter( course_id=course_id, is_active=1, ).exclude(user__in=staff).exclude(user__in=admins).exclude(user__in=coaches).count() @@ -1189,7 +1188,7 @@ class CourseEnrollmentManager(models.Manager): """ # Unfortunately, Django's "group by"-style queries look super-awkward query = use_read_replica_if_available( - super(CourseEnrollmentManager, self).get_queryset().filter(course_id=course_id, is_active=True).values( # lint-amnesty, pylint: disable=super-with-arguments + super().get_queryset().filter(course_id=course_id, is_active=True).values( 'mode').order_by().annotate(Count('mode'))) total = 0 enroll_dict = defaultdict(int) @@ -1262,17 +1261,17 @@ class CourseEnrollment(models.Model): objects = CourseEnrollmentManager() # cache key format e.g enrollment...mode = 'honor' - COURSE_ENROLLMENT_CACHE_KEY = u"enrollment.{}.{}.mode" # TODO Can this be removed? It doesn't seem to be used. + COURSE_ENROLLMENT_CACHE_KEY = "enrollment.{}.{}.mode" # TODO Can this be removed? It doesn't seem to be used. - MODE_CACHE_NAMESPACE = u'CourseEnrollment.mode_and_active' + MODE_CACHE_NAMESPACE = 'CourseEnrollment.mode_and_active' - class Meta(object): + class Meta: unique_together = (('user', 'course'), ) indexes = [Index(fields=['user', '-created'])] ordering = ('user', 'course') def __init__(self, *args, **kwargs): - super(CourseEnrollment, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) # Private variable for storing course_overview to minimize calls to the database. # When the property .course_overview is accessed for the first time, this variable will be set. @@ -1284,8 +1283,9 @@ class CourseEnrollment(models.Model): ).format(self.user, self.course_id, self.created, self.is_active) def save(self, force_insert=False, force_update=False, using=None, update_fields=None): - super(CourseEnrollment, self).save(force_insert=force_insert, force_update=force_update, using=using, # lint-amnesty, pylint: disable=super-with-arguments - update_fields=update_fields) + super().save( + force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields + ) # Delete the cached status hash, forcing the value to be recalculated the next time it is needed. cache.delete(self.enrollment_status_hash_cache_key(self.user)) @@ -1477,12 +1477,12 @@ class CourseEnrollment(models.Model): assert isinstance(self.course_id, CourseKey) data = { 'user_id': self.user.id, - 'course_id': text_type(self.course_id), + 'course_id': str(self.course_id), 'mode': self.mode, } segment_properties = { 'category': 'conversion', - 'label': text_type(self.course_id), + 'label': str(self.course_id), 'org': self.course_id.org, 'course': self.course_id.course, 'run': self.course_id.run, @@ -1500,7 +1500,7 @@ class CourseEnrollment(models.Model): except Exception: # pylint: disable=broad-except if event_name and self.course_id: log.exception( - u'Unable to emit event %s for user %s and course %s', + 'Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id, @@ -1547,7 +1547,7 @@ class CourseEnrollment(models.Model): Also emits relevant events for analytics purposes. """ if mode is None: - mode = _default_course_mode(text_type(course_key)) + mode = _default_course_mode(str(course_key)) # All the server-side checks for whether a user is allowed to enroll. try: course = CourseOverview.get_from_id(course_key) @@ -1555,31 +1555,31 @@ class CourseEnrollment(models.Model): # This is here to preserve legacy behavior which allowed enrollment in courses # announced before the start of content creation. if check_access: - log.warning(u"User %s failed to enroll in non-existent course %s", user.username, text_type(course_key)) + log.warning("User %s failed to enroll in non-existent course %s", user.username, str(course_key)) raise NonExistentCourseError # lint-amnesty, pylint: disable=raise-missing-from if check_access: if cls.is_enrollment_closed(user, course) and not can_upgrade: log.warning( - u"User %s failed to enroll in course %s because enrollment is closed", + "User %s failed to enroll in course %s because enrollment is closed", user.username, - text_type(course_key) + str(course_key) ) raise EnrollmentClosedError if cls.objects.is_course_full(course): log.warning( - u"Course %s has reached its maximum enrollment of %d learners. User %s failed to enroll.", - text_type(course_key), + "Course %s has reached its maximum enrollment of %d learners. User %s failed to enroll.", + str(course_key), course.max_student_enrollments_allowed, user.username, ) raise CourseFullError if cls.is_enrolled(user, course_key): log.warning( - u"User %s attempted to enroll in %s, but they were already enrolled", + "User %s attempted to enroll in %s, but they were already enrolled", user.username, - text_type(course_key) + str(course_key) ) if check_access: raise AlreadyEnrolledError @@ -1624,7 +1624,7 @@ class CourseEnrollment(models.Model): user = User.objects.get(email=email) return cls.enroll(user, course_id, mode) except User.DoesNotExist: - err_msg = u"Tried to enroll email {} into course {}, but user not found" + err_msg = "Tried to enroll email {} into course {}, but user not found" log.error(err_msg.format(email, course_id)) if ignore_errors: return None @@ -1652,7 +1652,7 @@ class CourseEnrollment(models.Model): except cls.DoesNotExist: log.error( - u"Tried to unenroll student %s from %s but they were not enrolled", + "Tried to unenroll student %s from %s but they were not enrolled", user, course_id ) @@ -1674,7 +1674,7 @@ class CourseEnrollment(models.Model): return cls.unenroll(user, course_id) except User.DoesNotExist: log.error( - u"Tried to unenroll email %s from course %s, but user not found", + "Tried to unenroll email %s from course %s, but user not found", email, course_id ) @@ -1712,7 +1712,7 @@ class CourseEnrollment(models.Model): assert isinstance(course_id_partial, CourseKey) assert not course_id_partial.run # None or empty string course_key = CourseKey.from_string('/'.join([course_id_partial.org, course_id_partial.course, ''])) - querystring = text_type(course_key) + querystring = str(course_key) try: return cls.objects.filter( user=user, @@ -1796,7 +1796,7 @@ class CourseEnrollment(models.Model): if not status_hash: enrollments = cls.enrollments_for_user(user).values_list('course_id', 'mode') - enrollments = [(six.text_type(e[0]).lower(), e[1].lower()) for e in enrollments] + enrollments = [(str(e[0]).lower(), e[1].lower()) for e in enrollments] enrollments = sorted(enrollments, key=lambda e: e[0]) hash_elements = [user.username] hash_elements += ['{course_id}={mode}'.format(course_id=e[0], mode=e[1]) for e in enrollments] @@ -1900,7 +1900,7 @@ class CourseEnrollment(models.Model): date_placed = order['date_placed'] # also save the attribute so that we don't need to call ecommerce again. username = self.user.username - enrollment_attributes = get_enrollment_attributes(username, six.text_type(self.course_id)) + enrollment_attributes = get_enrollment_attributes(username, str(self.course_id)) enrollment_attributes.append( { "namespace": "order", @@ -1908,23 +1908,23 @@ class CourseEnrollment(models.Model): "value": date_placed, } ) - set_enrollment_attributes(username, six.text_type(self.course_id), enrollment_attributes) + set_enrollment_attributes(username, str(self.course_id), enrollment_attributes) except HttpClientError: log.warning( - u"Encountered HttpClientError while getting order details from ecommerce. " - u"Order={number} and user {user}".format(number=order_number, user=self.user.id)) + "Encountered HttpClientError while getting order details from ecommerce. " + "Order={number} and user {user}".format(number=order_number, user=self.user.id)) return None except HttpServerError: log.warning( - u"Encountered HttpServerError while getting order details from ecommerce. " - u"Order={number} and user {user}".format(number=order_number, user=self.user.id)) + "Encountered HttpServerError while getting order details from ecommerce. " + "Order={number} and user {user}".format(number=order_number, user=self.user.id)) return None except SlumberBaseException: log.warning( - u"Encountered an error while getting order details from ecommerce. " - u"Order={number} and user {user}".format(number=order_number, user=self.user.id)) + "Encountered an error while getting order details from ecommerce. " + "Order={number} and user {user}".format(number=order_number, user=self.user.id)) return None refund_window_start_date = max( @@ -1944,7 +1944,7 @@ class CourseEnrollment(models.Model): # If there are multiple attributes then return the last one. enrollment_id = self.get_enrollment(self.user, self.course_id).id log.warning( - u"Multiple CourseEnrollmentAttributes found for user %s with enrollment-ID %s", + "Multiple CourseEnrollmentAttributes found for user %s with enrollment-ID %s", self.user.id, enrollment_id ) @@ -1974,7 +1974,7 @@ class CourseEnrollment(models.Model): log.info('Course Overviews: unable to find course overview for enrollment, loading from modulestore.') try: self._course_overview = CourseOverview.get_from_id(self.course_id) - except (CourseOverview.DoesNotExist, IOError): + except (CourseOverview.DoesNotExist, OSError): self._course_overview = None return self._course_overview @@ -2120,7 +2120,7 @@ class CourseEnrollment(models.Model): Returns: Unicode cache key """ - return cls.COURSE_ENROLLMENT_CACHE_KEY.format(user_id, text_type(course_key)) + return cls.COURSE_ENROLLMENT_CACHE_KEY.format(user_id, str(course_key)) @classmethod def _get_enrollment_state(cls, user, course_key): @@ -2203,7 +2203,7 @@ class FBEEnrollmentExclusion(models.Model): ) def __str__(self): - return "[FBEEnrollmentExclusion] %s" % (self.enrollment,) + return f"[FBEEnrollmentExclusion] {self.enrollment}" @receiver(models.signals.post_save, sender=CourseEnrollment) @@ -2215,7 +2215,7 @@ def invalidate_enrollment_mode_cache(sender, instance, **kwargs): # pylint: dis cache_key = CourseEnrollment.cache_key_name( instance.user.id, - text_type(instance.course_id) + str(instance.course_id) ) cache.delete(cache_key) @@ -2332,11 +2332,11 @@ class CourseEnrollmentAllowed(DeletableByUserValue, models.Model): created = models.DateTimeField(auto_now_add=True, null=True, db_index=True) - class Meta(object): + class Meta: unique_together = (('email', 'course_id'),) def __str__(self): - return "[CourseEnrollmentAllowed] %s: %s (%s)" % (self.email, self.course_id, self.created) + return f"[CourseEnrollmentAllowed] {self.email}: {self.course_id} ({self.created})" @classmethod def for_user(cls, user): @@ -2387,7 +2387,7 @@ class CourseAccessRole(models.Model): course_id = CourseKeyField(max_length=255, db_index=True, blank=True) role = models.CharField(max_length=64, db_index=True) - class Meta(object): + class Meta: unique_together = ('user', 'org', 'course_id', 'role') @property @@ -2415,14 +2415,14 @@ class CourseAccessRole(models.Model): return self._key < other._key def __str__(self): - return "[CourseAccessRole] user: {} role: {} org: {} course: {}".format(self.user.username, self.role, self.org, self.course_id) # lint-amnesty, pylint: disable=line-too-long + return f"[CourseAccessRole] user: {self.user.username} role: {self.role} org: {self.org} course: {self.course_id}" # lint-amnesty, pylint: disable=line-too-long #### Helper methods for use from python manage.py shell and other classes. def strip_if_string(value): - if isinstance(value, six.string_types): + if isinstance(value, str): return value.strip() return value @@ -2538,7 +2538,7 @@ def create_comments_service_user(user): # lint-amnesty, pylint: disable=missing except Exception: # pylint: disable=broad-except log = logging.getLogger("edx.discussion") # pylint: disable=redefined-outer-name log.error( - "Could not create comments service user with id {}".format(user.id), + f"Could not create comments service user with id {user.id}", exc_info=True ) @@ -2552,9 +2552,9 @@ def create_comments_service_user(user): # lint-amnesty, pylint: disable=missing def log_successful_login(sender, request, user, **kwargs): # lint-amnesty, pylint: disable=unused-argument """Handler to log when logins have occurred successfully.""" if settings.FEATURES['SQUELCH_PII_IN_LOGS']: - AUDIT_LOG.info(u"Login success - user.id: {0}".format(user.id)) + AUDIT_LOG.info(f"Login success - user.id: {user.id}") else: - AUDIT_LOG.info(u"Login success - {0} ({1})".format(user.username, user.email)) + AUDIT_LOG.info(f"Login success - {user.username} ({user.email})") @receiver(user_logged_out) @@ -2562,9 +2562,9 @@ def log_successful_logout(sender, request, user, **kwargs): # lint-amnesty, pyl """Handler to log when logouts have occurred successfully.""" if hasattr(request, 'user'): if settings.FEATURES['SQUELCH_PII_IN_LOGS']: - AUDIT_LOG.info('Logout - user.id: {0}'.format(request.user.id)) # pylint: disable=logging-format-interpolation + AUDIT_LOG.info(f'Logout - user.id: {request.user.id}') # pylint: disable=logging-format-interpolation else: - AUDIT_LOG.info('Logout - {0}'.format(request.user)) # pylint: disable=logging-format-interpolation + AUDIT_LOG.info(f'Logout - {request.user}') # pylint: disable=logging-format-interpolation if request.user.id: segment.track(request.user.id, 'edx.bi.user.account.logout') @@ -2604,7 +2604,7 @@ class DashboardConfiguration(ConfigurationModel): """ recent_enrollment_time_delta = models.PositiveIntegerField( default=0, - help_text=u"The number of seconds in which a new enrollment is considered 'recent'. " + help_text="The number of seconds in which a new enrollment is considered 'recent'. " "Used to display notifications." ) @@ -2735,11 +2735,11 @@ class EntranceExamConfiguration(models.Model): # for the course skip_entrance_exam = models.BooleanField(default=True) - class Meta(object): + class Meta: unique_together = (('user', 'course_id'), ) def __str__(self): - return "[EntranceExamConfiguration] %s: %s (%s) = %s" % ( + return "[EntranceExamConfiguration] {}: {} ({}) = {}".format( self.user, self.course_id, self.created, self.skip_entrance_exam ) @@ -2773,7 +2773,7 @@ class LanguageField(models.CharField): 'help_text', _("The ISO 639-1 language code for this language."), ) - super(LanguageField, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( max_length=16, choices=settings.ALL_LANGUAGES, help_text=help_text, @@ -2794,7 +2794,7 @@ class LanguageProficiency(models.Model): .. no_pii: Language is not PII value according to OEP-30. """ - class Meta(object): + class Meta: unique_together = (('code', 'user_profile'),) user_profile = models.ForeignKey(UserProfile, db_index=True, related_name='language_proficiencies', @@ -2849,7 +2849,7 @@ class CourseEnrollmentAttribute(models.Model): def __str__(self): """Unicode representation of the attribute. """ - return u"{namespace}:{name}, {value}".format( + return "{namespace}:{name}, {value}".format( namespace=self.namespace, name=self.name, value=self.value, @@ -2953,7 +2953,7 @@ class RegistrationCookieConfiguration(ConfigurationModel): def __str__(self): """Unicode representation of this config. """ - return u"UTM: {utm_name}; AFFILIATE: {affiliate_name}".format( + return "UTM: {utm_name}; AFFILIATE: {affiliate_name}".format( utm_name=self.utm_cookie_name, affiliate_name=self.affiliate_cookie_name ) @@ -2964,8 +2964,8 @@ class BulkUnenrollConfiguration(ConfigurationModel): # lint-amnesty, pylint: di """ csv_file = models.FileField( - validators=[FileExtensionValidator(allowed_extensions=[u'csv'])], - help_text=_(u"It expect that the data will be provided in a csv file format with \ + validators=[FileExtensionValidator(allowed_extensions=['csv'])], + help_text=_("It expect that the data will be provided in a csv file format with \ first row being the header and columns will be as follows: \ user_id, username, email, course_id, is_verified, verification_date") ) @@ -2976,8 +2976,8 @@ class BulkChangeEnrollmentConfiguration(ConfigurationModel): config model for the bulk_change_enrollment_csv command """ csv_file = models.FileField( - validators=[FileExtensionValidator(allowed_extensions=[u'csv'])], - help_text=_(u"It expect that the data will be provided in a csv file format with \ + validators=[FileExtensionValidator(allowed_extensions=['csv'])], + help_text=_("It expect that the data will be provided in a csv file format with \ first row being the header and columns will be as follows: \ course_id, username, mode") ) @@ -2991,7 +2991,7 @@ class UserAttribute(TimeStampedModel): .. no_pii: """ - class Meta(object): + class Meta: # Ensure that at most one value exists for a given user/name. unique_together = (('user', 'name',), ) @@ -3043,13 +3043,13 @@ class AccountRecoveryManager(models.Manager): AccountRecovery: AccountRecovery object with is_active=true """ filters['is_active'] = True - return super(AccountRecoveryManager, self).get_queryset().get(**filters) # lint-amnesty, pylint: disable=super-with-arguments + return super().get_queryset().get(**filters) def activate(self): """ Set is_active flag to True. """ - super(AccountRecoveryManager, self).get_queryset().update(is_active=True) # lint-amnesty, pylint: disable=super-with-arguments + super().get_queryset().update(is_active=True) class AccountRecovery(models.Model): @@ -3070,7 +3070,7 @@ class AccountRecovery(models.Model): ) is_active = models.BooleanField(default=False) - class Meta(object): + class Meta: db_table = "auth_accountrecovery" objects = AccountRecoveryManager() @@ -3122,8 +3122,8 @@ class AccountRecoveryConfiguration(ConfigurationModel): configuration model for recover account management command """ csv_file = models.FileField( - validators=[FileExtensionValidator(allowed_extensions=[u'csv'])], - help_text=_(u"It expect that the data will be provided in a csv file format with \ + validators=[FileExtensionValidator(allowed_extensions=['csv'])], + help_text=_("It expect that the data will be provided in a csv file format with \ first row being the header and columns will be as follows: \ username, current_email, desired_email") ) diff --git a/common/djangoapps/student/roles.py b/common/djangoapps/student/roles.py index b7e2372b5c..e936277562 100644 --- a/common/djangoapps/student/roles.py +++ b/common/djangoapps/student/roles.py @@ -33,13 +33,13 @@ def register_access_role(cls): role_name = cls.ROLE REGISTERED_ACCESS_ROLES[role_name] = cls except AttributeError: - log.exception(u"Unable to register Access Role with attribute 'ROLE'.") + log.exception("Unable to register Access Role with attribute 'ROLE'.") return cls -class BulkRoleCache(object): # lint-amnesty, pylint: disable=missing-class-docstring - CACHE_NAMESPACE = u"student.roles.BulkRoleCache" - CACHE_KEY = u'roles_by_user' +class BulkRoleCache: # lint-amnesty, pylint: disable=missing-class-docstring + CACHE_NAMESPACE = "student.roles.BulkRoleCache" + CACHE_KEY = 'roles_by_user' @classmethod def prefetch(cls, users): # lint-amnesty, pylint: disable=missing-function-docstring @@ -58,7 +58,7 @@ class BulkRoleCache(object): # lint-amnesty, pylint: disable=missing-class-docs return get_cache(cls.CACHE_NAMESPACE)[cls.CACHE_KEY][user.id] -class RoleCache(object): +class RoleCache: """ A cache of the CourseAccessRoles held by a particular user """ @@ -82,7 +82,7 @@ class RoleCache(object): ) -class AccessRole(six.with_metaclass(ABCMeta, object)): +class AccessRole(metaclass=ABCMeta): """ Object representing a role with particular access to a resource """ @@ -150,7 +150,7 @@ class RoleBase(AccessRole): an org. Provide org and course if constrained to a course. Although, you should use the subclasses for all of these. """ - super(RoleBase, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() self.org = org self.course_key = course_key @@ -229,14 +229,14 @@ class CourseRole(RoleBase): Args: course_key (CourseKey) """ - super(CourseRole, self).__init__(role, course_key.org, course_key) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(role, course_key.org, course_key) @classmethod def course_group_already_exists(self, course_key): # lint-amnesty, pylint: disable=bad-classmethod-argument return CourseAccessRole.objects.filter(org=course_key.org, course_id=course_key).exists() def __repr__(self): - return '<{}: course_key={}>'.format(self.__class__.__name__, self.course_key) + return f'<{self.__class__.__name__}: course_key={self.course_key}>' class OrgRole(RoleBase): @@ -244,7 +244,7 @@ class OrgRole(RoleBase): A named role in a particular org independent of course """ def __repr__(self): - return '<{}>'.format(self.__class__.__name__) + return f'<{self.__class__.__name__}>' @register_access_role @@ -253,7 +253,7 @@ class CourseStaffRole(CourseRole): ROLE = 'staff' def __init__(self, *args, **kwargs): - super(CourseStaffRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -262,7 +262,7 @@ class CourseInstructorRole(CourseRole): ROLE = 'instructor' def __init__(self, *args, **kwargs): - super(CourseInstructorRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -271,7 +271,7 @@ class CourseFinanceAdminRole(CourseRole): ROLE = 'finance_admin' def __init__(self, *args, **kwargs): - super(CourseFinanceAdminRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -280,7 +280,7 @@ class CourseSalesAdminRole(CourseRole): ROLE = 'sales_admin' def __init__(self, *args, **kwargs): - super(CourseSalesAdminRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -289,7 +289,7 @@ class CourseBetaTesterRole(CourseRole): ROLE = 'beta_testers' def __init__(self, *args, **kwargs): - super(CourseBetaTesterRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -301,7 +301,7 @@ class LibraryUserRole(CourseRole): ROLE = 'library_user' def __init__(self, *args, **kwargs): - super(LibraryUserRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) class CourseCcxCoachRole(CourseRole): @@ -309,7 +309,7 @@ class CourseCcxCoachRole(CourseRole): ROLE = 'ccx_coach' def __init__(self, *args, **kwargs): - super(CourseCcxCoachRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -318,19 +318,19 @@ class CourseDataResearcherRole(CourseRole): ROLE = 'data_researcher' def __init__(self, *args, **kwargs): - super(CourseDataResearcherRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) class OrgStaffRole(OrgRole): """An organization staff member""" def __init__(self, *args, **kwargs): - super(OrgStaffRole, self).__init__('staff', *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__('staff', *args, **kwargs) class OrgInstructorRole(OrgRole): """An organization instructor""" def __init__(self, *args, **kwargs): - super(OrgInstructorRole, self).__init__('instructor', *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__('instructor', *args, **kwargs) class OrgLibraryUserRole(OrgRole): @@ -341,7 +341,7 @@ class OrgLibraryUserRole(OrgRole): ROLE = LibraryUserRole.ROLE def __init__(self, *args, **kwargs): - super(OrgLibraryUserRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) class OrgDataResearcherRole(OrgRole): @@ -349,7 +349,7 @@ class OrgDataResearcherRole(OrgRole): ROLE = 'data_researcher' def __init__(self, *args, **kwargs): - super(OrgDataResearcherRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -361,7 +361,7 @@ class CourseCreatorRole(RoleBase): ROLE = "course_creator_group" def __init__(self, *args, **kwargs): - super(CourseCreatorRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) @register_access_role @@ -372,10 +372,10 @@ class SupportStaffRole(RoleBase): ROLE = "support" def __init__(self, *args, **kwargs): - super(SupportStaffRole, self).__init__(self.ROLE, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(self.ROLE, *args, **kwargs) -class UserBasedRole(object): +class UserBasedRole: """ Backward mapping: given a user, manipulate the courses and roles """ diff --git a/common/djangoapps/student/tests/factories.py b/common/djangoapps/student/tests/factories.py index 91a15121ab..5f404c1e96 100644 --- a/common/djangoapps/student/tests/factories.py +++ b/common/djangoapps/student/tests/factories.py @@ -33,15 +33,15 @@ TEST_PASSWORD = 'test' class GroupFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = Group django_get_or_create = ('name', ) - name = factory.Sequence(u'group{0}'.format) + name = factory.Sequence('group{}'.format) class UserStandingFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = UserStanding user = None @@ -50,38 +50,38 @@ class UserStandingFactory(DjangoModelFactory): # lint-amnesty, pylint: disable= class UserProfileFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = UserProfile django_get_or_create = ('user', ) user = None - name = factory.LazyAttribute(u'{0.user.first_name} {0.user.last_name}'.format) + name = factory.LazyAttribute('{0.user.first_name} {0.user.last_name}'.format) level_of_education = None - gender = u'm' + gender = 'm' mailing_address = None - goals = u'Learn a lot' + goals = 'Learn a lot' allow_certificate = True class RegistrationFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = Registration user = None - activation_key = six.text_type(uuid4().hex) + activation_key = str(uuid4().hex) class UserFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = User django_get_or_create = ('email', 'username') _DEFAULT_PASSWORD = 'test' - username = factory.Sequence(u'robot{0}'.format) - email = factory.Sequence(u'robot+test+{0}@edx.org'.format) + username = factory.Sequence('robot{}'.format) + email = factory.Sequence('robot+test+{}@edx.org'.format) password = factory.PostGenerationMethodCall('set_password', _DEFAULT_PASSWORD) - first_name = factory.Sequence(u'Robot{0}'.format) + first_name = factory.Sequence('Robot{}'.format) last_name = 'Test' is_staff = False is_active = True @@ -104,7 +104,7 @@ class UserFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing- if extracted is None: return - if isinstance(extracted, six.string_types): + if isinstance(extracted, str): extracted = [extracted] for group_name in extracted: @@ -112,7 +112,7 @@ class UserFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing- class AnonymousUserFactory(factory.Factory): - class Meta(object): + class Meta: model = AnonymousUser @@ -125,7 +125,7 @@ class SuperuserFactory(UserFactory): class CourseEnrollmentFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = CourseEnrollment user = factory.SubFactory(UserFactory) @@ -147,7 +147,7 @@ class CourseEnrollmentFactory(DjangoModelFactory): # lint-amnesty, pylint: disa # foreign key constraint to CourseEnrollment. del kwargs['course_id'] - if isinstance(course_id, six.string_types): + if isinstance(course_id, str): course_id = CourseKey.from_string(course_id) course_kwargs.setdefault('id', course_id) @@ -174,7 +174,7 @@ class CourseEnrollmentCelebrationFactory(DjangoModelFactory): class CourseAccessRoleFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = CourseAccessRole user = factory.SubFactory(UserFactory) @@ -183,7 +183,7 @@ class CourseAccessRoleFactory(DjangoModelFactory): # lint-amnesty, pylint: disa class CourseEnrollmentAllowedFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = CourseEnrollmentAllowed email = 'test@edx.org' @@ -197,23 +197,23 @@ class PendingEmailChangeFactory(DjangoModelFactory): new_email: sequence of new+email+{}@edx.org activation_key: sequence of integers, padded to 30 characters """ - class Meta(object): + class Meta: model = PendingEmailChange user = factory.SubFactory(UserFactory) - new_email = factory.Sequence(u'new+email+{0}@edx.org'.format) - activation_key = factory.Sequence(u'{:0<30d}'.format) + new_email = factory.Sequence('new+email+{}@edx.org'.format) + activation_key = factory.Sequence('{:0<30d}'.format) class ContentTypeFactory(DjangoModelFactory): - class Meta(object): + class Meta: model = ContentType app_label = factory.Faker('app_name') class PermissionFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = Permission codename = factory.Faker('codename') @@ -221,10 +221,10 @@ class PermissionFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=mi class AccountRecoveryFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = AccountRecovery django_get_or_create = ('user',) user = None - secondary_email = factory.Sequence(u'robot+test+recovery+{0}@edx.org'.format) + secondary_email = factory.Sequence('robot+test+recovery+{}@edx.org'.format) is_active = True diff --git a/common/djangoapps/student/tests/test_activate_account.py b/common/djangoapps/student/tests/test_activate_account.py index ddad694912..d9795d7ecb 100644 --- a/common/djangoapps/student/tests/test_activate_account.py +++ b/common/djangoapps/student/tests/test_activate_account.py @@ -2,21 +2,20 @@ import unittest -from uuid import uuid4 from datetime import datetime +from unittest.mock import patch +from uuid import uuid4 from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.test import TestCase, override_settings from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_flag -from mock import patch -from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers -from openedx.core.djangoapps.user_authn.toggles import REDIRECT_TO_AUTHN_MICROFRONTEND from common.djangoapps.student.models import Registration from common.djangoapps.student.tests.factories import UserFactory - +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers +from openedx.core.djangoapps.user_authn.toggles import REDIRECT_TO_AUTHN_MICROFRONTEND FEATURES_WITH_AUTHN_MFE_ENABLED = settings.FEATURES.copy() FEATURES_WITH_AUTHN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True @@ -27,7 +26,7 @@ class TestActivateAccount(TestCase): """Tests for account creation""" def setUp(self): - super(TestActivateAccount, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.username = "jack" self.email = "jack@fake.edx.org" self.password = "test-password" @@ -108,8 +107,8 @@ class TestActivateAccount(TestCase): # Log in with test user. self.login() expected_message = ( - u"Check your {email_start}{email}{email_end} inbox for an account activation link from " - u"{platform_name}. If you need help, contact {link_start}{platform_name} Support{link_end}." + "Check your {email_start}{email}{email_end} inbox for an account activation link from " + "{platform_name}. If you need help, contact {link_start}{platform_name} Support{link_end}." ).format( platform_name=self.platform_name, email_start="", diff --git a/common/djangoapps/student/tests/test_admin_views.py b/common/djangoapps/student/tests/test_admin_views.py index c03cdf840e..4b5a351b78 100644 --- a/common/djangoapps/student/tests/test_admin_views.py +++ b/common/djangoapps/student/tests/test_admin_views.py @@ -1,10 +1,10 @@ -# coding=UTF-8 """ Tests student admin.py """ import datetime +from unittest.mock import Mock import ddt import pytest @@ -16,17 +16,20 @@ from django.test import TestCase, override_settings from django.urls import reverse from django.utils.timezone import now from edx_toggles.toggles.testutils import override_waffle_switch -from mock import Mock from pytz import UTC -from common.djangoapps.student.admin import AllowedAuthUserForm, COURSE_ENROLLMENT_ADMIN_SWITCH, UserAdmin, CourseEnrollmentForm # lint-amnesty, pylint: disable=line-too-long +from common.djangoapps.student.admin import ( # lint-amnesty, pylint: disable=line-too-long + COURSE_ENROLLMENT_ADMIN_SWITCH, + AllowedAuthUserForm, + CourseEnrollmentForm, + UserAdmin +) from common.djangoapps.student.models import AllowedAuthUser, CourseEnrollment, LoginFailures from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase -from xmodule.modulestore.tests.factories import CourseFactory - from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory class AdminCourseRolesPageTest(SharedModuleStoreTestCase): @@ -34,18 +37,18 @@ class AdminCourseRolesPageTest(SharedModuleStoreTestCase): """ @classmethod def setUpClass(cls): - super(AdminCourseRolesPageTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create(org='edx') def setUp(self): - super(AdminCourseRolesPageTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(is_staff=True, is_superuser=True) self.user.save() def test_save_valid_data(self): data = { - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'role': 'finance_admin', 'org': 'edx', 'email': self.user.email @@ -61,7 +64,7 @@ class AdminCourseRolesPageTest(SharedModuleStoreTestCase): self.assertContains(response, 'Select course access role to change') self.assertContains(response, 'Add course access role') self.assertContains(response, 'finance_admin') - self.assertContains(response, six.text_type(self.course.id)) + self.assertContains(response, str(self.course.id)) self.assertContains(response, '1 course access role') #try adding with same information raise error. @@ -73,7 +76,7 @@ class AdminCourseRolesPageTest(SharedModuleStoreTestCase): data = { 'role': 'staff', 'email': self.user.email, - 'course_id': six.text_type(self.course.id) + 'course_id': str(self.course.id) } self.client.login(username=self.user.username, password='test') @@ -125,7 +128,7 @@ class AdminCourseRolesPageTest(SharedModuleStoreTestCase): def test_save_with_invalid_course(self): - course = six.text_type('no/edx/course') + course = 'no/edx/course' email = "invalid@email.com" data = { 'course_id': course, @@ -155,7 +158,7 @@ class AdminCourseRolesPageTest(SharedModuleStoreTestCase): def test_save_valid_course_invalid_org(self): data = { - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'role': 'finance_admin', 'org': 'edxxx', 'email': self.user.email @@ -178,7 +181,7 @@ class AdminUserPageTest(TestCase): Unit tests for the UserAdmin view. """ def setUp(self): - super(AdminUserPageTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.admin = UserAdmin(User, AdminSite()) def test_username_is_writable_for_user_creation(self): @@ -221,7 +224,7 @@ class CourseEnrollmentAdminTest(SharedModuleStoreTestCase): ) def setUp(self): - super(CourseEnrollmentAdminTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(is_staff=True, is_superuser=True) self.course = CourseFactory() self.course_enrollment = CourseEnrollmentFactory( @@ -253,7 +256,7 @@ class CourseEnrollmentAdminTest(SharedModuleStoreTestCase): """ Ensure that course enrollment searches return exact matches on username first. """ - user2 = UserFactory.create(username='aaa_{}'.format(self.user.username)) + user2 = UserFactory.create(username=f'aaa_{self.user.username}') CourseEnrollmentFactory( user=user2, course_id=self.course.id, # pylint: disable=no-member @@ -279,8 +282,8 @@ class CourseEnrollmentAdminTest(SharedModuleStoreTestCase): # is_active will change from True to False assert self.course_enrollment.is_active data = { - 'user': six.text_type(self.course_enrollment.user.id), - 'course': six.text_type(self.course_enrollment.course.id), + 'user': str(self.course_enrollment.user.id), + 'course': str(self.course_enrollment.course.id), 'is_active': 'false', 'mode': self.course_enrollment.mode, } @@ -300,7 +303,7 @@ class CourseEnrollmentAdminTest(SharedModuleStoreTestCase): Send an invalid course ID instead of "org.0/course_0/Run_0" when saving, and verify that it fails. """ data = { - 'user': six.text_type(self.course_enrollment.user.id), + 'user': str(self.course_enrollment.user.id), 'course': 'invalid-course-id', 'is_active': 'true', 'mode': self.course_enrollment.mode, @@ -321,22 +324,22 @@ class LoginFailuresAdminTest(TestCase): @classmethod def setUpClass(cls): """Setup class""" - super(LoginFailuresAdminTest, cls).setUpClass() - cls.user = UserFactory.create(username=u'§', is_staff=True, is_superuser=True) + super().setUpClass() + cls.user = UserFactory.create(username='§', is_staff=True, is_superuser=True) cls.user.save() def setUp(self): """Setup.""" - super(LoginFailuresAdminTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.client.login(username=self.user.username, password='test') - self.user2 = UserFactory.create(username=u'Zażółć gęślą jaźń') + self.user2 = UserFactory.create(username='Zażółć gęślą jaźń') self.user_lockout_until = datetime.datetime.now(UTC) LoginFailures.objects.create(user=self.user, failure_count=10, lockout_until=self.user_lockout_until) LoginFailures.objects.create(user=self.user2, failure_count=2) def tearDown(self): """Tear Down.""" - super(LoginFailuresAdminTest, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() LoginFailures.objects.all().delete() def test_unicode_username(self): @@ -374,7 +377,7 @@ class LoginFailuresAdminTest(TestCase): url, data={ 'action': 'unlock_student_accounts', - '_selected_action': [six.text_type(o.pk) for o in LoginFailures.objects.all()] + '_selected_action': [str(o.pk) for o in LoginFailures.objects.all()] }, follow=True ) @@ -400,11 +403,11 @@ class CourseEnrollmentAdminFormTest(SharedModuleStoreTestCase): """ @classmethod def setUpClass(cls): - super(CourseEnrollmentAdminFormTest, cls).setUpClass() + super().setUpClass() cls.course = CourseOverviewFactory(start=now()) def setUp(self): - super(CourseEnrollmentAdminFormTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() def test_admin_model_form_create(self): @@ -415,7 +418,7 @@ class CourseEnrollmentAdminFormTest(SharedModuleStoreTestCase): form = CourseEnrollmentForm({ 'user': self.user.id, - 'course': six.text_type(self.course.id), + 'course': str(self.course.id), 'is_active': True, 'mode': 'audit', }) @@ -432,7 +435,7 @@ class CourseEnrollmentAdminFormTest(SharedModuleStoreTestCase): count = CourseEnrollment.objects.count() form = CourseEnrollmentForm({ 'user': self.user.id, - 'course': six.text_type(self.course.id), + 'course': str(self.course.id), 'is_active': False, 'mode': 'audit'}, instance=enrollment @@ -450,11 +453,11 @@ class AllowedAuthUserFormTest(SiteMixin, TestCase): """ @classmethod def setUpClass(cls): - super(AllowedAuthUserFormTest, cls).setUpClass() + super().setUpClass() cls.email_domain_name = "dummy.com" cls.email_with_wrong_domain = "dummy@example.com" - cls.valid_email = "dummy@{email_domain_name}".format(email_domain_name=cls.email_domain_name) - cls.other_valid_email = "dummy1@{email_domain_name}".format(email_domain_name=cls.email_domain_name) + cls.valid_email = f"dummy@{cls.email_domain_name}" + cls.other_valid_email = f"dummy1@{cls.email_domain_name}" UserFactory(email=cls.valid_email) UserFactory(email=cls.email_with_wrong_domain) diff --git a/common/djangoapps/student/tests/test_authz.py b/common/djangoapps/student/tests/test_authz.py index 16da5eff8e..4bd1587f55 100644 --- a/common/djangoapps/student/tests/test_authz.py +++ b/common/djangoapps/student/tests/test_authz.py @@ -2,7 +2,7 @@ Tests authz.py """ -import mock +from unittest import mock import pytest from ccx_keys.locator import CCXLocator @@ -23,7 +23,7 @@ class CreatorGroupTest(TestCase): def setUp(self): """ Test case setup """ - super(CreatorGroupTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = User.objects.create_user('testuser', 'test+courses@edx.org', 'foo') self.admin = User.objects.create_user('Mark', 'admin+courses@edx.org', 'foo') self.admin.is_staff = True @@ -151,7 +151,7 @@ class CCXCourseGroupTest(TestCase): """ Set up test variables """ - super(CCXCourseGroupTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.global_admin = AdminFactory() self.staff = User.objects.create_user('teststaff', 'teststaff+courses@edx.org', 'foo') self.ccx_course_key = CCXLocator.from_string('ccx-v1:edX+DemoX+Demo_Course+ccx@1') @@ -189,7 +189,7 @@ class CourseGroupTest(TestCase): def setUp(self): """ Test case setup """ - super(CourseGroupTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.global_admin = AdminFactory() self.creator = User.objects.create_user('testcreator', 'testcreator+courses@edx.org', 'foo') self.staff = User.objects.create_user('teststaff', 'teststaff+courses@edx.org', 'foo') diff --git a/common/djangoapps/student/tests/test_bulk_email_settings.py b/common/djangoapps/student/tests/test_bulk_email_settings.py index 79b900846b..60220dfb6f 100644 --- a/common/djangoapps/student/tests/test_bulk_email_settings.py +++ b/common/djangoapps/student/tests/test_bulk_email_settings.py @@ -27,11 +27,11 @@ class TestStudentDashboardEmailView(SharedModuleStoreTestCase): """ @classmethod def setUpClass(cls): - super(TestStudentDashboardEmailView, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): - super(TestStudentDashboardEmailView, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Create student account student = UserFactory.create() @@ -51,7 +51,7 @@ class TestStudentDashboardEmailView(SharedModuleStoreTestCase): ) def tearDown(self): - super(TestStudentDashboardEmailView, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() BulkEmailFlag.objects.all().delete() def test_email_flag_true(self): diff --git a/common/djangoapps/student/tests/test_certificates.py b/common/djangoapps/student/tests/test_certificates.py index 2ee6bd0efd..af388b8cfb 100644 --- a/common/djangoapps/student/tests/test_certificates.py +++ b/common/djangoapps/student/tests/test_certificates.py @@ -3,21 +3,22 @@ import datetime import unittest +from unittest.mock import patch import ddt from django.conf import settings from django.test.utils import override_settings from django.urls import reverse -from mock import patch from pytz import UTC from common.djangoapps.course_modes.models import CourseMode +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from lms.djangoapps.certificates.api import get_certificate_url from lms.djangoapps.certificates.models import CertificateStatuses from lms.djangoapps.certificates.tests.factories import ( - GeneratedCertificateFactory, LinkedInAddToProfileConfigurationFactory + GeneratedCertificateFactory, + LinkedInAddToProfileConfigurationFactory ) -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -37,7 +38,7 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(CertificateDisplayTestBase, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory() cls.course.certificates_display_behavior = "early_with_info" @@ -45,7 +46,7 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): cls.store.update_item(cls.course, cls.USERNAME) def setUp(self): - super(CertificateDisplayTestBase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD) result = self.client.login(username=self.USERNAME, password=self.PASSWORD) assert result, 'Could not log in' @@ -56,9 +57,9 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): """ response = self.client.get(reverse('dashboard')) if is_visible: - self.assertContains(response, u'Add Certificate to LinkedIn Profile') + self.assertContains(response, 'Add Certificate to LinkedIn Profile') else: - self.assertNotContains(response, u'Add Certificate to LinkedIn Profile') + self.assertNotContains(response, 'Add Certificate to LinkedIn Profile') def _create_certificate(self, enrollment_mode, download_url=DOWNLOAD_URL): """Simulate that the user has a generated certificate. """ @@ -80,7 +81,7 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): Inspect the dashboard to see if a certificate can be downloaded. """ response = self.client.get(reverse('dashboard')) - self.assertContains(response, u'Download Your ID Verified') + self.assertContains(response, 'Download Your ID Verified') self.assertContains(response, self.DOWNLOAD_URL) def _check_can_download_certificate_no_id(self): @@ -89,8 +90,8 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): is present """ response = self.client.get(reverse('dashboard')) - self.assertContains(response, u'Download') - self.assertContains(response, u'(PDF)') + self.assertContains(response, 'Download') + self.assertContains(response, '(PDF)') self.assertContains(response, self.DOWNLOAD_URL) def _check_can_not_download_certificate(self): @@ -98,9 +99,9 @@ class CertificateDisplayTestBase(SharedModuleStoreTestCase): Make sure response does not have any of the download certificate buttons """ response = self.client.get(reverse('dashboard')) - self.assertNotContains(response, u'View Test_Certificate') - self.assertNotContains(response, u'Download Your Test_Certificate (PDF)') - self.assertNotContains(response, u'Download Test_Certificate (PDF)') + self.assertNotContains(response, 'View Test_Certificate') + self.assertNotContains(response, 'Download Your Test_Certificate (PDF)') + self.assertNotContains(response, 'Download Test_Certificate (PDF)') self.assertNotContains(response, self.DOWNLOAD_URL) @@ -115,7 +116,7 @@ class CertificateDashboardMessageDisplayTest(CertificateDisplayTestBase): @classmethod def setUpClass(cls): - super(CertificateDashboardMessageDisplayTest, cls).setUpClass() + super().setUpClass() cls.course.certificates_display_behavior = "end" cls.course.save() cls.store.update_item(cls.course, cls.USERNAME) @@ -124,11 +125,11 @@ class CertificateDashboardMessageDisplayTest(CertificateDisplayTestBase): response = self.client.get(reverse('dashboard')) if certificate_available_date is None: - self.assertNotContains(response, u"Your certificate will be available on") - self.assertNotContains(response, u"View Test_Certificate") + self.assertNotContains(response, "Your certificate will be available on") + self.assertNotContains(response, "View Test_Certificate") elif datetime.datetime.now(UTC) < certificate_available_date: - self.assertContains(response, u"Your certificate will be available on") - self.assertNotContains(response, u"View Test_Certificate") + self.assertContains(response, "Your certificate will be available on") + self.assertNotContains(response, "View Test_Certificate") else: self._check_can_download_certificate() @@ -188,7 +189,7 @@ class CertificateDisplayTest(CertificateDisplayTestBase): response = self.client.get(reverse('dashboard')) self.assertContains( response, - u'do not have a current verified identity with {platform_name}' + 'do not have a current verified identity with {platform_name}' .format(platform_name=settings.PLATFORM_NAME)) def test_post_to_linkedin_visibility(self): @@ -218,7 +219,7 @@ class CertificateDisplayTestHtmlView(CertificateDisplayTestBase): @classmethod def setUpClass(cls): - super(CertificateDisplayTestHtmlView, cls).setUpClass() + super().setUpClass() cls.course.cert_html_view_enabled = True cls.course.save() cls.store.update_item(cls.course, cls.USERNAME) @@ -246,7 +247,7 @@ class CertificateDisplayTestLinkedHtmlView(CertificateDisplayTestBase): @classmethod def setUpClass(cls): - super(CertificateDisplayTestLinkedHtmlView, cls).setUpClass() + super().setUpClass() cls.course.cert_html_view_enabled = True certificates = [ @@ -274,5 +275,5 @@ class CertificateDisplayTestLinkedHtmlView(CertificateDisplayTestBase): response = self.client.get(reverse('dashboard')) - self.assertContains(response, u'View Test_Certificate') + self.assertContains(response, 'View Test_Certificate') self.assertContains(response, test_url) diff --git a/common/djangoapps/student/tests/test_configuration_overrides.py b/common/djangoapps/student/tests/test_configuration_overrides.py index 1ae8cb7b0a..be4aae913d 100644 --- a/common/djangoapps/student/tests/test_configuration_overrides.py +++ b/common/djangoapps/student/tests/test_configuration_overrides.py @@ -5,7 +5,7 @@ Test for user creation from sites with configuration overrides. import json -import mock +from unittest import mock from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.test import TestCase from django.urls import reverse @@ -53,7 +53,7 @@ def fake_get_value(name, default=None): class TestSite(TestCase): """Test for Account Creation from white labeled Sites""" def setUp(self): - super(TestSite, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.username = "test_user" self.url = reverse("create_account") self.params = { diff --git a/common/djangoapps/student/tests/test_course_listing.py b/common/djangoapps/student/tests/test_course_listing.py index ceaf25f30c..c061ed3899 100644 --- a/common/djangoapps/student/tests/test_course_listing.py +++ b/common/djangoapps/student/tests/test_course_listing.py @@ -6,7 +6,7 @@ by reversing group name formats. import unittest -import mock +from unittest import mock import six from django.conf import settings from django.test.client import Client @@ -35,7 +35,7 @@ class TestCourseListing(ModuleStoreTestCase, MilestonesTestCaseMixin): """ Add a student & teacher """ - super(TestCourseListing, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory() self.teacher = UserFactory() @@ -65,7 +65,7 @@ class TestCourseListing(ModuleStoreTestCase, MilestonesTestCaseMixin): Reverse the setup """ self.client.logout() - super(TestCourseListing, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_get_course_list(self): @@ -153,8 +153,8 @@ class TestCourseListing(ModuleStoreTestCase, MilestonesTestCaseMixin): self._create_course_with_access_groups(pre_requisite_course_location2) # create a course with pre_requisite_courses pre_requisite_courses = [ - six.text_type(pre_requisite_course_location), - six.text_type(pre_requisite_course_location2), + str(pre_requisite_course_location), + str(pre_requisite_course_location2), ] course_location = self.store.make_course_key('Org1', 'Course1', 'Run1') self._create_course_with_access_groups(course_location, { diff --git a/common/djangoapps/student/tests/test_credit.py b/common/djangoapps/student/tests/test_credit.py index 437606cc6b..5e5ee9cc88 100644 --- a/common/djangoapps/student/tests/test_credit.py +++ b/common/djangoapps/student/tests/test_credit.py @@ -5,18 +5,18 @@ Tests for credit courses on the student dashboard. import datetime import unittest +from unittest.mock import patch import ddt import pytz from django.conf import settings from django.test.utils import override_settings from django.urls import reverse -from mock import patch -from openedx.core.djangoapps.credit import api as credit_api -from openedx.core.djangoapps.credit.models import CreditCourse, CreditEligibility, CreditProvider from common.djangoapps.student.models import CourseEnrollmentAttribute from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from openedx.core.djangoapps.credit import api as credit_api +from openedx.core.djangoapps.credit.models import CreditCourse, CreditEligibility, CreditProvider from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -43,7 +43,7 @@ class CreditCourseDashboardTest(ModuleStoreTestCase): def setUp(self): """Create a course and an enrollment. """ - super(CreditCourseDashboardTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Create a user and log in self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD) @@ -213,14 +213,14 @@ class CreditCourseDashboardTest(ModuleStoreTestCase): @ddt.data( ( - [u'Arizona State University'], + ['Arizona State University'], 'You are now eligible for credit from Arizona State University'), ( - [u'Arizona State University', u'Hogwarts School of Witchcraft'], + ['Arizona State University', 'Hogwarts School of Witchcraft'], 'You are now eligible for credit from Arizona State University and Hogwarts School of Witchcraft' ), ( - [u'Arizona State University', u'Hogwarts School of Witchcraft and Wizardry', u'Charter Oak'], + ['Arizona State University', 'Hogwarts School of Witchcraft and Wizardry', 'Charter Oak'], 'You are now eligible for credit from Arizona State University, Hogwarts School' ' of Witchcraft and Wizardry, and Charter Oak' ), diff --git a/common/djangoapps/student/tests/test_email.py b/common/djangoapps/student/tests/test_email.py index e2dbc76ecc..fb61b43bed 100644 --- a/common/djangoapps/student/tests/test_email.py +++ b/common/djangoapps/student/tests/test_email.py @@ -1,13 +1,11 @@ -# coding=utf-8 # lint-amnesty, pylint: disable=missing-module-docstring - - import json import unittest from string import capwords +from unittest.mock import Mock, patch import ddt -import six import pytest +import six from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.core import mail @@ -18,7 +16,6 @@ from django.test.client import RequestFactory from django.urls import reverse from django.utils.html import escape from edx_toggles.toggles.testutils import override_waffle_flag -from mock import Mock, patch from six import text_type from common.djangoapps.edxmako.shortcuts import marketing_link @@ -56,7 +53,7 @@ def mock_render_to_string(template_name, context): """ Return a string that encodes template_name and context """ - return str((template_name, sorted(six.iteritems(context)))) + return str((template_name, sorted(context.items()))) def mock_render_to_response(template_name, context): @@ -68,7 +65,7 @@ def mock_render_to_response(template_name, context): return HttpResponse(mock_render_to_string(template_name, context)) -class EmailTestMixin(object): +class EmailTestMixin: """ Adds useful assertions for testing `email_user` """ @@ -105,29 +102,29 @@ class ActivationEmailTests(EmailTemplateTagMixin, CacheIsolationTestCase): Test sending of the activation email. """ - ACTIVATION_SUBJECT = u"Action Required: Activate your {} account".format(settings.PLATFORM_NAME) + ACTIVATION_SUBJECT = f"Action Required: Activate your {settings.PLATFORM_NAME} account" # Text fragments we expect in the body of an email # sent from an OpenEdX installation. OPENEDX_FRAGMENTS = [ ( - u"Use the link below to activate your account to access engaging, " - u"high-quality {platform_name} courses. Note that you will not be able to log back into your " - u"account until you have activated it.".format( + "Use the link below to activate your account to access engaging, " + "high-quality {platform_name} courses. Note that you will not be able to log back into your " + "account until you have activated it.".format( platform_name=settings.PLATFORM_NAME ) ), - u"{}/activate/".format(settings.LMS_ROOT_URL), - u"If you need help, please use our web form at ", ( + f"{settings.LMS_ROOT_URL}/activate/", + "If you need help, please use our web form at ", ( settings.ACTIVATION_EMAIL_SUPPORT_LINK or settings.SUPPORT_SITE_LINK ), settings.CONTACT_EMAIL, - u"This email message was automatically sent by ", + "This email message was automatically sent by ", settings.LMS_ROOT_URL, - u" because someone attempted to create an account on {platform_name}".format( + " because someone attempted to create an account on {platform_name}".format( platform_name=settings.PLATFORM_NAME ), - u" using this email address." + " using this email address." ] @ddt.data('plain_text', 'html') @@ -249,7 +246,7 @@ class ProctoringRequirementsEmailTests(EmailTemplateTagMixin, ModuleStoreTestCas text = message.body html = message.alternatives[0][0] - assert message.subject == "Proctoring requirements for {}".format(self.course.display_name) + assert message.subject == f"Proctoring requirements for {self.course.display_name}" for fragment in self._get_fragments(): assert fragment in text @@ -288,7 +285,7 @@ class EmailChangeRequestTests(EventTestMixin, EmailTemplateTagMixin, CacheIsolat """ def setUp(self, tracker='common.djangoapps.student.views.management.tracker'): - super(EmailChangeRequestTests, self).setUp(tracker) # lint-amnesty, pylint: disable=super-with-arguments + super().setUp(tracker) self.user = UserFactory.create() self.new_email = 'new.email@edx.org' self.req_factory = RequestFactory() @@ -306,7 +303,7 @@ class EmailChangeRequestTests(EventTestMixin, EmailTemplateTagMixin, CacheIsolat try: validate_new_email(self.request.user, email) except ValueError as err: - return text_type(err) + return str(err) def do_email_change(self, user, email, activation_key=None): """ @@ -377,22 +374,22 @@ class EmailChangeRequestTests(EventTestMixin, EmailTemplateTagMixin, CacheIsolat self.do_email_change(self.user, new_email, registration_key) self._assert_email( - subject=u'Request to change édX account e-mail', + subject='Request to change édX account e-mail', body_fragments=[ - u'We received a request to change the e-mail associated with', - u'your édX account from {old_email} to {new_email}.'.format( + 'We received a request to change the e-mail associated with', + 'your édX account from {old_email} to {new_email}.'.format( old_email=old_email, new_email=new_email, ), - u'If this is correct, please confirm your new e-mail address by visiting:', - u'http://edx.org/email_confirm/{key}'.format(key=registration_key), - u'Please do not reply to this e-mail; if you require assistance,', - u'check the help section of the édX web site.', + 'If this is correct, please confirm your new e-mail address by visiting:', + f'http://edx.org/email_confirm/{registration_key}', + 'Please do not reply to this e-mail; if you require assistance,', + 'check the help section of the édX web site.', ], ) self.assert_event_emitted( - SETTING_CHANGE_INITIATED, user_id=self.user.id, setting=u'email', old=old_email, new=new_email + SETTING_CHANGE_INITIATED, user_id=self.user.id, setting='email', old=old_email, new=new_email ) def _assert_email(self, subject, body_fragments): @@ -423,7 +420,7 @@ class EmailChangeConfirmationTests(EmailTestMixin, EmailTemplateTagMixin, CacheI """ def setUp(self): - super(EmailChangeConfirmationTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.clear_caches() self.addCleanup(self.clear_caches) self.user = UserFactory.create() @@ -435,31 +432,31 @@ class EmailChangeConfirmationTests(EmailTestMixin, EmailTemplateTagMixin, CacheI self.key = self.pending_change_request.activation_key # Expected subject of the email - self.email_subject = u"Email Change Confirmation for {platform_name}".format( + self.email_subject = "Email Change Confirmation for {platform_name}".format( platform_name=settings.PLATFORM_NAME ) # Text fragments we expect in the body of the confirmation email self.email_fragments = [ - u"This is to confirm that you changed the e-mail associated with {platform_name}" - u" from {old_email} to {new_email}. If you did not make this request, please contact us immediately." - u" Contact information is listed at:".format( + "This is to confirm that you changed the e-mail associated with {platform_name}" + " from {old_email} to {new_email}. If you did not make this request, please contact us immediately." + " Contact information is listed at:".format( platform_name=settings.PLATFORM_NAME, old_email=self.user.email, new_email=PendingEmailChange.objects.get(activation_key=self.key).new_email ), - u"We keep a log of old e-mails, so if this request was unintentional, we can investigate." + "We keep a log of old e-mails, so if this request was unintentional, we can investigate." ] @classmethod def setUpClass(cls): - super(EmailChangeConfirmationTests, cls).setUpClass() + super().setUpClass() cls.start_cache_isolation() @classmethod def tearDownClass(cls): cls.end_cache_isolation() - super(EmailChangeConfirmationTests, cls).tearDownClass() + super().tearDownClass() def assertRolledBack(self): """ @@ -613,7 +610,7 @@ class SecondaryEmailChangeRequestTests(EventTestMixin, EmailTemplateTagMixin, Ca try: validate_new_email(self.request.user, email) except ValueError as err: - return text_type(err) + return str(err) def do_secondary_email_change(self, user, email, activation_key=None): """ @@ -664,12 +661,12 @@ class SecondaryEmailChangeRequestTests(EventTestMixin, EmailTemplateTagMixin, Ca self.do_secondary_email_change(self.user, new_email, registration_key) self._assert_email( - subject=u'Confirm your recovery email for édX', + subject='Confirm your recovery email for édX', body_fragments=[ - u'You\'ve registered this recovery email address for édX.', - u'If you set this email address, click "confirm email."', - u'If you didn\'t request this change, you can disregard this email.', - u'http://edx.org/activate_secondary_email/{key}'.format(key=registration_key), + 'You\'ve registered this recovery email address for édX.', + 'If you set this email address, click "confirm email."', + 'If you didn\'t request this change, you can disregard this email.', + f'http://edx.org/activate_secondary_email/{registration_key}', ], ) diff --git a/common/djangoapps/student/tests/test_enrollment.py b/common/djangoapps/student/tests/test_enrollment.py index f7e415302f..facd68d0e9 100644 --- a/common/djangoapps/student/tests/test_enrollment.py +++ b/common/djangoapps/student/tests/test_enrollment.py @@ -4,18 +4,17 @@ Tests for student enrollment. import unittest -import pytest +from unittest.mock import patch import ddt +import pytest import six from django.conf import settings from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_flag -from mock import patch from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory -from openedx.core.djangoapps.embargo.test_utils import restrict_course from common.djangoapps.student.models import ( SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE, CourseEnrollment, @@ -26,6 +25,7 @@ from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRol from common.djangoapps.student.tests.factories import CourseEnrollmentAllowedFactory, UserFactory from common.djangoapps.util.testing import UrlResetMixin from lms.djangoapps.courseware.toggles import COURSEWARE_PROCTORING_IMPROVEMENTS +from openedx.core.djangoapps.embargo.test_utils import restrict_course from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory @@ -46,7 +46,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(EnrollmentTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() cls.course_limited = CourseFactory.create() cls.proctored_course = CourseFactory( @@ -59,13 +59,13 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase): @patch.dict(settings.FEATURES, {'EMBARGO': True}) def setUp(self): """ Create a course and user, then log in. """ - super(EnrollmentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD) self.client.login(username=self.USERNAME, password=self.PASSWORD) self.course_limited.max_student_enrollments_allowed = 1 self.store.update_item(self.course_limited, self.user.id) self.urls = [ - reverse('course_modes_choose', kwargs={'course_id': six.text_type(self.course.id)}) + reverse('course_modes_choose', kwargs={'course_id': str(self.course.id)}) ] # Set up proctored exam self._create_proctored_exam(self.proctored_course) @@ -123,7 +123,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase): # (otherwise, use an empty string, which the JavaScript client # interprets as a redirect to the dashboard) full_url = ( - reverse(next_url, kwargs={'course_id': six.text_type(self.course.id)}) + reverse(next_url, kwargs={'course_id': str(self.course.id)}) if next_url else next_url ) @@ -384,7 +384,7 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase): """ if course_id is None: - course_id = six.text_type(self.course.id) + course_id = str(self.course.id) params = { 'enrollment_action': action, diff --git a/common/djangoapps/student/tests/test_events.py b/common/djangoapps/student/tests/test_events.py index 180c53f882..938952f571 100644 --- a/common/djangoapps/student/tests/test_events.py +++ b/common/djangoapps/student/tests/test_events.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- """ Test that various events are fired for models in the student app. """ -import mock +from unittest import mock import pytest from django.db.utils import IntegrityError @@ -21,7 +20,7 @@ class TestUserProfileEvents(UserSettingsEventTestMixin, TestCase): Test that we emit field change events when UserProfile models are changed. """ def setUp(self): - super(TestUserProfileEvents, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.table = 'auth_userprofile' self.user = UserFactory.create() self.profile = self.user.profile @@ -46,18 +45,18 @@ class TestUserProfileEvents(UserSettingsEventTestMixin, TestCase): Verify that we emit one event per field when many fields change on the user profile in one transaction. """ - self.profile.gender = u'o' + self.profile.gender = 'o' self.profile.bio = 'test bio' self.profile.save() self.assert_user_setting_event_emitted(setting='bio', old=None, new=self.profile.bio) - self.assert_user_setting_event_emitted(setting='gender', old=u'm', new=u'o') + self.assert_user_setting_event_emitted(setting='gender', old='m', new='o') def test_unicode(self): """ Verify that the events we emit can handle unicode characters. """ old_name = self.profile.name - self.profile.name = u'Dånîél' + self.profile.name = 'Dånîél' self.profile.save() self.assert_user_setting_event_emitted(setting='name', old=old_name, new=self.profile.name) @@ -65,7 +64,7 @@ class TestUserProfileEvents(UserSettingsEventTestMixin, TestCase): """ Verify that we properly serialize the JSON-unfriendly Country field. """ - self.profile.country = Country(u'AL', 'dummy_flag_url') + self.profile.country = Country('AL', 'dummy_flag_url') self.profile.save() self.assert_user_setting_event_emitted(setting='country', old=None, new=self.profile.country) @@ -73,7 +72,7 @@ class TestUserProfileEvents(UserSettingsEventTestMixin, TestCase): """ Verify that we don't emit events for ignored fields. """ - self.profile.meta = {u'foo': u'bar'} + self.profile.meta = {'foo': 'bar'} self.profile.save() self.assert_no_events_were_emitted() @@ -95,7 +94,7 @@ class TestUserEvents(UserSettingsEventTestMixin, TestCase): Test that we emit field change events when User models are changed. """ def setUp(self): - super(TestUserEvents, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() self.reset_tracker() self.table = 'auth_user' @@ -105,7 +104,7 @@ class TestUserEvents(UserSettingsEventTestMixin, TestCase): Verify that we emit an event when a single field changes on the user. """ old_username = self.user.username - self.user.username = u'new username' + self.user.username = 'new username' self.user.save() self.assert_user_setting_event_emitted(setting='username', old=old_username, new=self.user.username) @@ -116,7 +115,7 @@ class TestUserEvents(UserSettingsEventTestMixin, TestCase): """ old_email = self.user.email old_is_staff = self.user.is_staff - self.user.email = u'foo@bar.com' + self.user.email = 'foo@bar.com' self.user.is_staff = True self.user.save() self.assert_user_setting_event_emitted(setting='email', old=old_email, new=self.user.email) @@ -126,7 +125,7 @@ class TestUserEvents(UserSettingsEventTestMixin, TestCase): """ Verify that password values are not included in the event payload. """ - self.user.password = u'new password' + self.user.password = 'new password' self.user.save() self.assert_user_setting_event_emitted(setting='password', old=None, new=None) @@ -145,7 +144,7 @@ class TestUserEvents(UserSettingsEventTestMixin, TestCase): signal is not called in this case either, but the intent is to make it clear that this model should never emit an event if save fails. """ - self.user.password = u'new password' + self.user.password = 'new password' with pytest.raises(IntegrityError): self.user.save() self.assert_no_events_were_emitted() diff --git a/common/djangoapps/student/tests/test_helpers.py b/common/djangoapps/student/tests/test_helpers.py index e9eb832d13..ef864a103b 100644 --- a/common/djangoapps/student/tests/test_helpers.py +++ b/common/djangoapps/student/tests/test_helpers.py @@ -3,6 +3,7 @@ import logging import unittest +from unittest.mock import patch import ddt from django.conf import settings @@ -10,11 +11,10 @@ from django.contrib.sessions.middleware import SessionMiddleware from django.test import TestCase from django.test.client import RequestFactory from django.test.utils import override_settings -from mock import patch from testfixtures import LogCapture -from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context from common.djangoapps.student.helpers import get_next_url_for_login_page +from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context LOGGER_NAME = "common.djangoapps.student.helpers" @@ -25,7 +25,7 @@ class TestLoginHelper(TestCase): static_url = settings.STATIC_URL def setUp(self): - super(TestLoginHelper, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.request = RequestFactory() @staticmethod @@ -56,7 +56,7 @@ class TestLoginHelper(TestCase): def test_next_failures(self, log_level, log_name, unsafe_url, http_accept, user_agent, expected_log): """ Test unsafe next parameter """ with LogCapture(LOGGER_NAME, level=log_level) as logger: - req = self.request.get(settings.LOGIN_URL + "?next={url}".format(url=unsafe_url)) + req = self.request.get(settings.LOGIN_URL + f"?next={unsafe_url}") req.META["HTTP_ACCEPT"] = http_accept req.META["HTTP_USER_AGENT"] = user_agent get_next_url_for_login_page(req) @@ -74,7 +74,7 @@ class TestLoginHelper(TestCase): @override_settings(LOGIN_REDIRECT_WHITELIST=['test.edx.org', 'test2.edx.org']) def test_safe_next(self, next_url, http_accept, host): """ Test safe next parameter """ - req = self.request.get(settings.LOGIN_URL + "?next={url}".format(url=next_url), HTTP_HOST=host) + req = self.request.get(settings.LOGIN_URL + f"?next={next_url}", HTTP_HOST=host) req.META["HTTP_ACCEPT"] = http_accept next_page = get_next_url_for_login_page(req) assert next_page == next_url @@ -121,7 +121,7 @@ class TestLoginHelper(TestCase): Assert that get_next_url_for_login_page returns as expected. """ if method == 'GET': - req = self.request.get(settings.LOGIN_URL + "?next={url}".format(url=next_url)) + req = self.request.get(settings.LOGIN_URL + f"?next={next_url}") elif method == 'POST': req = self.request.post(settings.LOGIN_URL, {'next': next_url}) req.META["HTTP_ACCEPT"] = "text/html" diff --git a/common/djangoapps/student/tests/test_linkedin.py b/common/djangoapps/student/tests/test_linkedin.py index ef530495f8..50dd921f25 100644 --- a/common/djangoapps/student/tests/test_linkedin.py +++ b/common/djangoapps/student/tests/test_linkedin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Tests for LinkedIn Add to Profile configuration. """ @@ -60,7 +59,7 @@ class LinkedInAddToProfileUrlTests(TestCase): assert 'https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME' in actual_url assert f'&name={quote(settings.PLATFORM_NAME.encode("utf-8"))}+{expected_cert_name}' in actual_url assert '&certUrl={cert_url}'.format(cert_url=quote(self.CERT_URL, safe='')) in actual_url - assert '&organizationId={org_id}'.format(org_id=config.company_identifier) in actual_url + assert f'&organizationId={config.company_identifier}' in actual_url @ddt.data( ('honor', 'Honor+Code+Credential+for+Test+Course+%E2%98%83'), @@ -95,4 +94,4 @@ class LinkedInAddToProfileUrlTests(TestCase): assert 'https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME' in actual_url assert f'&name={quote(settings.PLATFORM_NAME.encode("utf-8"))}+{expected_cert_name}' in actual_url assert '&certUrl={cert_url}'.format(cert_url=quote(self.CERT_URL, safe='')) in actual_url - assert '&organizationId={org_id}'.format(org_id=config.company_identifier) in actual_url + assert f'&organizationId={config.company_identifier}' in actual_url diff --git a/common/djangoapps/student/tests/test_long_username_email.py b/common/djangoapps/student/tests/test_long_username_email.py index 2740bcdd44..dbb5669a4d 100644 --- a/common/djangoapps/student/tests/test_long_username_email.py +++ b/common/djangoapps/student/tests/test_long_username_email.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- # lint-amnesty, pylint: disable=missing-module-docstring - - import json from django.test import TestCase @@ -12,7 +9,7 @@ from openedx.core.djangoapps.user_api.accounts import USERNAME_BAD_LENGTH_MSG class TestLongUsernameEmail(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring def setUp(self): - super(TestLongUsernameEmail, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('create_account') self.url_params = { 'username': 'username', diff --git a/common/djangoapps/student/tests/test_models.py b/common/djangoapps/student/tests/test_models.py index cb4e444b1d..52d5bbd9e1 100644 --- a/common/djangoapps/student/tests/test_models.py +++ b/common/djangoapps/student/tests/test_models.py @@ -1,10 +1,10 @@ # lint-amnesty, pylint: disable=missing-module-docstring import datetime import hashlib +from unittest import mock import ddt import factory -import mock import pytz from crum import set_current_request from django.contrib.auth.models import AnonymousUser, User # lint-amnesty, pylint: disable=imported-auth-user @@ -12,13 +12,24 @@ from django.core.cache import cache from django.db.models import signals from django.db.models.functions import Lower from django.test import TestCase +from edx_toggles.toggles.testutils import override_waffle_flag from freezegun import freeze_time from opaque_keys.edx.keys import CourseKey from pytz import UTC -from edx_toggles.toggles.testutils import override_waffle_flag from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.models import ( + ALLOWEDTOENROLL_TO_ENROLLED, + AccountRecovery, + CourseEnrollment, + CourseEnrollmentAllowed, + ManualEnrollmentAudit, + PendingEmailChange, + PendingNameChange, + UserCelebration +) +from common.djangoapps.student.tests.factories import AccountRecoveryFactory, CourseEnrollmentFactory, UserFactory from lms.djangoapps.courseware.models import DynamicUpgradeDeadlineConfiguration from lms.djangoapps.courseware.toggles import ( COURSEWARE_MICROFRONTEND_PROGRESS_MILESTONES, @@ -29,17 +40,6 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOvervi from openedx.core.djangoapps.schedules.models import Schedule from openedx.core.djangoapps.user_api.preferences.api import set_user_preference from openedx.core.djangolib.testing.utils import skip_unless_lms -from common.djangoapps.student.models import ( - ALLOWEDTOENROLL_TO_ENROLLED, - AccountRecovery, - CourseEnrollment, - CourseEnrollmentAllowed, - UserCelebration, - ManualEnrollmentAudit, - PendingEmailChange, - PendingNameChange, -) -from common.djangoapps.student.tests.factories import AccountRecoveryFactory, CourseEnrollmentFactory, UserFactory from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -49,11 +49,11 @@ from xmodule.modulestore.tests.factories import CourseFactory class CourseEnrollmentTests(SharedModuleStoreTestCase): # lint-amnesty, pylint: disable=missing-class-docstring @classmethod def setUpClass(cls): - super(CourseEnrollmentTests, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory() def setUp(self): - super(CourseEnrollmentTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory() self.user_2 = UserFactory() @@ -465,7 +465,7 @@ class PendingNameChangeTests(SharedModuleStoreTestCase): """ @classmethod def setUpClass(cls): - super(PendingNameChangeTests, cls).setUpClass() + super().setUpClass() cls.user = UserFactory() cls.user2 = UserFactory() @@ -494,7 +494,7 @@ class PendingEmailChangeTests(SharedModuleStoreTestCase): """ @classmethod def setUpClass(cls): - super(PendingEmailChangeTests, cls).setUpClass() + super().setUpClass() cls.user = UserFactory() cls.user2 = UserFactory() @@ -519,7 +519,7 @@ class PendingEmailChangeTests(SharedModuleStoreTestCase): class TestCourseEnrollmentAllowed(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring def setUp(self): - super(TestCourseEnrollmentAllowed, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.email = 'learner@example.com' self.course_key = CourseKey.from_string("course-v1:edX+DemoX+Demo_Course") self.user = UserFactory.create() @@ -558,7 +558,7 @@ class TestManualEnrollmentAudit(SharedModuleStoreTestCase): """ @classmethod def setUpClass(cls): - super(TestManualEnrollmentAudit, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory() cls.other_course = CourseFactory() cls.user = UserFactory() @@ -625,7 +625,7 @@ class TestUserPostSaveCallback(SharedModuleStoreTestCase): changing any existing course mode states. """ def setUp(self): - super(TestUserPostSaveCallback, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() @ddt.data(*(set(CourseMode.ALL_MODES) - set(CourseMode.AUDIT_MODES))) @@ -675,7 +675,7 @@ class TestUserPostSaveCallback(SharedModuleStoreTestCase): actual_student = User.objects.get(email=student.email) actual_cea = CourseEnrollmentAllowed.objects.get(email=student.email) - assert actual_course_enrollment.mode == u'audit' + assert actual_course_enrollment.mode == 'audit' assert actual_student.is_active is True assert actual_cea.user == student @@ -687,7 +687,7 @@ class TestUserPostSaveCallback(SharedModuleStoreTestCase): student = self._set_up_invited_student( course=self.course, active=True, - course_mode=u'verified' + course_mode='verified' ) old_email = student.email @@ -699,7 +699,7 @@ class TestUserPostSaveCallback(SharedModuleStoreTestCase): actual_course_enrollment = CourseEnrollment.objects.get(user=student, course_id=self.course.id) actual_student = User.objects.get(email=student.email) - assert actual_course_enrollment.mode == u'verified' + assert actual_course_enrollment.mode == 'verified' assert actual_student.is_active is True def _set_up_invited_student(self, course, active=False, enrolled=True, course_mode=''): diff --git a/common/djangoapps/student/tests/test_parental_controls.py b/common/djangoapps/student/tests/test_parental_controls.py index 40ce8d3097..058e26a7cb 100644 --- a/common/djangoapps/student/tests/test_parental_controls.py +++ b/common/djangoapps/student/tests/test_parental_controls.py @@ -17,7 +17,7 @@ class ProfileParentalControlsTest(TestCase): password = "test" def setUp(self): - super(ProfileParentalControlsTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(password=self.password) self.profile = UserProfile.objects.get(id=self.user.id) diff --git a/common/djangoapps/student/tests/test_password_policy.py b/common/djangoapps/student/tests/test_password_policy.py index 11bbf38b5a..f380095608 100644 --- a/common/djangoapps/student/tests/test_password_policy.py +++ b/common/djangoapps/student/tests/test_password_policy.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ This test file will verify proper password policy enforcement, which is an option feature """ @@ -17,7 +16,7 @@ class TestPasswordPolicy(TestCase): Go through some password policy tests to make sure things are properly working """ def setUp(self): - super(TestPasswordPolicy, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('create_account') self.request_factory = RequestFactory() self.url_params = { @@ -125,7 +124,7 @@ class TestPasswordPolicy(TestCase): ]) def test_not_enough_numeric_characters(self): # The unicode ២ is the number 2 in Khmer and the ٧ is the Arabic-Indic number 7 - self.url_params['password'] = u'thisShouldFail២٧' + self.url_params['password'] = 'thisShouldFail២٧' response = self.client.post(self.url, self.url_params) assert response.status_code == 400 obj = json.loads(response.content.decode('utf-8')) @@ -136,7 +135,7 @@ class TestPasswordPolicy(TestCase): ]) def test_enough_numeric_characters(self): # The unicode ២ is the number 2 in Khmer - self.url_params['password'] = u'thisShouldPass២33' + self.url_params['password'] = 'thisShouldPass២33' response = self.client.post(self.url, self.url_params) assert response.status_code == 200 obj = json.loads(response.content.decode('utf-8')) @@ -156,7 +155,7 @@ class TestPasswordPolicy(TestCase): create_validator_config('common.djangoapps.util.password_policy_validators.AlphabeticValidator', {'min_alphabetic': 3}) # lint-amnesty, pylint: disable=line-too-long ]) def test_enough_alphabetic_characters(self): - self.url_params['password'] = u'𝒯𝓗Ï𝓼𝒫å𝓼𝓼𝔼𝓼' + self.url_params['password'] = '𝒯𝓗Ï𝓼𝒫å𝓼𝓼𝔼𝓼' response = self.client.post(self.url, self.url_params) assert response.status_code == 200 obj = json.loads(response.content.decode('utf-8')) @@ -189,7 +188,7 @@ class TestPasswordPolicy(TestCase): create_validator_config('common.djangoapps.util.password_policy_validators.PunctuationValidator', {'min_punctuation': 3}), # lint-amnesty, pylint: disable=line-too-long ]) def test_multiple_errors_pass(self): - self.url_params['password'] = u'tH1s Sh0u!d P3#$!' + self.url_params['password'] = 'tH1s Sh0u!d P3#$!' response = self.client.post(self.url, self.url_params) assert response.status_code == 200 obj = json.loads(response.content.decode('utf-8')) @@ -220,7 +219,7 @@ class TestPasswordPolicy(TestCase): create_validator_config('common.djangoapps.util.password_policy_validators.MaximumLengthValidator', {'max_length': 75}), # lint-amnesty, pylint: disable=line-too-long ]) def test_with_unicode(self): - self.url_params['password'] = u'四節比分和七年前' + self.url_params['password'] = '四節比分和七年前' response = self.client.post(self.url, self.url_params) assert response.status_code == 200 obj = json.loads(response.content.decode('utf-8')) @@ -232,7 +231,7 @@ class TestUsernamePasswordNonmatch(TestCase): Test that registration username and password fields differ """ def setUp(self): - super(TestUsernamePasswordNonmatch, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('create_account') self.url_params = { diff --git a/common/djangoapps/student/tests/test_recent_enrollments.py b/common/djangoapps/student/tests/test_recent_enrollments.py index bc0d71ac0d..a9cbdd94e2 100644 --- a/common/djangoapps/student/tests/test_recent_enrollments.py +++ b/common/djangoapps/student/tests/test_recent_enrollments.py @@ -12,7 +12,6 @@ from django.urls import reverse from django.utils.timezone import now from opaque_keys.edx import locator from pytz import UTC -from six.moves import range, zip from common.test.utils import XssTestMixin from common.djangoapps.student.models import CourseEnrollment, DashboardConfiguration @@ -35,7 +34,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin): """ Add a student """ - super(TestRecentEnrollments, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory() self.student.set_password(self.PASSWORD) self.student.save() @@ -102,9 +101,9 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin): courses = [] for idx, seconds_past in zip(list(range(2, 6)), [5, 10, 15, 20]): course_location = locator.CourseLocator( - 'Org{num}'.format(num=idx), - 'Course{num}'.format(num=idx), - 'Run{num}'.format(num=idx) + f'Org{idx}', + f'Course{idx}', + f'Run{idx}' ) course, enrollment = self._create_course_and_enrollment(course_location) enrollment.created = now() - datetime.timedelta(seconds=seconds_past) @@ -126,10 +125,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin): response = self.client.get(reverse("dashboard")) # verify recent enrollment message - self.assertContains( - response, - 'Thank you for enrolling in:'.format(course_name=self.course.display_name) - ) + self.assertContains(response, 'Thank you for enrolling in:') self.assertContains( response, ', '.join(enrollment.course.display_name for enrollment in recent_course_list) @@ -144,7 +140,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin): response = self.client.get(reverse("dashboard")) self.assertContains( response, - "Thank you for enrolling in {course_name}".format(course_name=self.course.display_name) + f"Thank you for enrolling in {self.course.display_name}" ) def test_dashboard_rendering_with_two_courses(self): @@ -171,7 +167,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin): self.assertContains( response, - "Thank you for enrolling in:".format(course_name=self.course.display_name) + "Thank you for enrolling in:" ) self.assertContains( response, diff --git a/common/djangoapps/student/tests/test_refunds.py b/common/djangoapps/student/tests/test_refunds.py index 87110106dd..6ecf47d397 100644 --- a/common/djangoapps/student/tests/test_refunds.py +++ b/common/djangoapps/student/tests/test_refunds.py @@ -6,6 +6,7 @@ import logging import unittest from datetime import datetime, timedelta +from unittest.mock import patch import ddt import httpretty @@ -16,17 +17,15 @@ from django.conf import settings from django.test.client import Client from django.test.utils import override_settings from django.urls import reverse -from mock import patch -from six.moves import range # These imports refer to lms djangoapps. # Their testcases are only run under lms. from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.models import CourseEnrollment, CourseEnrollmentAttribute, EnrollmentRefundConfiguration +from common.djangoapps.student.tests.factories import UserFactory from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory from openedx.core.djangoapps.commerce.utils import ECOMMERCE_DATE_FORMAT -from common.djangoapps.student.models import CourseEnrollment, CourseEnrollmentAttribute, EnrollmentRefundConfiguration -from common.djangoapps.student.tests.factories import UserFactory from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -46,12 +45,12 @@ class RefundableTest(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(RefundableTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): """ Setup components used by each refund test.""" - super(RefundableTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(password=self.USER_PASSWORD) self.verified_mode = CourseModeFactory.create( course_id=self.course.id, @@ -136,11 +135,11 @@ class RefundableTest(SharedModuleStoreTestCase): expected_date = now + expected_date_delta refund_period = timedelta(days=days) date_placed = order_date.strftime(ECOMMERCE_DATE_FORMAT) - expected_content = '{{"date_placed": "{date}"}}'.format(date=date_placed) + expected_content = f'{{"date_placed": "{date_placed}"}}' httpretty.register_uri( httpretty.GET, - '{url}/orders/{order}/'.format(url=TEST_API_URL, order=self.ORDER_NUMBER), + f'{TEST_API_URL}/orders/{self.ORDER_NUMBER}/', status=200, body=expected_content, adding_headers={'Content-Type': JSON} ) @@ -202,7 +201,7 @@ class RefundableTest(SharedModuleStoreTestCase): httpretty.register_uri( httpretty.GET, - '{url}/orders/{order}/'.format(url=TEST_API_URL, order=self.ORDER_NUMBER), + f'{TEST_API_URL}/orders/{self.ORDER_NUMBER}/', status=200, body=expected_content, adding_headers={'Content-Type': JSON} ) diff --git a/common/djangoapps/student/tests/test_retirement.py b/common/djangoapps/student/tests/test_retirement.py index b37d49b396..e41b4f8f8b 100644 --- a/common/djangoapps/student/tests/test_retirement.py +++ b/common/djangoapps/student/tests/test_retirement.py @@ -270,7 +270,7 @@ class TestRegisterRetiredUsername(TestCase): INVALID_ERR_MSG = ('It looks like', 'belongs to an existing account. Try again with a different username.') def setUp(self): - super(TestRegisterRetiredUsername, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('user_api_registration') self.url_params = { 'username': 'username', diff --git a/common/djangoapps/student/tests/test_roles.py b/common/djangoapps/student/tests/test_roles.py index 392c183843..059abcf2e8 100644 --- a/common/djangoapps/student/tests/test_roles.py +++ b/common/djangoapps/student/tests/test_roles.py @@ -28,7 +28,7 @@ class RolesTestCase(TestCase): """ def setUp(self): - super(RolesTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course_key = CourseKey.from_string('edX/toy/2012_Fall') self.course_loc = self.course_key.make_usage_key('course', '2012_Fall') self.anonymous_user = AnonymousUserFactory() @@ -156,7 +156,7 @@ class RoleCacheTestCase(TestCase): # lint-amnesty, pylint: disable=missing-clas ) def setUp(self): - super(RoleCacheTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory() @ddt.data(*ROLES) diff --git a/common/djangoapps/student/tests/test_tasks.py b/common/djangoapps/student/tests/test_tasks.py index b6cbbf76a2..5a8462fac0 100644 --- a/common/djangoapps/student/tests/test_tasks.py +++ b/common/djangoapps/student/tests/test_tasks.py @@ -3,10 +3,9 @@ Tests for the Sending activation email celery tasks """ -import mock +from unittest import mock from django.conf import settings from django.test import TestCase -from six.moves import range from edx_ace.errors import ChannelError, RecoverableChannelDeliveryError from lms.djangoapps.courseware.tests.factories import UserFactory @@ -21,7 +20,7 @@ class SendActivationEmailTestCase(TestCase): """ def setUp(self): """ Setup components used by each test.""" - super(SendActivationEmailTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory() registration = Registration() diff --git a/common/djangoapps/student/tests/test_user_profile_properties.py b/common/djangoapps/student/tests/test_user_profile_properties.py index 686bc0a7d2..8310759266 100644 --- a/common/djangoapps/student/tests/test_user_profile_properties.py +++ b/common/djangoapps/student/tests/test_user_profile_properties.py @@ -21,7 +21,7 @@ class UserProfilePropertiesTest(CacheIsolationTestCase): ENABLED_CACHES = ['default'] def setUp(self): - super(UserProfilePropertiesTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(password=self.password) self.profile = self.user.profile diff --git a/common/djangoapps/student/tests/test_userstanding.py b/common/djangoapps/student/tests/test_userstanding.py index c7e4b3b4c4..3fd93e7af5 100644 --- a/common/djangoapps/student/tests/test_userstanding.py +++ b/common/djangoapps/student/tests/test_userstanding.py @@ -18,7 +18,7 @@ class UserStandingTest(TestCase): """test suite for user standing view for enabling and disabling accounts""" def setUp(self): - super(UserStandingTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # create users self.bad_user = UserFactory.create( username='bad_user', diff --git a/common/djangoapps/student/tests/test_verification_status.py b/common/djangoapps/student/tests/test_verification_status.py index 8b93eca72f..f03ae609ee 100644 --- a/common/djangoapps/student/tests/test_verification_status.py +++ b/common/djangoapps/student/tests/test_verification_status.py @@ -3,6 +3,7 @@ import unittest from datetime import datetime, timedelta +from unittest.mock import patch import ddt import six @@ -10,12 +11,9 @@ from django.conf import settings from django.test import override_settings from django.urls import reverse from django.utils.timezone import now - -from mock import patch from pytz import UTC from common.djangoapps.course_modes.tests.factories import CourseModeFactory -from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationDeadline from common.djangoapps.student.helpers import ( VERIFY_STATUS_APPROVED, VERIFY_STATUS_MISSED_DEADLINE, @@ -26,6 +24,7 @@ from common.djangoapps.student.helpers import ( ) from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from common.djangoapps.util.testing import UrlResetMixin +from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationDeadline from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -48,7 +47,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase): def setUp(self): # Invoke UrlResetMixin - super(TestCourseVerificationStatus, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory(password="edx") self.course = CourseFactory.create() @@ -379,7 +378,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase): response = self.client.get(self.dashboard_url) # Sanity check: verify that the course is on the page - self.assertContains(response, six.text_type(self.course.id)) + self.assertContains(response, str(self.course.id)) # Verify that the correct banner is rendered on the dashboard alt_text = self.BANNER_ALT_MESSAGES.get(status) diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index 132eafb3f3..fd79c1835e 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -8,6 +8,7 @@ import json import re import unittest from datetime import timedelta # lint-amnesty, pylint: disable=unused-import +from unittest.mock import patch import ddt import six @@ -18,14 +19,22 @@ from django.test.utils import override_settings from django.urls import reverse from django.utils.timezone import now from milestones.tests.utils import MilestonesTestCaseMixin -from mock import patch from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from pyquery import PyQuery as pq -from six.moves import range from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.entitlements.tests.factories import CourseEntitlementFactory +from common.djangoapps.student.helpers import DISABLE_UNENROLL_CERT_STATES +from common.djangoapps.student.models import CourseEnrollment, UserProfile +from common.djangoapps.student.signals import REFUND_ORDER +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from common.djangoapps.util.milestones_helpers import ( # lint-amnesty, pylint: disable=line-too-long + get_course_milestones, + remove_prerequisite_course, + set_prerequisite_courses +) +from common.djangoapps.util.testing import UrlResetMixin from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory from openedx.core.djangoapps.catalog.tests.factories import ProgramFactory from openedx.core.djangoapps.content.course_overviews.models import CourseOverview @@ -33,12 +42,6 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from openedx.features.course_experience.tests.views.helpers import add_course_mode -from common.djangoapps.student.helpers import DISABLE_UNENROLL_CERT_STATES -from common.djangoapps.student.models import CourseEnrollment, UserProfile -from common.djangoapps.student.signals import REFUND_ORDER -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from common.djangoapps.util.milestones_helpers import get_course_milestones, remove_prerequisite_course, set_prerequisite_courses # lint-amnesty, pylint: disable=line-too-long -from common.djangoapps.util.testing import UrlResetMixin from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory @@ -56,12 +59,12 @@ class TestStudentDashboardUnenrollments(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestStudentDashboardUnenrollments, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): """ Create a course and user, then log in. """ - super(TestStudentDashboardUnenrollments, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory() self.enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user) self.cert_status = 'processing' @@ -193,7 +196,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, """ Create a course and user, then log in. """ - super(StudentDashboardTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory() self.client.login(username=self.user.username, password=PASSWORD) self.path = reverse('dashboard') @@ -287,11 +290,11 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, org='edx', number='998', display_name='Test Course', - pre_requisite_courses=[six.text_type(self.pre_requisite_course.id)] + pre_requisite_courses=[str(self.pre_requisite_course.id)] ) self.course_enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user) # lint-amnesty, pylint: disable=attribute-defined-outside-init - set_prerequisite_courses(self.course.id, [six.text_type(self.pre_requisite_course.id)]) + set_prerequisite_courses(self.course.id, [str(self.pre_requisite_course.id)]) response = self.client.get(reverse('dashboard')) self.assertContains(response, '
') @@ -319,7 +322,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, mock_course_overview.return_value = CourseOverviewFactory.create(start=self.TOMORROW, id=course_key) mock_course_runs.return_value = [ { - 'key': six.text_type(course_key), + 'key': str(course_key), 'enrollment_end': str(self.TOMORROW), 'pacing_type': 'instructor_paced', 'type': 'verified', @@ -327,7 +330,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, } ] mock_pseudo_session.return_value = { - 'key': six.text_type(course_key), + 'key': str(course_key), 'type': 'verified' } response = self.client.get(self.path) @@ -404,7 +407,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, start=self.TOMORROW, end=self.THREE_YEARS_FROM_NOW, self_paced=True, enrollment_end=self.THREE_YEARS_AGO ) mock_course_overview.return_value = mocked_course_overview - course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=six.text_type(mocked_course_overview.id)) + course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=str(mocked_course_overview.id)) mock_course_runs.return_value = [ { 'key': str(mocked_course_overview.id), @@ -468,7 +471,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, start=self.TOMORROW, self_paced=True, enrollment_end=self.TOMORROW ) mock_course_overview.return_value = mocked_course_overview - course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=six.text_type(mocked_course_overview.id)) + course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=str(mocked_course_overview.id)) mock_course_runs.return_value = [ { 'key': str(mocked_course_overview.id), @@ -480,7 +483,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, ] entitlement = CourseEntitlementFactory(user=self.user, enrollment_course_run=course_enrollment) program = ProgramFactory() - program['courses'][0]['course_runs'] = [{'key': six.text_type(mocked_course_overview.id)}] + program['courses'][0]['course_runs'] = [{'key': str(mocked_course_overview.id)}] program['courses'][0]['uuid'] = entitlement.course_uuid mock_get_programs.return_value = [program] response = self.client.get(self.path) @@ -503,7 +506,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, start=self.TOMORROW, self_paced=True, enrollment_end=self.TOMORROW ) mock_course_overview.return_value = mocked_course_overview - course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=six.text_type(mocked_course_overview.id), created=self.THREE_YEARS_AGO) # lint-amnesty, pylint: disable=line-too-long + course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=str(mocked_course_overview.id), created=self.THREE_YEARS_AGO) # lint-amnesty, pylint: disable=line-too-long mock_course_runs.return_value = [ { 'key': str(mocked_course_overview.id), @@ -515,7 +518,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, ] entitlement = CourseEntitlementFactory(user=self.user, enrollment_course_run=course_enrollment, created=self.THREE_YEARS_AGO) # lint-amnesty, pylint: disable=line-too-long program = ProgramFactory() - program['courses'][0]['course_runs'] = [{'key': six.text_type(mocked_course_overview.id)}] + program['courses'][0]['course_runs'] = [{'key': str(mocked_course_overview.id)}] program['courses'][0]['uuid'] = entitlement.course_uuid mock_get_programs.return_value = [program] response = self.client.get(self.path) @@ -536,7 +539,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=course_overview.id) entitlement = CourseEntitlementFactory(user=self.user, enrollment_course_run=course_enrollment) course_runs = [{ - 'key': six.text_type(course_overview.id), + 'key': str(course_overview.id), 'uuid': entitlement.course_uuid }] mock_get_course_runs.return_value = course_runs @@ -722,7 +725,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, ItemFactory.create( category='video', parent_location=course.location, - display_name='Video {0}'.format(six.text_type(number)) + display_name='Video {}'.format(str(number)) ).location for number in range(5) ] @@ -823,7 +826,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, ItemFactory.create( category='video', parent_location=course.location, - display_name='Video {0}'.format(six.text_type(number)) + display_name='Video {}'.format(str(number)) ).location for number in range(5) ] diff --git a/common/djangoapps/student/tests/tests.py b/common/djangoapps/student/tests/tests.py index ecee011dde..f207c96cb2 100644 --- a/common/djangoapps/student/tests/tests.py +++ b/common/djangoapps/student/tests/tests.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Miscellaneous tests for the student app. """ @@ -7,6 +6,7 @@ Miscellaneous tests for the student app. import logging import unittest from datetime import datetime, timedelta +from unittest.mock import Mock, patch from urllib.parse import quote import ddt @@ -18,13 +18,26 @@ from django.test import TestCase, override_settings from django.test.client import Client from django.urls import reverse from markupsafe import escape -from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import CourseLocator from pyquery import PyQuery as pq from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.helpers import _cert_info, process_survey_link +from common.djangoapps.student.models import ( + AnonymousUserId, + CourseEnrollment, + LinkedInAddToProfileConfiguration, + UserAttribute, + anonymous_id_for_user, + unique_id_for_user, + user_by_anonymous_id +) +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from common.djangoapps.student.views import complete_course_mode_info +from common.djangoapps.util.model_utils import USER_SETTINGS_CHANGED_EVENT_NAME +from common.djangoapps.util.testing import EventTestMixin from lms.djangoapps.certificates.models import CertificateStatuses from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory from lms.djangoapps.verify_student.tests import TestVerificationBase @@ -34,20 +47,6 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms -from common.djangoapps.student.helpers import _cert_info, process_survey_link -from common.djangoapps.student.models import ( - CourseEnrollment, - LinkedInAddToProfileConfiguration, - UserAttribute, - AnonymousUserId, - anonymous_id_for_user, - unique_id_for_user, - user_by_anonymous_id -) -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from common.djangoapps.student.views import complete_course_mode_info -from common.djangoapps.util.model_utils import USER_SETTINGS_CHANGED_EVENT_NAME -from common.djangoapps.util.testing import EventTestMixin from xmodule.modulestore.tests.django_utils import ModuleStoreEnum, ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls @@ -67,7 +66,7 @@ class CourseEndingTest(ModuleStoreTestCase): assert process_survey_link(link1, user) == link1 link2 = "http://www.mysurvey.com?unique={UNIQUE_ID}" - link2_expected = "http://www.mysurvey.com?unique={UNIQUE_ID}".format(UNIQUE_ID=user_id) + link2_expected = f"http://www.mysurvey.com?unique={user_id}" assert process_survey_link(link2, user) == link2_expected @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': False}) @@ -217,7 +216,7 @@ class DashboardTest(ModuleStoreTestCase, TestVerificationBase): ENABLED_SIGNALS = ['course_published'] def setUp(self): - super(DashboardTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.user = UserFactory.create(username="jack", email="jack@fake.edx.org", password='test') self.client = Client() @@ -240,7 +239,7 @@ class DashboardTest(ModuleStoreTestCase, TestVerificationBase): if mode in ['professional', 'no-id-professional']: self.assertContains(response, 'class="course professional"') else: - self.assertContains(response, 'class="course {0}"'.format(mode)) + self.assertContains(response, f'class="course {mode}"') self.assertContains(response, value) @patch.dict("django.conf.settings.FEATURES", {'ENABLE_VERIFIED_CERTIFICATES': True}) @@ -277,7 +276,7 @@ class DashboardTest(ModuleStoreTestCase, TestVerificationBase): # Audit mode does not have a banner. Assert no banner element. assert pq(response.content)('.sts-enrollment').length == 0 else: - self.assertNotContains(response, "class=\"course {0}\"".format(mode)) + self.assertNotContains(response, f"class=\"course {mode}\"") self.assertNotContains(response, value) @patch.dict("django.conf.settings.FEATURES", {'ENABLE_VERIFIED_CERTIFICATES': False}) @@ -325,7 +324,7 @@ class DashboardTest(ModuleStoreTestCase, TestVerificationBase): self.course.start = datetime.now(pytz.UTC) - timedelta(days=2) self.course.end = datetime.now(pytz.UTC) - timedelta(days=1) - self.course.display_name = u"Omega" + self.course.display_name = "Omega" self.course = self.update_course(self.course, self.user.id) download_url = 'www.edx.org' @@ -485,7 +484,7 @@ class DashboardTestsWithSiteOverrides(SiteMixin, ModuleStoreTestCase): """ def setUp(self): - super(DashboardTestsWithSiteOverrides, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.org = 'fakeX' self.course = CourseFactory.create(org=self.org) self.user = UserFactory.create(username='jack', email='jack@fake.edx.org', password='test') @@ -541,7 +540,7 @@ class UserSettingsEventTestMixin(EventTestMixin): Mixin for verifying that user setting events were emitted during a test. """ def setUp(self): # lint-amnesty, pylint: disable=arguments-differ - super(UserSettingsEventTestMixin, self).setUp('common.djangoapps.util.model_utils.tracker') # lint-amnesty, pylint: disable=super-with-arguments + super().setUp('common.djangoapps.util.model_utils.tracker') def assert_user_setting_event_emitted(self, **kwargs): """ @@ -568,7 +567,7 @@ class UserSettingsEventTestMixin(EventTestMixin): class EnrollmentEventTestMixin(EventTestMixin): """ Mixin with assertions for validating enrollment events. """ def setUp(self): # lint-amnesty, pylint: disable=arguments-differ - super(EnrollmentEventTestMixin, self).setUp('common.djangoapps.student.models.tracker') # lint-amnesty, pylint: disable=super-with-arguments + super().setUp('common.djangoapps.student.models.tracker') def assert_enrollment_mode_change_event_was_emitted(self, user, course_key, mode): """Ensures an enrollment mode change event was emitted""" @@ -794,7 +793,7 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase): """Tests the student.views.change_enrollment view""" def setUp(self): - super(ChangeEnrollmentViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.user = UserFactory.create(password='secret') self.client.login(username=self.user.username, password='secret') @@ -836,7 +835,7 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase): Tests that a student that is a currently enrolled verified student cannot accidentally change their enrollment mode """ - CourseEnrollment.enroll(self.user, self.course.id, mode=u'verified') + CourseEnrollment.enroll(self.user, self.course.id, mode='verified') assert CourseEnrollment.is_enrolled(self.user, self.course.id) # now try to enroll the student in the default mode: response = self._enroll_through_view(self.course) @@ -845,14 +844,14 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase): self.user, self.course.id ) assert is_active - assert enrollment_mode == u'verified' + assert enrollment_mode == 'verified' def test_change_to_default_if_verified_not_active(self): """ Tests that one can renroll for a course if one has already unenrolled """ # enroll student - CourseEnrollment.enroll(self.user, self.course.id, mode=u'verified') + CourseEnrollment.enroll(self.user, self.course.id, mode='verified') # now unenroll student: CourseEnrollment.unenroll(self.user, self.course.id) # check that they are verified but inactive @@ -860,7 +859,7 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase): self.user, self.course.id ) assert not is_active - assert enrollment_mode == u'verified' + assert enrollment_mode == 'verified' # now enroll them through the view: response = self._enroll_through_view(self.course) assert response.status_code == 200 @@ -876,7 +875,7 @@ class AnonymousLookupTable(ModuleStoreTestCase): Tests for anonymous_id_functions """ def setUp(self): - super(AnonymousLookupTable, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.user = UserFactory.create() CourseModeFactory.create( @@ -916,7 +915,7 @@ class AnonymousLookupTable(ModuleStoreTestCase): assert anonymous_id == anonymous_id_for_user(self.user, self.course.id) def test_roundtrip_with_unicode_course_id(self): - course2 = CourseFactory.create(display_name=u"Omega Course Ω") + course2 = CourseFactory.create(display_name="Omega Course Ω") CourseEnrollment.enroll(self.user, course2.id) anonymous_id = anonymous_id_for_user(self.user, course2.id) real_user = user_by_anonymous_id(anonymous_id) @@ -958,14 +957,14 @@ class RelatedProgramsTests(ProgramsApiConfigMixin, SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(RelatedProgramsTests, cls).setUpClass() + super().setUpClass() cls.user = UserFactory() cls.course = CourseFactory() cls.enrollment = CourseEnrollmentFactory(user=cls.user, course_id=cls.course.id) # pylint: disable=no-member def setUp(self): - super(RelatedProgramsTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('dashboard') @@ -987,7 +986,7 @@ class RelatedProgramsTests(ProgramsApiConfigMixin, SharedModuleStoreTestCase): def expected_link_text(self, program): """Construct expected dashboard link text.""" - return u'{title} {type}'.format(title=program['title'], type=program['type']) + return '{title} {type}'.format(title=program['title'], type=program['type']) def test_related_programs_listed(self, mock_get_programs): """Verify that related programs are listed when available.""" @@ -1019,7 +1018,7 @@ class RelatedProgramsTests(ProgramsApiConfigMixin, SharedModuleStoreTestCase): def test_program_title_unicode(self, mock_get_programs): """Verify that the dashboard can deal with programs whose titles contain Unicode.""" - self.programs[0]['title'] = u'Bases matemáticas para estudiar ingeniería' + self.programs[0]['title'] = 'Bases matemáticas para estudiar ingeniería' mock_get_programs.return_value = self.programs response = self.client.get(self.url) @@ -1030,7 +1029,7 @@ class UserAttributeTests(TestCase): """Tests for the UserAttribute model.""" def setUp(self): - super(UserAttributeTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory() self.name = 'test' self.value = 'test-value' diff --git a/common/djangoapps/student/urls.py b/common/djangoapps/student/urls.py index 3b42642013..aafac7b1dd 100644 --- a/common/djangoapps/student/urls.py +++ b/common/djangoapps/student/urls.py @@ -19,7 +19,7 @@ urlpatterns = [ url(r'^change_email_settings$', views.change_email_settings, name='change_email_settings'), - url(r'^course_run/{}/refund_status$'.format(settings.COURSE_ID_PATTERN), + url(fr'^course_run/{settings.COURSE_ID_PATTERN}/refund_status$', views.course_run_refund_status, name="course_run_refund_status"), diff --git a/common/djangoapps/student/views/dashboard.py b/common/djangoapps/student/views/dashboard.py index ba01a6dab2..64a01fffbe 100644 --- a/common/djangoapps/student/views/dashboard.py +++ b/common/djangoapps/student/views/dashboard.py @@ -62,7 +62,7 @@ from xmodule.modulestore.django import modulestore log = logging.getLogger("edx.student") -experiments_namespace = LegacyWaffleFlagNamespace(name=u'student.experiments') +experiments_namespace = LegacyWaffleFlagNamespace(name='student.experiments') def get_org_black_and_whitelist_for_site(): @@ -402,10 +402,10 @@ def _credit_statuses(user, course_enrollments): statuses = {} for eligibility in credit_api.get_eligibilities_for_user(user.username): - course_key = CourseKey.from_string(text_type(eligibility["course_key"])) + course_key = CourseKey.from_string(str(eligibility["course_key"])) providers_names = get_credit_provider_attribute_values(course_key, 'display_name') status = { - "course_key": text_type(course_key), + "course_key": str(course_key), "eligible": True, "deadline": eligibility["deadline"], "purchased": course_key in credit_enrollments, @@ -425,10 +425,10 @@ def _credit_statuses(user, course_enrollments): if provider_id is None: status["error"] = True log.error( - u"Could not find credit provider associated with credit enrollment " - u"for user %s in course %s. The user will not be able to see their " - u"credit request status on the student dashboard. This attribute should " - u"have been set when the user purchased credit in the course.", + "Could not find credit provider associated with credit enrollment " + "for user %s in course %s. The user will not be able to see their " + "credit request status on the student dashboard. This attribute should " + "have been set when the user purchased credit in the course.", user.id, course_key ) else: @@ -440,8 +440,8 @@ def _credit_statuses(user, course_enrollments): if not status["provider_name"] and not status["provider_status_url"]: status["error"] = True log.error( - u"Could not find credit provider info for [%s] in [%s]. The user will not " - u"be able to see their credit request status on the student dashboard.", + "Could not find credit provider info for [%s] in [%s]. The user will not " + "be able to see their credit request status on the student dashboard.", provider_id, provider_info_by_id ) @@ -548,7 +548,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem mode.slug: mode for mode in modes } - for course_id, modes in iteritems(unexpired_course_modes) + for course_id, modes in unexpired_course_modes.items() } # Check to see if the student has recently enrolled in a course. @@ -638,7 +638,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem inverted_programs = meter.invert_programs() urls, programs_data = {}, {} - bundles_on_dashboard_flag = LegacyWaffleFlag(experiments_namespace, u'bundles_on_dashboard', __name__) + bundles_on_dashboard_flag = LegacyWaffleFlag(experiments_namespace, 'bundles_on_dashboard', __name__) # TODO: Delete this code and the relevant HTML code after testing LEARNER-3072 is complete if bundles_on_dashboard_flag.is_enabled() and inverted_programs and list(inverted_programs.items()): diff --git a/common/djangoapps/student/views/management.py b/common/djangoapps/student/views/management.py index 1f873df1f7..bbca629e83 100644 --- a/common/djangoapps/student/views/management.py +++ b/common/djangoapps/student/views/management.py @@ -104,7 +104,7 @@ def csrf_token(context): token = context.get('csrf_token', '') if token == 'NOTPROVIDED': return '' - return (HTML(u'
').format(Text(token))) @@ -241,7 +241,7 @@ def course_run_refund_status(request, course_id): return JsonResponse({'course_refundable_status': ''}, status=406) refundable_status = course_enrollment.refundable() - logging.info("Course refund status for course {0} is {1}".format(course_id, refundable_status)) + logging.info(f"Course refund status for course {course_id} is {refundable_status}") return JsonResponse({'course_refundable_status': refundable_status}, status=200) @@ -308,7 +308,7 @@ def change_enrollment(request, check_access=True): course_id = CourseKey.from_string(request.POST.get("course_id")) except InvalidKeyError: log.warning( - u"User %s tried to %s with invalid course id: %s", + "User %s tried to %s with invalid course id: %s", user.username, action, request.POST.get("course_id"), @@ -317,14 +317,14 @@ def change_enrollment(request, check_access=True): # Allow us to monitor performance of this transaction on a per-course basis since we often roll-out features # on a per-course basis. - monitoring_utils.set_custom_attribute('course_id', text_type(course_id)) + monitoring_utils.set_custom_attribute('course_id', str(course_id)) if action == "enroll": # Make sure the course exists # We don't do this check on unenroll, or a bad course id can't be unenrolled from if not modulestore().has_course(course_id): log.warning( - u"User %s tried to enroll in non-existent course %s", + "User %s tried to enroll in non-existent course %s", user.username, course_id ) @@ -348,7 +348,7 @@ def change_enrollment(request, check_access=True): return HttpResponse(redirect_url) if CourseEntitlement.check_for_existing_entitlement_and_enroll(user=user, course_run_key=course_id): - return HttpResponse(reverse('courseware', args=[six.text_type(course_id)])) + return HttpResponse(reverse('courseware', args=[str(course_id)])) # Check that auto enrollment is allowed for this course # (= the course is NOT behind a paywall) @@ -372,7 +372,7 @@ def change_enrollment(request, check_access=True): # funnels users directly into the verification / payment flow) if CourseMode.has_verified_mode(available_modes) or CourseMode.has_professional_mode(available_modes): return HttpResponse( - reverse("course_modes_choose", kwargs={'course_id': text_type(course_id)}) + reverse("course_modes_choose", kwargs={'course_id': str(course_id)}) ) # Otherwise, there is only one mode available (the default) @@ -454,11 +454,11 @@ def disable_account_ajax(request): if account_action == 'disable': user_account.account_status = UserStanding.ACCOUNT_DISABLED context['message'] = _("Successfully disabled {}'s account").format(username) - log.info(u"%s disabled %s's account", request.user, username) + log.info("%s disabled %s's account", request.user, username) elif account_action == 'reenable': user_account.account_status = UserStanding.ACCOUNT_ENABLED context['message'] = _("Successfully reenabled {}'s account").format(username) - log.info(u"%s reenabled %s's account", request.user, username) + log.info("%s reenabled %s's account", request.user, username) else: context['message'] = _("Unexpected account status") return JsonResponse(context, status=400) @@ -479,7 +479,7 @@ def user_signup_handler(sender, **kwargs): # pylint: disable=unused-argument if site: user_signup_source = UserSignupSource(user=kwargs['instance'], site=site) user_signup_source.save() - log.info(u'user {} originated from a white labeled "Microsite"'.format(kwargs['instance'].id)) + log.info('user {} originated from a white labeled "Microsite"'.format(kwargs['instance'].id)) @ensure_csrf_cookie @@ -488,7 +488,7 @@ def activate_account(request, key): When link in activation e-mail is clicked """ # If request is in Studio call the appropriate view - if theming_helpers.get_project_root_name().lower() == u'cms': + if theming_helpers.get_project_root_name().lower() == 'cms': monitoring_utils.set_custom_attribute('student_activate_account', 'cms') return activate_account_studio(request, key) @@ -558,7 +558,7 @@ def activate_account(request, key): ) if should_redirect_to_authn_microfrontend() and not request.user.is_authenticated: - url_path = '/login?account_activation_status={}'.format(activation_message_type) + url_path = f'/login?account_activation_status={activation_message_type}' return redirect(settings.AUTHN_MICROFRONTEND_URL + url_path) return redirect('dashboard') @@ -692,7 +692,7 @@ def do_email_change_request(user, new_email, activation_key=None, secondary_emai ace.send(msg) except Exception: from_address = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL) - log.error(u'Unable to send email activation link to user from "%s"', from_address, exc_info=True) + log.error('Unable to send email activation link to user from "%s"', from_address, exc_info=True) raise ValueError(_('Unable to send email activation link. Please try again later.')) # lint-amnesty, pylint: disable=raise-missing-from if not secondary_email_change_request: @@ -838,7 +838,7 @@ def change_email_settings(request): if optout_object: optout_object.delete() log.info( - u"User %s (%s) opted in to receive emails from course %s", + "User %s (%s) opted in to receive emails from course %s", user.username, user.email, course_id, @@ -852,7 +852,7 @@ def change_email_settings(request): else: Optout.objects.get_or_create(user=user, course_id=course_key) log.info( - u"User %s (%s) opted out of receiving emails from course %s", + "User %s (%s) opted out of receiving emails from course %s", user.username, user.email, course_id,