diff --git a/openedx/core/djangoapps/user_authn/api/tests/test_views.py b/openedx/core/djangoapps/user_authn/api/tests/test_views.py index 4e9df02788..f270398ba7 100644 --- a/openedx/core/djangoapps/user_authn/api/tests/test_views.py +++ b/openedx/core/djangoapps/user_authn/api/tests/test_views.py @@ -1,12 +1,12 @@ """ Logistration API View Tests """ +from unittest.mock import patch +from urllib.parse import urlencode import ddt from django.conf import settings from django.urls import reverse -from mock import patch from rest_framework.test import APITestCase -from six.moves.urllib.parse import urlencode from openedx.core.djangolib.testing.utils import skip_unless_lms from common.djangoapps.third_party_auth import pipeline @@ -24,7 +24,7 @@ class TPAContextViewTest(ThirdPartyAuthTestMixin, APITestCase): """ Test Setup """ - super(TPAContextViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('third_party_auth_context') self.query_params = {'next': '/dashboard'} @@ -42,7 +42,7 @@ class TPAContextViewTest(ThirdPartyAuthTestMixin, APITestCase): """ Construct the login URL to start third party authentication """ - return u'{url}?auth_entry={auth_entry}&{param_str}'.format( + return '{url}?auth_entry={auth_entry}&{param_str}'.format( url=reverse('social:begin', kwargs={'backend': backend_name}), auth_entry=auth_entry, param_str=urlencode(params) diff --git a/openedx/core/djangoapps/user_authn/apps.py b/openedx/core/djangoapps/user_authn/apps.py index 7e37633626..465e7f7820 100644 --- a/openedx/core/djangoapps/user_authn/apps.py +++ b/openedx/core/djangoapps/user_authn/apps.py @@ -12,14 +12,14 @@ class UserAuthnConfig(AppConfig): """ Application Configuration for User Authentication. """ - name = u'openedx.core.djangoapps.user_authn' + name = 'openedx.core.djangoapps.user_authn' plugin_app = { PluginURLs.CONFIG: { ProjectType.LMS: { - PluginURLs.NAMESPACE: u'', - PluginURLs.REGEX: u'', - PluginURLs.RELATIVE_PATH: u'urls', + PluginURLs.NAMESPACE: '', + PluginURLs.REGEX: '', + PluginURLs.RELATIVE_PATH: 'urls', }, }, } diff --git a/openedx/core/djangoapps/user_authn/config/waffle.py b/openedx/core/djangoapps/user_authn/config/waffle.py index 15edcd85a1..030b9ef412 100644 --- a/openedx/core/djangoapps/user_authn/config/waffle.py +++ b/openedx/core/djangoapps/user_authn/config/waffle.py @@ -5,8 +5,8 @@ Waffle flags and switches for user authn. from edx_toggles.toggles import LegacyWaffleSwitch, LegacyWaffleSwitchNamespace -_WAFFLE_NAMESPACE = u'user_authn' -_WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name=_WAFFLE_NAMESPACE, log_prefix=u'UserAuthN: ') +_WAFFLE_NAMESPACE = 'user_authn' +_WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name=_WAFFLE_NAMESPACE, log_prefix='UserAuthN: ') # .. toggle_name: user_authn.enable_login_using_thirdparty_auth_only # .. toggle_implementation: WaffleSwitch diff --git a/openedx/core/djangoapps/user_authn/cookies.py b/openedx/core/djangoapps/user_authn/cookies.py index 1c766726e9..429c553b87 100644 --- a/openedx/core/djangoapps/user_authn/cookies.py +++ b/openedx/core/djangoapps/user_authn/cookies.py @@ -7,7 +7,6 @@ import json import logging import time -import six from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.dispatch import Signal @@ -223,7 +222,7 @@ def _set_deprecated_logged_in_cookie(response, cookie_settings): def _convert_to_absolute_uris(request, urls_obj): """ Convert relative URL paths to absolute URIs """ - for url_name, url_path in six.iteritems(urls_obj): + for url_name, url_path in urls_obj.items(): urls_obj[url_name] = request.build_absolute_uri(url_path) return urls_obj @@ -350,5 +349,5 @@ def _get_login_oauth_client(): return Application.objects.get(client_id=login_client_id) except Application.DoesNotExist: raise AuthFailedError( # lint-amnesty, pylint: disable=raise-missing-from - u"OAuth Client for the Login service, '{}', is not configured.".format(login_client_id) + f"OAuth Client for the Login service, '{login_client_id}', is not configured." ) diff --git a/openedx/core/djangoapps/user_authn/exceptions.py b/openedx/core/djangoapps/user_authn/exceptions.py index 4dc1f25276..6ce80aa1cb 100644 --- a/openedx/core/djangoapps/user_authn/exceptions.py +++ b/openedx/core/djangoapps/user_authn/exceptions.py @@ -12,7 +12,7 @@ class AuthFailedError(Exception): def __init__( # lint-amnesty, pylint: disable=dangerous-default-value self, value=None, redirect=None, redirect_url=None, error_code=None, context={}, ): - super(AuthFailedError, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() self.value = Text(value) self.redirect = redirect self.redirect_url = redirect_url diff --git a/openedx/core/djangoapps/user_authn/message_types.py b/openedx/core/djangoapps/user_authn/message_types.py index 0688881a61..83391374a1 100644 --- a/openedx/core/djangoapps/user_authn/message_types.py +++ b/openedx/core/djangoapps/user_authn/message_types.py @@ -10,7 +10,7 @@ class PasswordReset(BaseMessageType): A message to the user with password reset link. """ def __init__(self, *args, **kwargs): - super(PasswordReset, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) # pylint: disable=unsupported-assignment-operation self.options['transactional'] = True @@ -22,5 +22,5 @@ class PasswordResetSuccess(BaseMessageType): """ def __init__(self, *args, **kwargs): - super(PasswordResetSuccess, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) self.options['transactional'] = True diff --git a/openedx/core/djangoapps/user_authn/migrations/0001_data__add_login_service.py b/openedx/core/djangoapps/user_authn/migrations/0001_data__add_login_service.py index d17f2ea75b..f36a4567d5 100644 --- a/openedx/core/djangoapps/user_authn/migrations/0001_data__add_login_service.py +++ b/openedx/core/djangoapps/user_authn/migrations/0001_data__add_login_service.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.conf import settings from django.db import migrations diff --git a/openedx/core/djangoapps/user_authn/tests/test_cookies.py b/openedx/core/djangoapps/user_authn/tests/test_cookies.py index 1eea0163f6..ad9808069f 100644 --- a/openedx/core/djangoapps/user_authn/tests/test_cookies.py +++ b/openedx/core/djangoapps/user_authn/tests/test_cookies.py @@ -3,14 +3,13 @@ from datetime import date import json -import six +from unittest.mock import MagicMock, patch from django.conf import settings from django.http import HttpResponse from django.test import RequestFactory, TestCase from django.urls import reverse from edx_rest_framework_extensions.auth.jwt.decoder import jwt_decode_handler from edx_rest_framework_extensions.auth.jwt.middleware import JwtAuthCookieMiddleware -from mock import MagicMock, patch from openedx.core.djangoapps.user_api.accounts.utils import retrieve_last_sitewide_block_completed from openedx.core.djangoapps.user_authn import cookies as cookies_api @@ -24,7 +23,7 @@ from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_ class CookieTests(TestCase): def setUp(self): - super(CookieTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() self.user.profile = UserProfileFactory.create(user=self.user) self.request = RequestFactory().get('/') @@ -38,7 +37,7 @@ class CookieTests(TestCase): def _convert_to_absolute_uris(self, request, urls_obj): """ Convert relative URL paths to absolute URIs """ - for url_name, url_path in six.iteritems(urls_obj): + for url_name, url_path in urls_obj.items(): urls_obj[url_name] = request.build_absolute_uri(url_path) return urls_obj @@ -70,7 +69,7 @@ class CookieTests(TestCase): def _copy_cookies_to_request(self, response, request): request.COOKIES = { key: val.value - for key, val in six.iteritems(response.cookies) + for key, val in response.cookies.items() } def _set_use_jwt_cookie_header(self, request): diff --git a/openedx/core/djangoapps/user_authn/tests/test_utils.py b/openedx/core/djangoapps/user_authn/tests/test_utils.py index 95551a6d88..9ce0797c97 100644 --- a/openedx/core/djangoapps/user_authn/tests/test_utils.py +++ b/openedx/core/djangoapps/user_authn/tests/test_utils.py @@ -2,12 +2,12 @@ from collections import namedtuple +from urllib.parse import urlencode # pylint: disable=import-error import pytest import ddt from django.test import TestCase from django.test.client import RequestFactory from django.test.utils import override_settings -from six.moves.urllib.parse import urlencode # pylint: disable=import-error from openedx.core.djangoapps.oauth_dispatch.tests.factories import ApplicationFactory from openedx.core.djangoapps.user_authn.utils import ( @@ -20,7 +20,7 @@ class TestRedirectUtils(TestCase): """Test redirect utility methods.""" def setUp(self): - super(TestRedirectUtils, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.request = RequestFactory() RedirectCase = namedtuple('RedirectCase', ['url', 'host', 'req_is_secure', 'expected_is_safe']) @@ -79,8 +79,8 @@ class GeneratePasswordTest(TestCase): def test_default_args(self): password = generate_password() assert 12 == len(password) - assert any((c.isdigit for c in password)) - assert any((c.isalpha for c in password)) + assert any(c.isdigit for c in password) + assert any(c.isalpha for c in password) def test_length(self): length = 25 @@ -90,8 +90,8 @@ class GeneratePasswordTest(TestCase): char = '!' password = generate_password(length=12, chars=(char,)) - assert any((c.isdigit for c in password)) - assert any((c.isalpha for c in password)) + assert any(c.isdigit for c in password) + assert any(c.isalpha for c in password) assert (char * 10) == password[2:] def test_min_length(self): diff --git a/openedx/core/djangoapps/user_authn/tests/utils.py b/openedx/core/djangoapps/user_authn/tests/utils.py index 42aac2552c..4b002eef31 100644 --- a/openedx/core/djangoapps/user_authn/tests/utils.py +++ b/openedx/core/djangoapps/user_authn/tests/utils.py @@ -3,11 +3,11 @@ from datetime import datetime, timedelta from enum import Enum +from unittest.mock import patch import ddt import pytz from django.conf import settings -from mock import patch from oauth2_provider import models as dot_models from rest_framework import status @@ -46,7 +46,7 @@ def utcnow(): @ddt.ddt -class AuthAndScopesTestMixin(object): +class AuthAndScopesTestMixin: """ Mixin class to test authentication and oauth scopes for an API. Test classes that use this Mixin need to define: @@ -61,7 +61,7 @@ class AuthAndScopesTestMixin(object): user_password = 'test' def setUp(self): - super(AuthAndScopesTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory.create(password=self.user_password) self.other_student = UserFactory.create(password=self.user_password) self.global_staff = UserFactory.create(password=self.user_password, is_staff=True) @@ -84,12 +84,12 @@ class AuthAndScopesTestMixin(object): elif auth_type == AuthType.oauth: if not token: token = self._create_oauth_token(requesting_user) - auth_header = u"Bearer {0}".format(token) + auth_header = f"Bearer {token}" else: assert auth_type in JWT_AUTH_TYPES if not token: token = self._create_jwt_token(requesting_user, auth_type) - auth_header = u"JWT {0}".format(token) + auth_header = f"JWT {token}" extra = dict(HTTP_AUTHORIZATION=auth_header) if auth_header else {} return self.client.get( @@ -119,7 +119,7 @@ class AuthAndScopesTestMixin(object): """ Creates and returns a JWT token for the given user with the given parameters. """ filters = [] if include_org_filter: - filters += ['content_org:{}'.format(self.course.id.org)] + filters += [f'content_org:{self.course.id.org}'] if include_me_filter: filters += ['user:me'] diff --git a/openedx/core/djangoapps/user_authn/utils.py b/openedx/core/djangoapps/user_authn/utils.py index 2bf24cd81e..2774b9a965 100644 --- a/openedx/core/djangoapps/user_authn/utils.py +++ b/openedx/core/djangoapps/user_authn/utils.py @@ -4,11 +4,11 @@ Utility functions used during user authentication. import random import string +from urllib.parse import urlparse # pylint: disable=import-error from django.conf import settings from django.utils import http from oauth2_provider.models import Application -from six.moves.urllib.parse import urlparse # pylint: disable=import-error from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # lint-amnesty, pylint: disable=unused-import diff --git a/openedx/core/djangoapps/user_authn/views/login.py b/openedx/core/djangoapps/user_authn/views/login.py index 8917d5f400..9d47e2bc7e 100644 --- a/openedx/core/djangoapps/user_authn/views/login.py +++ b/openedx/core/djangoapps/user_authn/views/login.py @@ -8,8 +8,8 @@ import json import logging import hashlib import re +import urllib -import six from django.conf import settings from django.contrib.auth import authenticate from django.contrib.auth import login as django_login @@ -71,17 +71,17 @@ def _do_third_party_auth(request): return pipeline.get_authenticated_user(requested_provider, username, third_party_uid) except User.DoesNotExist: AUDIT_LOG.info( - u"Login failed - user with username {username} has no social auth " - u"with backend_name {backend_name}".format( + "Login failed - user with username {username} has no social auth " + "with backend_name {backend_name}".format( username=username, backend_name=backend_name) ) message = Text(_( - u"You've successfully signed in to your {provider_name} account, " - u"but this account isn't linked with your {platform_name} account yet. {blank_lines}" - u"Use your {platform_name} username and password to sign in to {platform_name} below, " - u"and then link your {platform_name} account with {provider_name} from your dashboard. {blank_lines}" - u"If you don't have an account on {platform_name} yet, " - u"click {register_label_strong} at the top of the page." + "You've successfully signed in to your {provider_name} account, " + "but this account isn't linked with your {platform_name} account yet. {blank_lines}" + "Use your {platform_name} username and password to sign in to {platform_name} below, " + "and then link your {platform_name} account with {provider_name} from your dashboard. {blank_lines}" + "If you don't have an account on {platform_name} yet, " + "click {register_label_strong} at the top of the page." )).format( blank_lines=HTML('

'), platform_name=platform_name, @@ -149,12 +149,12 @@ def _enforce_password_policy_compliance(request, user): # lint-amnesty, pylint: password_policy_compliance.enforce_compliance_on_login(user, request.POST.get('password')) except password_policy_compliance.NonCompliantPasswordWarning as e: # Allow login, but warn the user that they will be required to reset their password soon. - PageLevelMessages.register_warning_message(request, six.text_type(e)) + PageLevelMessages.register_warning_message(request, str(e)) except password_policy_compliance.NonCompliantPasswordException as e: AUDIT_LOG.info("Password reset initiated for email %s.", user.email) send_password_reset_email_for_user(user, request) # Prevent the login attempt. - raise AuthFailedError(HTML(six.text_type(e)), error_code=e.__class__.__name__) # lint-amnesty, pylint: disable=raise-missing-from + raise AuthFailedError(HTML(str(e)), error_code=e.__class__.__name__) # lint-amnesty, pylint: disable=raise-missing-from def _log_and_raise_inactive_user_auth_error(unauthenticated_user): @@ -309,8 +309,8 @@ def _create_message(site, root_url, allowed_domain): through allowed domain SSO provider. """ msg = Text(_( - u'As {allowed_domain} user, You must login with your {allowed_domain} ' - u'{link_start}{provider} account{link_end}.' + 'As {allowed_domain} user, You must login with your {allowed_domain} ' + '{link_start}{provider} account{link_end}.' )).format( allowed_domain=allowed_domain, link_start=HTML("").format( @@ -404,7 +404,7 @@ def enterprise_selection_page(request, user, next_url): # Check to see if next url has an enterprise in it. In this case if user is associated with # that enterprise, activate that enterprise and bypass the selection page. - if re.match(ENTERPRISE_ENROLLMENT_URL_REGEX, six.moves.urllib.parse.unquote(next_url)): + if re.match(ENTERPRISE_ENROLLMENT_URL_REGEX, urllib.parse.unquote(next_url)): enterprise_in_url = re.search(UUID4_REGEX, next_url).group(0) for enterprise in response: if enterprise_in_url == str(enterprise['enterprise_customer']['uuid']): @@ -614,7 +614,7 @@ class LoginSessionView(APIView): @method_decorator(sensitive_post_parameters("password")) def dispatch(self, request, *args, **kwargs): - return super(LoginSessionView, self).dispatch(request, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().dispatch(request, *args, **kwargs) def _parse_analytics_param_for_course_id(request): @@ -642,7 +642,7 @@ def _parse_analytics_param_for_course_id(request): except (ValueError, TypeError): set_custom_attribute('shim_analytics_course_id', 'parse-error') log.error( - u"Could not parse analytics object sent to user API: {analytics}".format( + "Could not parse analytics object sent to user API: {analytics}".format( analytics=analytics ) ) diff --git a/openedx/core/djangoapps/user_authn/views/login_form.py b/openedx/core/djangoapps/user_authn/views/login_form.py index 2b851d49ab..66c4dc8812 100644 --- a/openedx/core/djangoapps/user_authn/views/login_form.py +++ b/openedx/core/djangoapps/user_authn/views/login_form.py @@ -3,8 +3,8 @@ import json import logging +import urllib -import six from django.conf import settings from django.contrib import messages from django.shortcuts import redirect @@ -115,7 +115,7 @@ def get_login_session_form(request): # Translators: This label appears above a field on the login form # meant to hold the user's password. - password_label = _(u"Password") + password_label = _("Password") form_desc.add_field( "password", @@ -166,7 +166,7 @@ def login_and_registration_form(request, initial_mode="login"): third_party_auth_hint = None if '?' in redirect_to: # lint-amnesty, pylint: disable=too-many-nested-blocks try: - next_args = six.moves.urllib.parse.parse_qs(six.moves.urllib.parse.urlparse(redirect_to).query) + next_args = urllib.parse.parse_qs(urllib.parse.urlparse(redirect_to).query) if 'tpa_hint' in next_args: provider_id = next_args['tpa_hint'][0] tpa_hint_provider = third_party_auth.provider.Registry.get(provider_id=provider_id) @@ -184,7 +184,7 @@ def login_and_registration_form(request, initial_mode="login"): third_party_auth_hint = provider_id initial_mode = "hinted_login" except (KeyError, ValueError, IndexError) as ex: - log.exception(u"Unknown tpa_hint provider: %s", ex) + log.exception("Unknown tpa_hint provider: %s", ex) # Redirect to authn MFE if it is enabled or user is not an enterprise user or not coming from a SAML IDP. saml_provider = False diff --git a/openedx/core/djangoapps/user_authn/views/logout.py b/openedx/core/djangoapps/user_authn/views/logout.py index 1012b2edb9..bbbbdae7ce 100644 --- a/openedx/core/djangoapps/user_authn/views/logout.py +++ b/openedx/core/djangoapps/user_authn/views/logout.py @@ -2,14 +2,14 @@ import re +import urllib.parse as parse # pylint: disable=import-error +from urllib.parse import parse_qs, urlsplit, urlunsplit # pylint: disable=import-error -import six.moves.urllib.parse as parse # pylint: disable=import-error from django.conf import settings from django.contrib.auth import logout from django.utils.http import urlencode from django.views.generic import TemplateView from oauth2_provider.models import Application -from six.moves.urllib.parse import parse_qs, urlsplit, urlunsplit # pylint: disable=import-error from openedx.core.djangoapps.user_authn.cookies import delete_logged_in_cookies from openedx.core.djangoapps.user_authn.utils import is_safe_login_or_logout_redirect @@ -76,7 +76,7 @@ class LogoutView(TemplateView): logout(request) - response = super(LogoutView, self).dispatch(request, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + response = super().dispatch(request, *args, **kwargs) # Clear the cookie used by the edx.org marketing site delete_logged_in_cookies(response) @@ -123,7 +123,7 @@ class LogoutView(TemplateView): return False def get_context_data(self, **kwargs): - context = super(LogoutView, self).get_context_data(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + context = super().get_context_data(**kwargs) # Create a list of URIs that must be called to log the user out of all of the IDAs. uris = [] diff --git a/openedx/core/djangoapps/user_authn/views/password_reset.py b/openedx/core/djangoapps/user_authn/views/password_reset.py index cdbd0f057d..894fc8adfd 100644 --- a/openedx/core/djangoapps/user_authn/views/password_reset.py +++ b/openedx/core/djangoapps/user_authn/views/password_reset.py @@ -85,16 +85,16 @@ def get_password_reset_form(): # Translators: This label appears above a field on the password reset # form meant to hold the user's email address. - email_label = _(u"Email") + email_label = _("Email") # Translators: This example email address is used as a placeholder in # a field on the password reset form meant to hold the user's email address. - email_placeholder = _(u"username@domain.com") + email_placeholder = _("username@domain.com") # Translators: These instructions appear on the password reset form, # immediately below a field meant to hold the user's email address. # pylint: disable=no-member - email_instructions = _(u"The email address you used to register with {platform_name}").format( + email_instructions = _("The email address you used to register with {platform_name}").format( platform_name=configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME) ) @@ -124,7 +124,7 @@ def send_password_reset_success_email(user, request): message_context, user_language_preference = get_user_default_email_params(user) lms_root_url = configuration_helpers.get_value('LMS_ROOT_URL', settings.LMS_ROOT_URL) message_context.update( - {'login_link': '{}/login'.format(lms_root_url), 'request': request, } + {'login_link': f'{lms_root_url}/login', 'request': request, } ) msg = PasswordResetSuccess(context=message_context).personalize( @@ -392,8 +392,7 @@ class PasswordResetConfirmWrapper(PasswordResetConfirmView): except (ValueError, User.DoesNotExist): # if there's any error getting a user, just let django's # password_reset_confirm function handle it. - return super(PasswordResetConfirmWrapper, self).dispatch(request, uidb64=self.uidb64, token=self.token, # lint-amnesty, pylint: disable=super-with-arguments - extra_context=self.platform_name) + return super().dispatch(request, uidb64=self.uidb64, token=self.token, extra_context=self.platform_name) def _handle_retired_user(self, request): """ @@ -430,8 +429,8 @@ class PasswordResetConfirmWrapper(PasswordResetConfirmView): form_valid = response.context_data['form'].is_valid() if response.context_data['form'] else False if not form_valid: log.warning( - u'Unable to reset password for user [%s] because form is not valid. ' - u'A possible cause is that the user had an invalid reset token', + 'Unable to reset password for user [%s] because form is not valid. ' + 'A possible cause is that the user had an invalid reset token', self.user.username, ) response.context_data['err_msg'] = _('Error in resetting your password. Please try again.') @@ -459,8 +458,8 @@ class PasswordResetConfirmWrapper(PasswordResetConfirmView): messages.success( request, HTML(_( - u'{html_start}Password Creation Complete{html_end}' - u'Your password has been created. {bold_start}{email}{bold_end} is now your primary login email.' + '{html_start}Password Creation Complete{html_end}' + 'Your password has been created. {bold_start}{email}{bold_end} is now your primary login email.' )).format( support_url=configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK), html_start=HTML('

'), @@ -532,7 +531,7 @@ class PasswordResetConfirmWrapper(PasswordResetConfirmView): self.token = self._get_token_from_session(self.request) return self.post(self.request, *args, **kwargs) else: - response = super(PasswordResetConfirmWrapper, self).dispatch( # lint-amnesty, pylint: disable=super-with-arguments + response = super().dispatch( self.request, uidb64=self.uidb64, token=self.token, @@ -634,7 +633,7 @@ def password_change_request_handler(request): ) ace.send(msg) except errors.UserAPIInternalError as err: - log.exception(u'Error occured during password change for user {email}: {error}' + log.exception('Error occured during password change for user {email}: {error}' .format(email=email, error=err)) return HttpResponse(_("Some error occured during password change. Please try again"), status=500) diff --git a/openedx/core/djangoapps/user_authn/views/register.py b/openedx/core/djangoapps/user_authn/views/register.py index 322b0866e6..c97f973af8 100644 --- a/openedx/core/djangoapps/user_authn/views/register.py +++ b/openedx/core/djangoapps/user_authn/views/register.py @@ -28,7 +28,6 @@ from ratelimit.decorators import ratelimit from requests import HTTPError from rest_framework.response import Response from rest_framework.views import APIView -from six import text_type from social_core.exceptions import AuthAlreadyAssociated, AuthException from social_django import utils as social_utils @@ -106,8 +105,8 @@ REGISTER_USER = Signal(providing_args=["user", "registration"]) # .. toggle_target_removal_date: 2020-06-01 # .. toggle_warnings: This temporary feature toggle does not have a target removal date. REGISTRATION_FAILURE_LOGGING_FLAG = LegacyWaffleFlag( - waffle_namespace=LegacyWaffleFlagNamespace(name=u'registration'), - flag_name=u'enable_failure_logging', + waffle_namespace=LegacyWaffleFlagNamespace(name='registration'), + flag_name='enable_failure_logging', module_name=__name__, ) REAL_IP_KEY = 'openedx.core.djangoapps.util.ratelimit.real_ip' @@ -179,7 +178,7 @@ def create_account_with_params(request, params): raise ValidationError( { 'session_expired': [ - _(u"Registration using {provider} has timed out.").format( + _("Registration using {provider} has timed out.").format( provider=params.get('social_auth_provider')) ], 'error_code': 'tpa-session-expired', @@ -240,7 +239,7 @@ def create_account_with_params(request, params): try: enable_notifications(user) except Exception: # pylint: disable=broad-except - log.exception(u"Enable discussion notifications failed for user {id}.".format(id=user.id)) + log.exception(f"Enable discussion notifications failed for user {user.id}.") _track_user_registration(user, profile, params, third_party_provider) @@ -258,7 +257,7 @@ def create_account_with_params(request, params): # TODO: there is no error checking here to see that the user actually logged in successfully, # and is not yet an active user. if new_user is not None: - AUDIT_LOG.info(u"Login success on new account creation - {0}".format(new_user.username)) + AUDIT_LOG.info(f"Login success on new account creation - {new_user.username}") return new_user @@ -287,7 +286,7 @@ def _link_user_to_third_party_provider( if not social_access_token: raise ValidationError({ 'access_token': [ - _(u"An access_token is required when passing value ({}) for provider.").format( + _("An access_token is required when passing value ({}) for provider.").format( params['provider'] ) ], @@ -333,7 +332,7 @@ def _track_user_registration(user, profile, params, third_party_provider): 'education': profile.level_of_education_display, 'address': profile.mailing_address, 'gender': profile.gender_display, - 'country': text_type(profile.country), + 'country': str(profile.country), } ] # .. pii: Many pieces of PII are sent to Segment here. Retired directly through Segment API call in Tubular. @@ -409,7 +408,7 @@ def _skip_activation_email(user, running_pipeline, third_party_provider): # log the cases where skip activation email flag is set, but email validity check fails if third_party_provider and third_party_provider.skip_email_verification and not valid_email: log.info( - u'[skip_email_verification=True][user=%s][pipeline-email=%s][identity_provider=%s][provider_type=%s] ' + '[skip_email_verification=True][user=%s][pipeline-email=%s][identity_provider=%s][provider_type=%s] ' 'Account activation email sent as user\'s system email differs from SSO email.', user.email, sso_pipeline_email, @@ -483,7 +482,7 @@ class RegistrationView(APIView): @method_decorator(transaction.non_atomic_requests) @method_decorator(sensitive_post_parameters("password")) def dispatch(self, request, *args, **kwargs): - return super(RegistrationView, self).dispatch(request, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().dispatch(request, *args, **kwargs) @method_decorator(ensure_csrf_cookie) def get(self, request): @@ -573,7 +572,7 @@ class RegistrationView(APIView): user = create_account_with_params(request, data) except AccountValidationError as err: errors = { - err.field: [{"user_message": text_type(err)}] + err.field: [{"user_message": str(err)}] } response = self._create_response(request, errors, status_code=409, error_code=err.error_code) except ValidationError as err: diff --git a/openedx/core/djangoapps/user_authn/views/registration_form.py b/openedx/core/djangoapps/user_authn/views/registration_form.py index 3b7a2869f6..04407171f1 100644 --- a/openedx/core/djangoapps/user_authn/views/registration_form.py +++ b/openedx/core/djangoapps/user_authn/views/registration_form.py @@ -6,8 +6,6 @@ import copy from importlib import import_module import re -import six - from django import forms from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user @@ -69,7 +67,7 @@ def validate_username(username): message = accounts.USERNAME_INVALID_CHARS_ASCII if settings.FEATURES.get("ENABLE_UNICODE_USERNAME"): - username_re = r"^{regex}$".format(regex=settings.USERNAME_REGEX_PARTIAL) + username_re = fr"^{settings.USERNAME_REGEX_PARTIAL}$" flags = re.UNICODE message = accounts.USERNAME_INVALID_CHARS_UNICODE @@ -109,7 +107,7 @@ class UsernameField(forms.CharField): default_validators = [validate_username] def __init__(self, *args, **kwargs): # lint-amnesty, pylint: disable=unused-argument - super(UsernameField, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( min_length=accounts.USERNAME_MIN_LENGTH, max_length=accounts.USERNAME_MAX_LENGTH, error_messages={ @@ -127,7 +125,7 @@ class UsernameField(forms.CharField): """ value = self.to_python(value).strip() - return super(UsernameField, self).clean(value) # lint-amnesty, pylint: disable=super-with-arguments + return super().clean(value) class AccountCreationForm(forms.Form): @@ -136,8 +134,8 @@ class AccountCreationForm(forms.Form): validation, not rendering. """ - _EMAIL_INVALID_MSG = _(u"A properly formatted e-mail is required") - _NAME_TOO_SHORT_MSG = _(u"Your legal name must be a minimum of one character long") + _EMAIL_INVALID_MSG = _("A properly formatted e-mail is required") + _NAME_TOO_SHORT_MSG = _("Your legal name must be a minimum of one character long") # TODO: Resolve repetition @@ -149,7 +147,7 @@ class AccountCreationForm(forms.Form): error_messages={ "required": _EMAIL_INVALID_MSG, "invalid": _EMAIL_INVALID_MSG, - "max_length": _(u"Email cannot be more than %(limit_value)s characters long"), + "max_length": _("Email cannot be more than %(limit_value)s characters long"), } ) @@ -172,7 +170,7 @@ class AccountCreationForm(forms.Form): do_third_party_auth=True, tos_required=True ): - super(AccountCreationForm, self).__init__(data) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(data) extra_fields = extra_fields or {} self.extended_profile_fields = extended_profile_fields or {} @@ -245,11 +243,11 @@ class AccountCreationForm(forms.Form): # they may have been manually invited by an instructor and if not, # reject the registration. if not CourseEnrollmentAllowed.objects.filter(email=email).exists(): - raise ValidationError(_(u"Unauthorized email address.")) + raise ValidationError(_("Unauthorized email address.")) if email_exists_or_retired(email): raise ValidationError( _( - u"It looks like {email} belongs to an existing account. Try again with a different email address." + "It looks like {email} belongs to an existing account. Try again with a different email address." ).format(email=email) ) return email @@ -290,7 +288,7 @@ def get_registration_extension_form(*args, **kwargs): return getattr(module, klass)(*args, **kwargs) -class RegistrationFormFactory(object): +class RegistrationFormFactory: """ Construct Registration forms and associated fields. """ @@ -338,14 +336,14 @@ class RegistrationFormFactory(object): # Check that the setting is configured correctly for field_name in self.EXTRA_FIELDS: if self._extra_fields_setting.get(field_name, "hidden") not in ["required", "optional", "hidden"]: - msg = u"Setting REGISTRATION_EXTRA_FIELDS values must be either required, optional, or hidden." + msg = "Setting REGISTRATION_EXTRA_FIELDS values must be either required, optional, or hidden." raise ImproperlyConfigured(msg) # Map field names to the instance method used to add the field to the form self.field_handlers = {} valid_fields = self.DEFAULT_FIELDS + self.EXTRA_FIELDS for field_name in valid_fields: - handler = getattr(self, "_add_{field_name}_field".format(field_name=field_name)) + handler = getattr(self, f"_add_{field_name}_field") self.field_handlers[field_name] = handler field_order = configuration_helpers.get_value('REGISTRATION_FIELD_ORDER') @@ -397,7 +395,7 @@ class RegistrationFormFactory(object): field_type = field_options.get('field_type', FormDescription.FIELD_TYPE_MAP.get(field.__class__)) if not field_type: raise ImproperlyConfigured( - u"Field type '{}' not recognized for registration extension field '{}'.".format( + "Field type '{}' not recognized for registration extension field '{}'.".format( field_type, field_name ) @@ -450,11 +448,11 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # meant to hold the user's email address. - email_label = _(u"Email") + email_label = _("Email") # Translators: These instructions appear on the registration form, immediately # below a field meant to hold the user's email address. - email_instructions = _(u"This is what you will use to login.") + email_instructions = _("This is what you will use to login.") form_desc.add_field( "email", @@ -477,7 +475,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # meant to confirm the user's email address. - email_label = _(u"Confirm Email") + email_label = _("Confirm Email") error_msg = accounts.REQUIRED_FIELD_CONFIRM_EMAIL_MSG @@ -500,11 +498,11 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # meant to hold the user's full name. - name_label = _(u"Full Name") + name_label = _("Full Name") # Translators: These instructions appear on the registration form, immediately # below a field meant to hold the user's full name. - name_instructions = _(u"This name will be used on any certificates that you earn.") + name_instructions = _("This name will be used on any certificates that you earn.") form_desc.add_field( "name", @@ -525,13 +523,13 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # meant to hold the user's public username. - username_label = _(u"Public Username") + username_label = _("Public Username") username_instructions = _( # Translators: These instructions appear on the registration form, immediately # below a field meant to hold the user's public username. - u"The name that will identify you in your courses. " - u"It cannot be changed later." + "The name that will identify you in your courses. " + "It cannot be changed later." ) form_desc.add_field( "username", @@ -553,7 +551,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # meant to hold the user's password. - password_label = _(u"Password") + password_label = _("Password") form_desc.add_field( "password", @@ -573,7 +571,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a dropdown menu on the registration # form used to select the user's highest completed level of education. - education_level_label = _(u"Highest level of education completed") + education_level_label = _("Highest level of education completed") error_msg = accounts.REQUIRED_FIELD_LEVEL_OF_EDUCATION_MSG # The labels are marked for translation in UserProfile model definition. @@ -600,7 +598,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a dropdown menu on the registration # form used to select the user's gender. - gender_label = _(u"Gender") + gender_label = _("Gender") # The labels are marked for translation in UserProfile model definition. # pylint: disable=translation-of-non-string @@ -623,9 +621,9 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a dropdown menu on the registration # form used to select the user's year of birth. - yob_label = _(u"Year of birth") + yob_label = _("Year of birth") - options = [(six.text_type(year), six.text_type(year)) for year in UserProfile.VALID_YEARS] + options = [(str(year), str(year)) for year in UserProfile.VALID_YEARS] form_desc.add_field( "year_of_birth", label=yob_label, @@ -656,14 +654,14 @@ class RegistrationFormFactory(object): include_default_option = False options = None error_msg = '' - error_msg = getattr(accounts, u'REQUIRED_FIELD_{}_TEXT_MSG'.format(field_name.upper())) + error_msg = getattr(accounts, f'REQUIRED_FIELD_{field_name.upper()}_TEXT_MSG') else: field_type = "select" include_default_option = True field_options = extra_field_options.get(field_name) - options = [(six.text_type(option.lower()), option) for option in field_options] + options = [(str(option.lower()), option) for option in field_options] error_msg = '' - error_msg = getattr(accounts, u'REQUIRED_FIELD_{}_SELECT_MSG'.format(field_name.upper())) + error_msg = getattr(accounts, f'REQUIRED_FIELD_{field_name.upper()}_SELECT_MSG') form_desc.add_field( field_name, @@ -718,7 +716,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # meant to hold the user's mailing address. - mailing_address_label = _(u"Mailing address") + mailing_address_label = _("Mailing address") error_msg = accounts.REQUIRED_FIELD_MAILING_ADDRESS_MSG form_desc.add_field( @@ -740,7 +738,7 @@ class RegistrationFormFactory(object): """ # Translators: This phrase appears above a field on the registration form # meant to hold the user's reasons for registering with edX. - goals_label = _(u"Tell us why you're interested in {platform_name}").format( + goals_label = _("Tell us why you're interested in {platform_name}").format( platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME) ) error_msg = accounts.REQUIRED_FIELD_GOALS_MSG @@ -764,7 +762,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # which allows the user to input the city in which they live. - city_label = _(u"City") + city_label = _("City") error_msg = accounts.REQUIRED_FIELD_CITY_MSG form_desc.add_field( @@ -785,7 +783,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # which allows the user to input the State/Province/Region in which they live. - state_label = _(u"State/Province/Region") + state_label = _("State/Province/Region") form_desc.add_field( "state", @@ -802,7 +800,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # which allows the user to input the Company - company_label = _(u"Company") + company_label = _("Company") form_desc.add_field( "company", @@ -819,7 +817,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # which allows the user to input the Title - title_label = _(u"Title") + title_label = _("Title") form_desc.add_field( "title", @@ -836,7 +834,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # which allows the user to input the Job Title - job_title_label = _(u"Job Title") + job_title_label = _("Job Title") form_desc.add_field( "job_title", @@ -853,7 +851,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # which allows the user to input the First Name - first_name_label = _(u"First Name") + first_name_label = _("First Name") form_desc.add_field( "first_name", @@ -870,7 +868,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a field on the registration form # which allows the user to input the First Name - last_name_label = _(u"Last Name") + last_name_label = _("Last Name") form_desc.add_field( "last_name", @@ -887,7 +885,7 @@ class RegistrationFormFactory(object): """ # Translators: This label appears above a dropdown menu on the registration # form used to select the country in which the user lives. - country_label = _(u"Country or Region of Residence") + country_label = _("Country or Region of Residence") error_msg = accounts.REQUIRED_FIELD_COUNTRY_MSG @@ -898,7 +896,7 @@ class RegistrationFormFactory(object): country_instructions = _( # Translators: These instructions appear on the registration form, immediately # below a field meant to hold the user's country. - u"The country or region where you live." + "The country or region where you live." ) if default_country: form_desc.override_field_properties( @@ -930,24 +928,24 @@ class RegistrationFormFactory(object): separate_honor_and_tos = self._is_field_visible("terms_of_service") # Separate terms of service and honor code checkboxes if separate_honor_and_tos: - terms_label = _(u"Honor Code") + terms_label = _("Honor Code") terms_link = marketing_link("HONOR") # Combine terms of service and honor code checkboxes else: # Translators: This is a legal document users must agree to # in order to register a new account. - terms_label = _(u"Terms of Service and Honor Code") + terms_label = _("Terms of Service and Honor Code") terms_link = marketing_link("HONOR") # Translators: "Terms of Service" is a legal document users must agree to # in order to register a new account. label = Text(_( - u"I agree to the {platform_name} {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end}" + "I agree to the {platform_name} {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end}" )).format( platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME), terms_of_service=terms_label, - terms_of_service_link_start=HTML(u"").format( + terms_of_service_link_start=HTML("").format( terms_link=terms_link ), terms_of_service_link_end=HTML(""), @@ -955,7 +953,7 @@ class RegistrationFormFactory(object): # Translators: "Terms of Service" is a legal document users must agree to # in order to register a new account. - error_msg = _(u"You must agree to the {platform_name} {terms_of_service}").format( + error_msg = _("You must agree to the {platform_name} {terms_of_service}").format( platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME), terms_of_service=terms_label ) @@ -966,18 +964,18 @@ class RegistrationFormFactory(object): pp_link = marketing_link("PRIVACY") label = Text(_( - u"By creating an account, you agree to the \ + "By creating an account, you agree to the \ {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end} \ and you acknowledge that {platform_name} and each Member process your personal data in accordance \ with the {privacy_policy_link_start}Privacy Policy{privacy_policy_link_end}." )).format( platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME), terms_of_service=terms_label, - terms_of_service_link_start=HTML(u"").format( + terms_of_service_link_start=HTML("").format( terms_url=terms_link ), terms_of_service_link_end=HTML(""), - privacy_policy_link_start=HTML(u"").format( + privacy_policy_link_start=HTML("").format( pp_url=pp_link ), privacy_policy_link_end=HTML(""), @@ -1003,15 +1001,15 @@ class RegistrationFormFactory(object): """ # Translators: This is a legal document users must agree to # in order to register a new account. - terms_label = _(u"Terms of Service") + terms_label = _("Terms of Service") terms_link = marketing_link("TOS") # Translators: "Terms of service" is a legal document users must agree to # in order to register a new account. - label = Text(_(u"I agree to the {platform_name} {tos_link_start}{terms_of_service}{tos_link_end}")).format( + label = Text(_("I agree to the {platform_name} {tos_link_start}{terms_of_service}{tos_link_end}")).format( platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME), terms_of_service=terms_label, - tos_link_start=HTML(u"").format( + tos_link_start=HTML("").format( terms_link=terms_link ), tos_link_end=HTML(""), @@ -1019,7 +1017,7 @@ class RegistrationFormFactory(object): # Translators: "Terms of service" is a legal document users must agree to # in order to register a new account. - error_msg = _(u"You must agree to the {platform_name} {terms_of_service}").format( + error_msg = _("You must agree to the {platform_name} {terms_of_service}").format( platform_name=configuration_helpers.get_value("PLATFORM_NAME", settings.PLATFORM_NAME), terms_of_service=terms_label ) diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py b/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py index cab3865e03..de3850869f 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py @@ -2,14 +2,13 @@ import json +from unittest.mock import Mock, patch import ddt -import six from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.test import TestCase from django.test.client import Client -from mock import Mock, patch from opaque_keys.edx.locator import CourseLocator from common.djangoapps.student.models import CourseAccessRole, CourseEnrollment, UserProfile, anonymous_id_for_user @@ -51,7 +50,7 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase, ModuleStoreTestCase): # of the UrlResetMixin) self.CREATE_USER = False # no need to add a user from modulestore setup - super(AutoAuthEnabledTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = '/auto_auth' self.client = Client() @@ -148,7 +147,7 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase, ModuleStoreTestCase): @ddt.unpack def test_set_roles(self, course_id, course_key): seed_permissions_roles(course_key) - course_roles = dict((r.name, r) for r in Role.objects.filter(course_id=course_key)) + course_roles = {r.name: r for r in Role.objects.filter(course_id=course_key)} assert len(course_roles) == 5 # sanity check @@ -163,13 +162,13 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase, ModuleStoreTestCase): self._auto_auth({'username': 'a_moderator', 'course_id': course_id, 'roles': 'Moderator'}) user = User.objects.get(username='a_moderator') user_roles = user.roles.all() - assert set(user_roles) == set([course_roles[FORUM_ROLE_STUDENT], course_roles[FORUM_ROLE_MODERATOR]]) + assert set(user_roles) == {course_roles[FORUM_ROLE_STUDENT], course_roles[FORUM_ROLE_MODERATOR]} # check multiple roles work. self.client.logout() self._auto_auth({ 'username': 'an_admin', 'course_id': course_id, - 'roles': '{},{}'.format(FORUM_ROLE_MODERATOR, FORUM_ROLE_ADMINISTRATOR) + 'roles': f'{FORUM_ROLE_MODERATOR},{FORUM_ROLE_ADMINISTRATOR}' }) user = User.objects.get(username='an_admin') user_roles = user.roles.all() @@ -211,7 +210,7 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase, ModuleStoreTestCase): if settings.ROOT_URLCONF == 'lms.urls': url_pattern = '/course/' else: - url_pattern = '/course/{}'.format(six.text_type(course_key)) + url_pattern = '/course/{}'.format(str(course_key)) assert response.url.endswith(url_pattern) @@ -306,7 +305,7 @@ class AutoAuthDisabledTestCase(AutoAuthTestCase): # value affects the contents of urls.py, # so we need to call super.setUp() which reloads urls.py (because # of the UrlResetMixin) - super(AutoAuthDisabledTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = '/auto_auth' self.client = Client() @@ -330,7 +329,7 @@ class AutoAuthRestrictedTestCase(AutoAuthTestCase): # value affects the contents of urls.py, # so we need to call super.setUp() which reloads urls.py (because # of the UrlResetMixin) - super(AutoAuthRestrictedTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = '/auto_auth' self.client = Client() diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_login.py b/openedx/core/djangoapps/user_authn/views/tests/test_login.py index 28a5913cdc..171c6d1b86 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_login.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_login.py @@ -1,4 +1,3 @@ -# coding:utf-8 """ Tests for student activation and login """ @@ -8,9 +7,9 @@ import datetime import hashlib import json import unicodedata +from unittest.mock import Mock, patch import ddt -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 @@ -21,7 +20,6 @@ from django.test.utils import override_settings from django.urls import NoReverseMatch, reverse from edx_toggles.toggles.testutils import override_waffle_flag, override_waffle_switch from freezegun import freeze_time -from mock import Mock, patch from common.djangoapps.student.tests.factories import RegistrationFactory, UserFactory, UserProfileFactory from openedx.core.djangoapps.password_policy.compliance import ( @@ -59,7 +57,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): def setUp(self): """Setup a test user along with its registration and profile""" - super(LoginTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = self._create_user(self.username, self.user_email) RegistrationFactory(user=self.user) @@ -81,7 +79,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): self.user_email, self.password, patched_audit_log='common.djangoapps.student.models.AUDIT_LOG' ) self._assert_response(response, success=True) - self._assert_audit_log(mock_audit_log, 'info', [u'Login success', self.user_email]) + self._assert_audit_log(mock_audit_log, 'info', ['Login success', self.user_email]) FEATURES_WITH_AUTHN_MFE_ENABLED = settings.FEATURES.copy() FEATURES_WITH_AUTHN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True @@ -291,11 +289,11 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): self.user_email, self.password, patched_audit_log='common.djangoapps.student.models.AUDIT_LOG' ) self._assert_response(response, success=True) - self._assert_audit_log(mock_audit_log, 'info', [u'Login success']) + self._assert_audit_log(mock_audit_log, 'info', ['Login success']) self._assert_not_in_audit_log(mock_audit_log, 'info', [self.user_email]) def test_login_success_unicode_email(self): - unicode_email = u'test' + six.unichr(40960) + u'@edx.org' + unicode_email = 'test' + chr(40960) + '@edx.org' self.user.email = unicode_email self.user.save() @@ -303,10 +301,10 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): unicode_email, self.password, patched_audit_log='common.djangoapps.student.models.AUDIT_LOG' ) self._assert_response(response, success=True) - self._assert_audit_log(mock_audit_log, 'info', [u'Login success', unicode_email]) + self._assert_audit_log(mock_audit_log, 'info', ['Login success', unicode_email]) def test_login_fail_no_user_exists(self): - nonexistent_email = u'not_a_user@edx.org' + nonexistent_email = 'not_a_user@edx.org' # pylint: disable=too-many-function-args email_hash = hashlib.shake_128(nonexistent_email.encode('utf-8')).hexdigest(16) response, mock_audit_log = self._login_response( @@ -316,17 +314,17 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): self._assert_response( response, success=False, value=self.LOGIN_FAILED_WARNING, status_code=400 ) - self._assert_audit_log(mock_audit_log, 'warning', [u'Login failed', u'Unknown user email', email_hash]) + self._assert_audit_log(mock_audit_log, 'warning', ['Login failed', 'Unknown user email', email_hash]) @patch.dict("django.conf.settings.FEATURES", {'SQUELCH_PII_IN_LOGS': True}) def test_login_fail_no_user_exists_no_pii(self): - nonexistent_email = u'not_a_user@edx.org' + nonexistent_email = 'not_a_user@edx.org' response, mock_audit_log = self._login_response( nonexistent_email, self.password, ) self._assert_response(response, success=False, value=self.LOGIN_FAILED_WARNING) - self._assert_audit_log(mock_audit_log, 'warning', [u'Login failed', u'Unknown user email']) + self._assert_audit_log(mock_audit_log, 'warning', ['Login failed', 'Unknown user email']) self._assert_not_in_audit_log(mock_audit_log, 'warning', [nonexistent_email]) def test_login_fail_wrong_password(self): @@ -336,14 +334,14 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): ) self._assert_response(response, success=False, value=self.LOGIN_FAILED_WARNING) self._assert_audit_log(mock_audit_log, 'warning', - [u'Login failed', u'password for', str(self.user.id), u'invalid']) + ['Login failed', 'password for', str(self.user.id), 'invalid']) @patch.dict("django.conf.settings.FEATURES", {'SQUELCH_PII_IN_LOGS': True}) def test_login_fail_wrong_password_no_pii(self): response, mock_audit_log = self._login_response(self.user_email, 'wrong_password') self._assert_response(response, success=False, value=self.LOGIN_FAILED_WARNING) self._assert_audit_log( - mock_audit_log, 'warning', [u'Login failed', u'password for', str(self.user.id), u'invalid'] + mock_audit_log, 'warning', ['Login failed', 'password for', str(self.user.id), 'invalid'] ) self._assert_not_in_audit_log(mock_audit_log, 'warning', [self.user_email]) @@ -358,8 +356,8 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): self.password ) self._assert_response(response, success=False, error_code="inactive-user") - self._assert_audit_log(mock_audit_log, 'warning', [u'Login failed', u'Account not active for user']) - self._assert_not_in_audit_log(mock_audit_log, 'warning', [u'test']) + self._assert_audit_log(mock_audit_log, 'warning', ['Login failed', 'Account not active for user']) + self._assert_not_in_audit_log(mock_audit_log, 'warning', ['test']) def test_login_not_activated_with_correct_credentials(self): """ @@ -374,7 +372,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): self.password, ) self._assert_response(response, success=False, error_code="inactive-user") - self._assert_audit_log(mock_audit_log, 'warning', [u'Login failed', u'Account not active for user']) + self._assert_audit_log(mock_audit_log, 'warning', ['Login failed', 'Account not active for user']) @patch('openedx.core.djangoapps.user_authn.views.login._log_and_raise_inactive_user_auth_error') def test_login_inactivated_user_with_incorrect_credentials(self, mock_inactive_user_email_and_error): @@ -391,10 +389,10 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): assert not mock_inactive_user_email_and_error.called self._assert_response(response, success=False, value=self.LOGIN_FAILED_WARNING) - self._assert_audit_log(mock_audit_log, 'warning', [u'Login failed', u'Unknown user email', email_hash]) + self._assert_audit_log(mock_audit_log, 'warning', ['Login failed', 'Unknown user email', email_hash]) def test_login_unicode_email(self): - unicode_email = self.user_email + six.unichr(40960) + unicode_email = self.user_email + chr(40960) # pylint: disable=too-many-function-args email_hash = hashlib.shake_128(unicode_email.encode('utf-8')).hexdigest(16) response, mock_audit_log = self._login_response( @@ -402,17 +400,17 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): self.password, ) self._assert_response(response, success=False) - self._assert_audit_log(mock_audit_log, 'warning', [u'Login failed', email_hash]) + self._assert_audit_log(mock_audit_log, 'warning', ['Login failed', email_hash]) def test_login_unicode_password(self): - unicode_password = self.password + six.unichr(1972) + unicode_password = self.password + chr(1972) response, mock_audit_log = self._login_response( self.user_email, unicode_password, ) self._assert_response(response, success=False) self._assert_audit_log(mock_audit_log, 'warning', - [u'Login failed', u'password for', str(self.user.id), u'invalid']) + ['Login failed', 'password for', str(self.user.id), 'invalid']) def test_logout_logging(self): response, _ = self._login_response(self.user_email, self.password) @@ -421,7 +419,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): with patch('common.djangoapps.student.models.AUDIT_LOG') as mock_audit_log: response = self.client.post(logout_url) assert response.status_code == 200 - self._assert_audit_log(mock_audit_log, 'info', [u'Logout', u'test']) + self._assert_audit_log(mock_audit_log, 'info', ['Logout', 'test']) def test_login_user_info_cookie(self): response, _ = self._login_response(self.user_email, self.password) @@ -457,8 +455,8 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): assert '01 Jan 1970' in cookie.get('expires').replace('-', ' ') @override_settings( - EDXMKTG_LOGGED_IN_COOKIE_NAME=u"unicode-logged-in", - EDXMKTG_USER_INFO_COOKIE_NAME=u"unicode-user-info", + EDXMKTG_LOGGED_IN_COOKIE_NAME="unicode-logged-in", + EDXMKTG_USER_INFO_COOKIE_NAME="unicode-user-info", ) def test_unicode_mktg_cookie_names(self): # When logged in cookie names are loaded from JSON files, they may @@ -481,15 +479,15 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): with patch('common.djangoapps.student.models.AUDIT_LOG') as mock_audit_log: response = self.client.post(logout_url) assert response.status_code == 200 - self._assert_audit_log(mock_audit_log, 'info', [u'Logout']) - self._assert_not_in_audit_log(mock_audit_log, 'info', [u'test']) + self._assert_audit_log(mock_audit_log, 'info', ['Logout']) + self._assert_not_in_audit_log(mock_audit_log, 'info', ['test']) @override_settings(RATELIMIT_ENABLE=False) def test_excessive_login_attempts_success(self): # Try (and fail) logging in with fewer attempts than the limit of 30 # and verify that you can still successfully log in afterwards. for i in range(20): - password = u'test_password{0}'.format(i) + password = f'test_password{i}' response, _audit_log = self._login_response(self.user_email, password) self._assert_response(response, success=False) # now try logging in with a valid password @@ -506,7 +504,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): # are not predictable and we don't want the test to be flaky. with freeze_time(): for i in range(6): - password = u'test_password{0}'.format(i) + password = f'test_password{i}' # Provide unique IPs so we don't get ip rate limited. real_ip_mock.return_value = f'192.168.1.{i}' self._login_response(self.user_email, password) @@ -692,12 +690,12 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): @ddt.data( ('test_password', 'test_password', True), - (unicodedata.normalize('NFKD', u'Ṗŕệṿïệẅ Ṯệẍt'), - unicodedata.normalize('NFKC', u'Ṗŕệṿïệẅ Ṯệẍt'), False), - (unicodedata.normalize('NFKC', u'Ṗŕệṿïệẅ Ṯệẍt'), - unicodedata.normalize('NFKD', u'Ṗŕệṿïệẅ Ṯệẍt'), True), - (unicodedata.normalize('NFKD', u'Ṗŕệṿïệẅ Ṯệẍt'), - unicodedata.normalize('NFKD', u'Ṗŕệṿïệẅ Ṯệẍt'), False), + (unicodedata.normalize('NFKD', 'Ṗŕệṿïệẅ Ṯệẍt'), + unicodedata.normalize('NFKC', 'Ṗŕệṿïệẅ Ṯệẍt'), False), + (unicodedata.normalize('NFKC', 'Ṗŕệṿïệẅ Ṯệẍt'), + unicodedata.normalize('NFKD', 'Ṗŕệṿïệẅ Ṯệẍt'), True), + (unicodedata.normalize('NFKD', 'Ṗŕệṿïệẅ Ṯệẍt'), + unicodedata.normalize('NFKD', 'Ṗŕệṿïệẅ Ṯệẍt'), False), ) @ddt.unpack def test_password_unicode_normalization_login(self, password, password_entered, login_success): @@ -741,7 +739,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): try: response_dict = json.loads(response.content.decode('utf-8')) except ValueError: - self.fail(u"Could not parse response content as JSON: %s" + self.fail("Could not parse response content as JSON: %s" % str(response.content)) if success is not None: @@ -751,8 +749,8 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): assert response_dict['error_code'] == error_code if value is not None: - msg = (u"'%s' did not contain '%s'" % - (six.text_type(response_dict['value']), six.text_type(value))) + msg = ("'%s' did not contain '%s'" % + (str(response_dict['value']), str(value))) assert value in response_dict['value'], msg def _assert_redirect_url(self, response, expected_redirect_url): @@ -877,7 +875,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): provider = 'Google' provider_tpa_hint = 'saml-test' username = 'batman' - user_email = '{username}@{domain}'.format(username=username, domain=user_domain) + user_email = f'{username}@{user_domain}' user = self._create_user(username, user_email) default_site_configuration_values = { 'SITE_NAME': allowed_domain, @@ -898,7 +896,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase): if success: value = None else: - value = u'As {0} user, You must login with your {0} {2} account.'.format( + value = 'As {0} user, You must login with your {0} {2} account.'.format( allowed_domain, '{}?tpa_hint={}'.format(reverse("dashboard"), provider_tpa_hint), provider, @@ -958,7 +956,7 @@ class LoginSessionViewTest(ApiTestCase): PASSWORD = "password" def setUp(self): - super(LoginSessionViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("user_api_login_session") @ddt.data("get", "post") diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py b/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py index 3c202af712..bfcd347e02 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- """ Tests for Logistration views. """ from datetime import datetime, timedelta from http.cookies import SimpleCookie from urllib.parse import urlencode +from unittest import mock import ddt -import mock from django.conf import settings from django.contrib import messages from django.contrib.auth.models import AnonymousUser @@ -45,13 +44,13 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto """ Tests for Login and Registration. """ USERNAME = "bob" EMAIL = "bob@example.com" - PASSWORD = u"password" + PASSWORD = "password" URLCONF_MODULES = ['openedx.core.djangoapps.embargo'] @mock.patch.dict(settings.FEATURES, {'EMBARGO': True}) def setUp(self): # pylint: disable=arguments-differ - super(LoginAndRegistrationTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Several third party auth providers are created for these tests: self.google_provider = self.configure_google_provider(enabled=True, visible=True) @@ -125,7 +124,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto @ddt.unpack def test_login_and_registration_form(self, url_name, initial_mode): response = self.client.get(reverse(url_name)) - expected_data = u'"initial_mode": "{mode}"'.format(mode=initial_mode) + expected_data = f'"initial_mode": "{initial_mode}"' self.assertContains(response, expected_data) def test_login_and_registration_form_ratelimited(self): @@ -399,10 +398,10 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto response = login_and_registration_form(request) expected_error_message = Text(_( - u'We are sorry, you are not authorized to access {platform_name} via this channel. ' - u'Please contact your learning administrator or manager in order to access {platform_name}.' - u'{line_break}{line_break}' - u'Error Details:{line_break}{error_message}') + 'We are sorry, you are not authorized to access {platform_name} via this channel. ' + 'Please contact your learning administrator or manager in order to access {platform_name}.' + '{line_break}{line_break}' + 'Error Details:{line_break}{error_message}') ).format( platform_name=settings.PLATFORM_NAME, error_message=dummy_error_message, @@ -421,12 +420,12 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto self.assertContains(response, '"third_party_auth_hint": "oa2-google-oauth2"') tpa_hint = self.hidden_enabled_provider.provider_id - params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))] + params = [("next", f"/courses/something/?tpa_hint={tpa_hint}")] response = self.client.get(reverse('signin_user'), params, HTTP_ACCEPT="text/html") - self.assertContains(response, u'"third_party_auth_hint": "{0}"'.format(tpa_hint)) + self.assertContains(response, f'"third_party_auth_hint": "{tpa_hint}"') tpa_hint = self.hidden_disabled_provider.provider_id - params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))] + params = [("next", f"/courses/something/?tpa_hint={tpa_hint}")] response = self.client.get(reverse('signin_user'), params, HTTP_ACCEPT="text/html") assert response.content.decode('utf-8') not in tpa_hint @@ -464,13 +463,13 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto # THIRD_PARTY_AUTH_HINT can be overridden via the query string tpa_hint = self.hidden_enabled_provider.provider_id - params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))] + params = [("next", f"/courses/something/?tpa_hint={tpa_hint}")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") - self.assertContains(response, u'"third_party_auth_hint": "{0}"'.format(tpa_hint)) + self.assertContains(response, f'"third_party_auth_hint": "{tpa_hint}"') # Even disabled providers in the query string will override THIRD_PARTY_AUTH_HINT tpa_hint = self.hidden_disabled_provider.provider_id - params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))] + params = [("next", f"/courses/something/?tpa_hint={tpa_hint}")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") assert response.content.decode('utf-8') not in tpa_hint @@ -525,7 +524,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") - enterprise_sidebar_div_id = u'enterprise-content-container' + enterprise_sidebar_div_id = 'enterprise-content-container' if not ec_present: self.assertNotContains(response, text=enterprise_sidebar_div_id) @@ -541,7 +540,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto line_break=HTML('
'), enterprise_name=ec_name, platform_name=settings.PLATFORM_NAME, - privacy_policy_link_start=HTML(u"").format( + privacy_policy_link_start=HTML("").format( pp_url=get_privacy_url() ), privacy_policy_link_end=HTML(""), @@ -607,7 +606,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto auth_info['providers'] = [] auth_info = dump_js_escaped_json(auth_info) - expected_data = u'"third_party_auth": {auth_info}'.format( + expected_data = '"third_party_auth": {auth_info}'.format( auth_info=auth_info ) self.assertContains(response, expected_data) @@ -635,14 +634,14 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto } auth_info = dump_js_escaped_json(auth_info) - expected_data = u'"third_party_auth": {auth_info}'.format( + expected_data = '"third_party_auth": {auth_info}'.format( auth_info=auth_info ) self.assertContains(response, expected_data) def _third_party_login_url(self, backend_name, auth_entry, login_params): """Construct the login URL to start third party authentication. """ - return u"{url}?auth_entry={auth_entry}&{param_str}".format( + return "{url}?auth_entry={auth_entry}&{param_str}".format( url=reverse("social:begin", kwargs={"backend": backend_name}), auth_entry=auth_entry, param_str=self._finish_auth_url_param(login_params), @@ -689,7 +688,7 @@ class AccountCreationTestCaseWithSiteOverrides(SiteMixin, TestCase): def setUp(self): """Set up the tests""" - super(AccountCreationTestCaseWithSiteOverrides, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Set the feature flag ALLOW_PUBLIC_ACCOUNT_CREATION to False self.site_configuration_values = { @@ -704,4 +703,4 @@ class AccountCreationTestCaseWithSiteOverrides(SiteMixin, TestCase): ALLOW_PUBLIC_ACCOUNT_CREATION flag is turned off """ response = self.client.get(reverse('signin_user')) - self.assertNotContains(response, u'Register') + self.assertNotContains(response, 'Register') diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_logout.py b/openedx/core/djangoapps/user_authn/views/tests/test_logout.py index c9262dfe26..6e906ca53f 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_logout.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_logout.py @@ -4,10 +4,9 @@ Tests for logout import unittest - +import urllib +from unittest import mock import ddt -import mock -import six from django.conf import settings from django.test import TestCase from django.test.utils import override_settings @@ -24,7 +23,7 @@ class LogoutTests(TestCase): def setUp(self): """ Create a course and user, then log in. """ - super(LogoutTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory() self.client.login(username=self.user.username, password='test') @@ -75,7 +74,7 @@ class LogoutTests(TestCase): ) response = self.client.get(url, HTTP_HOST=host) expected = { - 'target': six.moves.urllib.parse.unquote(redirect_url), + 'target': urllib.parse.unquote(redirect_url), } self.assertDictContainsSubset(expected, response.context_data) @@ -180,7 +179,7 @@ class LogoutTests(TestCase): Test when learner logout from learner portal having active SSO session logout page should have link to logout url IdP. """ - learner_portal_logout_url = '{}/logout'.format(settings.LEARNER_PORTAL_URL_ROOT) + learner_portal_logout_url = f'{settings.LEARNER_PORTAL_URL_ROOT}/logout' idp_logout_url = 'http://mock-idp.com/logout' client = self._create_oauth_client() diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_password.py b/openedx/core/djangoapps/user_authn/views/tests/test_password.py index a2bc6eba18..6d694a5283 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_password.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_password.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Tests for user authorization password-related functionality. """ @@ -6,6 +5,7 @@ import json import logging import re from datetime import datetime, timedelta +from unittest.mock import Mock, patch import pytest import ddt @@ -17,7 +17,6 @@ from django.test import TestCase from django.test.client import RequestFactory from django.urls import reverse from freezegun import freeze_time -from mock import Mock, patch from oauth2_provider.models import AccessToken as dot_access_token from oauth2_provider.models import RefreshToken as dot_refresh_token from pytz import UTC @@ -38,9 +37,9 @@ class TestRequestPasswordChange(CreateAccountMixin, TestCase): """ Tests for users who request a password change. """ - USERNAME = u'claire-underwood' - PASSWORD = u'ṕáśśẃőŕd' - EMAIL = u'claire+underwood@example.com' + USERNAME = 'claire-underwood' + PASSWORD = 'ṕáśśẃőŕd' + EMAIL = 'claire+underwood@example.com' IS_SECURE = False @@ -97,19 +96,19 @@ class TestRequestPasswordChange(CreateAccountMixin, TestCase): class TestPasswordChange(CreateAccountMixin, CacheIsolationTestCase): """ Tests for views that change the user's password. """ - USERNAME = u"heisenberg" - ALTERNATE_USERNAME = u"walt" - OLD_PASSWORD = u"ḅḷüëṡḳÿ" - NEW_PASSWORD = u"B🄸🄶B🄻🅄🄴" - OLD_EMAIL = u"walter@graymattertech.com" - NEW_EMAIL = u"walt@savewalterwhite.com" + USERNAME = "heisenberg" + ALTERNATE_USERNAME = "walt" + OLD_PASSWORD = "ḅḷüëṡḳÿ" + NEW_PASSWORD = "B🄸🄶B🄻🅄🄴" + OLD_EMAIL = "walter@graymattertech.com" + NEW_EMAIL = "walt@savewalterwhite.com" - INVALID_KEY = u"123abc" + INVALID_KEY = "123abc" ENABLED_CACHES = ['default'] def setUp(self): - super(TestPasswordChange, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.create_account(self.USERNAME, self.OLD_PASSWORD, self.OLD_EMAIL) result = self.client.login(username=self.USERNAME, password=self.OLD_PASSWORD) @@ -204,11 +203,11 @@ class TestPasswordChange(CreateAccountMixin, CacheIsolationTestCase): html_body = sent_message.alternatives[0][0] for email_body in [text_body, html_body]: - msg = u'However, there is currently no user account associated with your email address: {email}'.format( + msg = 'However, there is currently no user account associated with your email address: {email}'.format( email=bad_email ) - assert u'reset for your user account at {}'.format(settings.PLATFORM_NAME) in email_body + assert f'reset for your user account at {settings.PLATFORM_NAME}' in email_body assert 'password_reset_confirm' not in email_body, 'The link should not be added if user was not found' assert msg in email_body @@ -270,7 +269,7 @@ class TestPasswordChange(CreateAccountMixin, CacheIsolationTestCase): assert response.status_code == 200 expected_logs = ( - (LOGGER_NAME, 'INFO', 'Password reset initiated for email {}.'.format(self.NEW_EMAIL)), + (LOGGER_NAME, 'INFO', f'Password reset initiated for email {self.NEW_EMAIL}.'), (LOGGER_NAME, 'INFO', 'Invalid password reset attempt') ) logger.check(*expected_logs) diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_register.py b/openedx/core/djangoapps/user_authn/views/tests/test_register.py index adf510e9eb..4280b7d41c 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_register.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_register.py @@ -1,14 +1,12 @@ -# -*- coding: utf-8 -*- """Tests for account creation""" import json from datetime import datetime from unittest import skipIf, skipUnless +from unittest import mock import ddt import httpretty -import mock -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.test.utils import override_settings from django.urls import reverse from pytz import UTC -from six.moves import range from social_django.models import Partial, UserSocialAuth from edx_toggles.toggles.testutils import override_waffle_flag @@ -90,7 +87,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa GOALS = "Learn all the things!" def setUp(self): # pylint: disable=arguments-differ - super(RegistrationViewValidationErrorTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("user_api_registration") @mock.patch.dict(settings.FEATURES, { @@ -143,7 +140,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa { "email": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different email address." ).format( self.EMAIL @@ -188,7 +185,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa { "username": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different username." ).format( self.USERNAME @@ -226,7 +223,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa { "email": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different email address." ).format( self.EMAIL @@ -264,7 +261,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa { "email": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different email address." ).format( self.EMAIL @@ -301,7 +298,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa { "username": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different username." ).format( self.USERNAME @@ -338,7 +335,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa { "username": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different username." ).format( self.USERNAME @@ -346,7 +343,7 @@ class RegistrationViewValidationErrorTest(ThirdPartyAuthTestMixin, UserAPITestCa }], "email": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different email address." ).format( self.EMAIL @@ -376,31 +373,31 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): GOALS = "Learn all the things!" PROFESSION_OPTIONS = [ { - "name": u'--', - "value": u'', + "name": '--', + "value": '', "default": True }, { - "value": u'software engineer', - "name": u'Software Engineer', + "value": 'software engineer', + "name": 'Software Engineer', "default": False }, { - "value": u'teacher', - "name": u'Teacher', + "value": 'teacher', + "name": 'Teacher', "default": False }, { - "value": u'other', - "name": u'Other', + "value": 'other', + "name": 'Other', "default": False } ] SPECIALTY_OPTIONS = [ { - "name": u'--', - "value": u'', + "name": '--', + "value": '', "default": True }, @@ -410,20 +407,20 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "default": False }, { - "value": u'early education', - "name": u'Early Education', + "value": 'early education', + "name": 'Early Education', "default": False }, { - "value": u'n/a', - "name": u'N/A', + "value": 'n/a', + "name": 'N/A', "default": False } ] - link_template = u"{link_label}" + link_template = "{link_label}" def setUp(self): # pylint: disable=arguments-differ - super(RegistrationViewTestV1, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("user_api_registration") @ddt.data("get", "post") @@ -451,12 +448,12 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"email", - u"type": u"email", - u"required": True, - u"label": u"Email", - u"instructions": u"This is what you will use to login.", - u"restrictions": { + "name": "email", + "type": "email", + "required": True, + "label": "Email", + "instructions": "This is what you will use to login.", + "restrictions": { "min_length": EMAIL_MIN_LENGTH, "max_length": EMAIL_MAX_LENGTH }, @@ -466,12 +463,12 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"name", - u"type": u"text", - u"required": True, - u"label": u"Full Name", - u"instructions": u"This name will be used on any certificates that you earn.", - u"restrictions": { + "name": "name", + "type": "text", + "required": True, + "label": "Full Name", + "instructions": "This name will be used on any certificates that you earn.", + "restrictions": { "max_length": 255 }, } @@ -480,13 +477,12 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"username", - u"type": u"text", - u"required": True, - u"label": u"Public Username", - u"instructions": u"The name that will identify you in your courses. " - u"It cannot be changed later.", - u"restrictions": { + "name": "username", + "type": "text", + "required": True, + "label": "Public Username", + "instructions": "The name that will identify you in your courses. It cannot be changed later.", + "restrictions": { "min_length": USERNAME_MIN_LENGTH, "max_length": USERNAME_MAX_LENGTH }, @@ -496,13 +492,13 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"placeholder": "", - u"name": u"password", - u"type": u"password", - u"required": True, - u"label": u"Password", - u"instructions": password_validators_instruction_texts(), - u"restrictions": password_validators_restrictions(), + "placeholder": "", + "name": "password", + "type": "password", + "required": True, + "label": "Password", + "instructions": password_validators_instruction_texts(), + "restrictions": password_validators_restrictions(), } ) @@ -524,22 +520,22 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u'name': u'password', - u'label': u'Password', - u"instructions": password_validators_instruction_texts(), - u"restrictions": password_validators_restrictions(), + 'name': 'password', + 'label': 'Password', + "instructions": password_validators_instruction_texts(), + "restrictions": password_validators_restrictions(), } ) - msg = u'Your password must contain at least 2 characters, including ' \ - u'3 uppercase letters & 1 symbol.' + msg = 'Your password must contain at least 2 characters, including ' \ + '3 uppercase letters & 1 symbol.' self._assert_reg_field( no_extra_fields_setting, { - u'name': u'password', - u'label': u'Password', - u'instructions': msg, - u"restrictions": password_validators_restrictions(), + 'name': 'password', + 'label': 'Password', + 'instructions': msg, + "restrictions": password_validators_restrictions(), } ) @@ -551,12 +547,12 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"email", - u"type": u"email", - u"required": True, - u"label": u"Email", - u"instructions": u"This is what you will use to login.", - u"restrictions": { + "name": "email", + "type": "email", + "required": True, + "label": "Email", + "instructions": "This is what you will use to login.", + "restrictions": { "min_length": EMAIL_MIN_LENGTH, "max_length": EMAIL_MAX_LENGTH }, @@ -566,15 +562,15 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"favorite_editor", - u"type": u"select", - u"required": False, - u"label": u"Favorite Editor", - u"placeholder": u"cat", - u"defaultValue": u"vim", - u"errorMessages": { - u'required': u'This field is required.', - u'invalid_choice': u'Select a valid choice. %(value)s is not one of the available choices.', + "name": "favorite_editor", + "type": "select", + "required": False, + "label": "Favorite Editor", + "placeholder": "cat", + "defaultValue": "vim", + "errorMessages": { + 'required': 'This field is required.', + 'invalid_choice': 'Select a valid choice. %(value)s is not one of the available choices.', } } ) @@ -582,17 +578,17 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"favorite_movie", - u"type": u"text", - u"required": True, - u"label": u"Fav Flick", - u"placeholder": None, - u"defaultValue": None, - u"errorMessages": { - u'required': u'Please tell us your favorite movie.', - u'invalid': u"We're pretty sure you made that movie up." + "name": "favorite_movie", + "type": "text", + "required": True, + "label": "Fav Flick", + "placeholder": None, + "defaultValue": None, + "errorMessages": { + 'required': 'Please tell us your favorite movie.', + 'invalid': "We're pretty sure you made that movie up." }, - u"restrictions": { + "restrictions": { "min_length": TestCaseForm.MOVIE_MIN_LEN, "max_length": TestCaseForm.MOVIE_MAX_LEN, } @@ -620,7 +616,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): ] + [ { "value": country_code, - "name": six.text_type(country_name), + "name": str(country_name), "default": country_code == expected_country_code } for country_code, country_name in SORTED_COUNTRIES @@ -642,13 +638,13 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"email", - u"defaultValue": u"bob@example.com", - u"type": u"email", - u"required": True, - u"label": u"Email", - u"instructions": u"This is what you will use to login.", - u"restrictions": { + "name": "email", + "defaultValue": "bob@example.com", + "type": "email", + "required": True, + "label": "Email", + "instructions": "This is what you will use to login.", + "restrictions": { "min_length": EMAIL_MIN_LENGTH, "max_length": EMAIL_MAX_LENGTH }, @@ -659,13 +655,13 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"name", - u"defaultValue": u"Bob", - u"type": u"text", - u"required": True, - u"label": u"Full Name", - u"instructions": u"This name will be used on any certificates that you earn.", - u"restrictions": { + "name": "name", + "defaultValue": "Bob", + "type": "text", + "required": True, + "label": "Full Name", + "instructions": "This name will be used on any certificates that you earn.", + "restrictions": { "max_length": NAME_MAX_LENGTH, } } @@ -675,14 +671,13 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( no_extra_fields_setting, { - u"name": u"username", - u"defaultValue": expected_username, - u"type": u"text", - u"required": True, - u"label": u"Public Username", - u"instructions": u"The name that will identify you in your courses. " - u"It cannot be changed later.", - u"restrictions": { + "name": "username", + "defaultValue": expected_username, + "type": "text", + "required": True, + "label": "Public Username", + "instructions": "The name that will identify you in your courses. It cannot be changed later.", + "restrictions": { "min_length": USERNAME_MIN_LENGTH, "max_length": USERNAME_MAX_LENGTH } @@ -691,17 +686,17 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): # Country should be filled in. self._assert_reg_field( - {u"country": u"required"}, + {"country": "required"}, { - u"label": u"Country or Region of Residence", - u"name": u"country", - u"defaultValue": expected_country_code, - u"type": u"select", - u"required": True, - u"options": country_options, - u"instructions": u"The country or region where you live.", - u"errorMessages": { - u"required": u"Select your country or region of residence." + "label": "Country or Region of Residence", + "name": "country", + "defaultValue": expected_country_code, + "type": "select", + "required": True, + "options": country_options, + "instructions": "The country or region where you live.", + "errorMessages": { + "required": "Select your country or region of residence." }, } ) @@ -809,8 +804,8 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): } ] + [ { - "value": six.text_type(year), - "name": six.text_type(year), + "value": str(year), + "name": str(year), "default": False } for year in range(this_year, this_year - 120, -1) @@ -916,7 +911,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "name": "goals", "type": "textarea", "required": False, - "label": u"Tell us why you're interested in {platform_name}".format( + "label": "Tell us why you're interested in {platform_name}".format( platform_name=settings.PLATFORM_NAME ), "errorMessages": { @@ -961,7 +956,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): ] + [ { "value": country_code, - "name": six.text_type(country_name), + "name": str(country_name), "default": False } for country_code, country_name in SORTED_COUNTRIES @@ -991,17 +986,17 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): @mock.patch.dict(settings.FEATURES, {"ENABLE_MKTG_SITE": True}) def test_registration_honor_code_mktg_site_enabled(self): link_template = "{link_label}" - link_template2 = u"{link_label}" + link_template2 = "{link_label}" link_label = "Terms of Service and Honor Code" link_label2 = "Privacy Policy" self._assert_reg_field( {"honor_code": "required"}, { - "label": (u"By creating an account, you agree to the {spacing}" - u"{link_label} {spacing}" - u"and you acknowledge that {platform_name} and each Member process your " - u"personal data in accordance {spacing}" - u"with the {link_label2}.").format( + "label": ("By creating an account, you agree to the {spacing}" + "{link_label} {spacing}" + "and you acknowledge that {platform_name} and each Member process your " + "personal data in accordance {spacing}" + "with the {link_label2}.").format( platform_name=settings.PLATFORM_NAME, link_label=link_template.format(link_label=link_label), link_label2=link_template2.format(link_label=link_label2), @@ -1012,7 +1007,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "type": "plaintext", "required": True, "errorMessages": { - "required": u"You must agree to the {platform_name} {link_label}".format( + "required": "You must agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=link_label ) @@ -1029,11 +1024,11 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( {"honor_code": "required"}, { - "label": (u"By creating an account, you agree to the {spacing}" - u"{link_label} {spacing}" - u"and you acknowledge that {platform_name} and each Member process your " - u"personal data in accordance {spacing}" - u"with the {link_label2}.").format( + "label": ("By creating an account, you agree to the {spacing}" + "{link_label} {spacing}" + "and you acknowledge that {platform_name} and each Member process your " + "personal data in accordance {spacing}" + "with the {link_label2}.").format( platform_name=settings.PLATFORM_NAME, link_label=self.link_template.format(link_label=link_label), link_label2=link_template.format(link_label=link_label2), @@ -1044,7 +1039,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "type": "plaintext", "required": True, "errorMessages": { - "required": u"You must agree to the {platform_name} {link_label}".format( + "required": "You must agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=link_label ) @@ -1062,11 +1057,11 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): # Honor code field should say ONLY honor code, # not "terms of service and honor code" link_label = 'Honor Code' - link_template = u"{link_label}" + link_template = "{link_label}" self._assert_reg_field( {"honor_code": "required", "terms_of_service": "required"}, { - "label": u"I agree to the {platform_name} {link_label}".format( + "label": "I agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=link_template.format(link_label=link_label) ), @@ -1075,7 +1070,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "type": "checkbox", "required": True, "errorMessages": { - "required": u"You must agree to the {platform_name} {link_label}".format( + "required": "You must agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=link_label ) @@ -1085,11 +1080,11 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): # Terms of service field should also be present link_label = "Terms of Service" - link_template = u"{link_label}" + link_template = "{link_label}" self._assert_reg_field( {"honor_code": "required", "terms_of_service": "required"}, { - "label": u"I agree to the {platform_name} {link_label}".format( + "label": "I agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=link_template.format(link_label=link_label) ), @@ -1098,7 +1093,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "type": "checkbox", "required": True, "errorMessages": { - "required": u"You must agree to the {platform_name} {link_label}".format( + "required": "You must agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=link_label ) @@ -1115,7 +1110,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self._assert_reg_field( {"honor_code": "required", "terms_of_service": "required"}, { - "label": u"I agree to the {platform_name} {link_label}".format( + "label": "I agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=self.link_template.format(link_label=link_label) ), @@ -1124,7 +1119,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "type": "checkbox", "required": True, "errorMessages": { - "required": u"You must agree to the {platform_name} Honor Code".format( + "required": "You must agree to the {platform_name} Honor Code".format( platform_name=settings.PLATFORM_NAME ) } @@ -1133,11 +1128,11 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): link_label = 'Terms of Service' # Terms of service field should also be present - link_template = u"{link_label}" + link_template = "{link_label}" self._assert_reg_field( {"honor_code": "required", "terms_of_service": "required"}, { - "label": u"I agree to the {platform_name} {link_label}".format( + "label": "I agree to the {platform_name} {link_label}".format( platform_name=settings.PLATFORM_NAME, link_label=link_template.format(link_label=link_label) ), @@ -1146,7 +1141,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): "type": "checkbox", "required": True, "errorMessages": { - "required": u"You must agree to the {platform_name} Terms of Service".format( + "required": "You must agree to the {platform_name} Terms of Service".format( platform_name=settings.PLATFORM_NAME ) } @@ -1390,8 +1385,8 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): sent_email = mail.outbox[0] assert sent_email.to == [self.EMAIL] assert sent_email.subject ==\ - u'Action Required: Activate your {platform} account'.format(platform=settings.PLATFORM_NAME) - assert u'high-quality {platform} courses'.format(platform=settings.PLATFORM_NAME) in sent_email.body + f'Action Required: Activate your {settings.PLATFORM_NAME} account' + assert f'high-quality {settings.PLATFORM_NAME} courses' in sent_email.body @ddt.data( {"email": ""}, @@ -1461,7 +1456,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): { "email": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different email address." ).format( self.EMAIL @@ -1498,7 +1493,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): { "username": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different username." ).format( self.USERNAME @@ -1535,7 +1530,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): { "username": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different username." ).format( self.USERNAME @@ -1543,7 +1538,7 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): }], "email": [{ "user_message": ( - u"It looks like {} belongs to an existing account. " + "It looks like {} belongs to an existing account. " "Try again with a different email address." ).format( self.EMAIL @@ -1577,8 +1572,8 @@ class RegistrationViewTestV1(ThirdPartyAuthTestMixin, UserAPITestCase): self.assertDictEqual( response_json, { - "username": [{u"user_message": USERNAME_BAD_LENGTH_MSG}], - "password": [{u"user_message": u"This field is required."}], + "username": [{"user_message": USERNAME_BAD_LENGTH_MSG}], + "password": [{"user_message": "This field is required."}], "error_code": "validation-error" } ) @@ -1988,11 +1983,11 @@ class ThirdPartyRegistrationTestMixin(ThirdPartyOAuthTestMixin, CacheIsolationTe __test__ = False def setUp(self): - super(ThirdPartyRegistrationTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('user_api_registration') def tearDown(self): - super(ThirdPartyRegistrationTestMixin, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() Partial.objects.all().delete() def data(self, user=None): @@ -2114,7 +2109,7 @@ class ThirdPartyRegistrationTestMixin(ThirdPartyOAuthTestMixin, CacheIsolationTe response = self.client.post(self.url, data) self._assert_access_token_error( response, - u"An access_token is required when passing value ({}) for provider.".format(self.BACKEND), + f"An access_token is required when passing value ({self.BACKEND}) for provider.", "tpa-missing-access-token" ) self._verify_user_existence(user_exists=False, social_link_exists=False) @@ -2136,7 +2131,7 @@ class ThirdPartyRegistrationTestMixin(ThirdPartyOAuthTestMixin, CacheIsolationTe response = self.client.post(self.url, data) self._assert_third_party_session_expired_error( response, - u"Registration using {provider} has timed out.".format(provider="Google") + "Registration using {provider} has timed out.".format(provider="Google") ) self._verify_user_existence(user_exists=False, social_link_exists=False) @@ -2177,7 +2172,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): path = reverse(endpoint_name) def setUp(self): - super(RegistrationValidationViewTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() cache.clear() def get_validation_decision(self, data): @@ -2293,7 +2288,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_confirm_email_doesnt_equal_email(self, confirm_email): self.assertValidationDecision( {'email': 'user@email.com', 'confirm_email': confirm_email}, - {'email': '', 'confirm_email': six.text_type(REQUIRED_FIELD_CONFIRM_EMAIL_MSG)} + {'email': '', 'confirm_email': str(REQUIRED_FIELD_CONFIRM_EMAIL_MSG)} ) @ddt.data( @@ -2303,7 +2298,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_username_bad_length_validation_decision(self, username): self.assertValidationDecision( {'username': username}, - {'username': six.text_type(USERNAME_BAD_LENGTH_MSG)} + {'username': str(USERNAME_BAD_LENGTH_MSG)} ) @skipUnless(settings.FEATURES.get("ENABLE_UNICODE_USERNAME"), "Unicode usernames disabled.") @@ -2311,7 +2306,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_username_invalid_unicode_validation_decision(self, username): self.assertValidationDecision( {'username': username}, - {'username': six.text_type(USERNAME_INVALID_CHARS_UNICODE)} + {'username': str(USERNAME_INVALID_CHARS_UNICODE)} ) @skipIf(settings.FEATURES.get("ENABLE_UNICODE_USERNAME"), "Unicode usernames enabled.") @@ -2319,13 +2314,13 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_username_invalid_ascii_validation_decision(self, username): self.assertValidationDecision( {'username': username}, - {"username": six.text_type(USERNAME_INVALID_CHARS_ASCII)} + {"username": str(USERNAME_INVALID_CHARS_ASCII)} ) def test_password_empty_validation_decision(self): # 2 is the default setting for minimum length found in lms/envs/common.py # under AUTH_PASSWORD_VALIDATORS.MinimumLengthValidator - msg = u'This password is too short. It must contain at least 2 characters.' + msg = 'This password is too short. It must contain at least 2 characters.' self.assertValidationDecision( {'password': ''}, {"password": msg} @@ -2335,7 +2330,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): password = 'p' # 2 is the default setting for minimum length found in lms/envs/common.py # under AUTH_PASSWORD_VALIDATORS.MinimumLengthValidator - msg = u'This password is too short. It must contain at least 2 characters.' + msg = 'This password is too short. It must contain at least 2 characters.' self.assertValidationDecision( {'password': password}, {"password": msg} @@ -2345,7 +2340,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): password = 'p' * DEFAULT_MAX_PASSWORD_LENGTH # 75 is the default setting for maximum length found in lms/envs/common.py # under AUTH_PASSWORD_VALIDATORS.MaximumLengthValidator - msg = u'This password is too long. It must contain no more than 75 characters.' + msg = 'This password is too long. It must contain no more than 75 characters.' self.assertValidationDecision( {'password': password}, {"password": msg} @@ -2354,7 +2349,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase): def test_password_equals_username_validation_decision(self): self.assertValidationDecision( {"username": "somephrase", "password": "somephrase"}, - {"username": "", "password": u"The password is too similar to the username."} + {"username": "", "password": "The password is too similar to the username."} ) @override_settings( diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py b/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py index bce2154e56..f358585ab2 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py @@ -7,6 +7,7 @@ import re import unicodedata import unittest from datetime import datetime, timedelta +from unittest.mock import Mock, patch import ddt from django.conf import settings from django.contrib.auth.hashers import UNUSABLE_PASSWORD_PREFIX, make_password @@ -23,7 +24,6 @@ from django.urls import reverse from django.utils.http import int_to_base36 from edx_toggles.toggles.testutils import override_waffle_flag from freezegun import freeze_time -from mock import Mock, patch from oauth2_provider import models as dot_models from pytz import UTC @@ -290,7 +290,7 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase): assert self.user.email in sent_message.to self.assert_event_emitted( - SETTING_CHANGE_INITIATED, user_id=self.user.id, setting=u'password', old=None, new=None, + SETTING_CHANGE_INITIATED, user_id=self.user.id, setting='password', old=None, new=None, ) # Test that the user is not active @@ -321,7 +321,7 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase): assert expected_msg in msg self.assert_event_emitted( - SETTING_CHANGE_INITIATED, user_id=self.user.id, setting=u'password', old=None, new=None + SETTING_CHANGE_INITIATED, user_id=self.user.id, setting='password', old=None, new=None ) @override_settings(FEATURES=ENABLE_AUTHN_MICROFRONTEND) @@ -345,17 +345,17 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase): sent_message = mail.outbox[0] msg = sent_message.body - reset_msg = u"you requested a password reset for your user account at {}" + reset_msg = "you requested a password reset for your user account at {}" reset_msg = reset_msg.format(site_name) assert reset_msg in msg assert settings.AUTHN_MICROFRONTEND_URL in msg - sign_off = u"The {} Team".format(platform_name) + sign_off = f"The {platform_name} Team" assert sign_off in msg self.assert_event_emitted( - SETTING_CHANGE_INITIATED, user_id=self.user.id, setting=u'password', old=None, new=None + SETTING_CHANGE_INITIATED, user_id=self.user.id, setting='password', old=None, new=None ) @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', "Test only valid in LMS") @@ -384,14 +384,14 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase): body = bodies[body_type] - reset_msg = u"you requested a password reset for your user account at {}".format( + reset_msg = "you requested a password reset for your user account at {}".format( fake_get_value('PLATFORM_NAME') ) assert reset_msg in body self.assert_event_emitted( - SETTING_CHANGE_INITIATED, user_id=self.user.id, setting=u'password', old=None, new=None + SETTING_CHANGE_INITIATED, user_id=self.user.id, setting='password', old=None, new=None ) assert sent_message.from_email == 'no-reply@fakeuniversity.com' @@ -516,7 +516,7 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase): method of NFKC. In this test, the input password is u'p\u212bssword'. It should be normalized to u'p\xc5ssword' """ - password = u'p\u212bssword' + password = 'p\u212bssword' request_params = {'new_password1': password, 'new_password2': password} confirm_request = self.request_factory.post(self.password_reset_confirm_url, data=request_params) process_request(confirm_request) @@ -527,7 +527,7 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase): user = User.objects.get(pk=self.user.pk) salt_val = user.password.split('$')[1] - expected_user_password = make_password(unicodedata.normalize('NFKC', u'p\u212bssword'), salt_val) + expected_user_password = make_password(unicodedata.normalize('NFKC', 'p\u212bssword'), salt_val) assert expected_user_password == user.password self.assert_email_sent_successfully({ @@ -618,7 +618,7 @@ class PasswordResetViewTest(UserAPITestCase): """Tests of the user API's password reset endpoint. """ def setUp(self): - super(PasswordResetViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("user_api_password_reset") @ddt.data("get", "post") @@ -652,7 +652,7 @@ class PasswordResetViewTest(UserAPITestCase): assert form_desc['fields'] ==\ [{'name': 'email', 'defaultValue': '', 'type': 'email', 'required': True, 'label': 'Email', 'placeholder': 'username@domain.com', - 'instructions': u'The email address you used to register with {platform_name}' + 'instructions': 'The email address you used to register with {platform_name}' .format(platform_name=settings.PLATFORM_NAME), 'restrictions': {'min_length': EMAIL_MIN_LENGTH, 'max_length': EMAIL_MAX_LENGTH}, @@ -666,7 +666,7 @@ class PasswordResetTokenValidateViewTest(UserAPITestCase): """Tests of the user API's password reset endpoint. """ def setUp(self): - super(PasswordResetTokenValidateViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() self.user.is_active = False self.user.save() @@ -822,7 +822,7 @@ class ResetPasswordAPITests(EventTestMixin, CacheIsolationTestCase): self.assert_event_emitted( SETTING_CHANGE_INITIATED, user_id=self.user.id, - setting=u'email', + setting='email', old=self.user.email, new=updated_user.email ) diff --git a/openedx/core/djangoapps/user_authn/views/utils.py b/openedx/core/djangoapps/user_authn/views/utils.py index 87c5819502..6809dfab0d 100644 --- a/openedx/core/djangoapps/user_authn/views/utils.py +++ b/openedx/core/djangoapps/user_authn/views/utils.py @@ -1,7 +1,6 @@ """ User Auth Views Utils """ -import six from django.conf import settings from django.contrib import messages from django.utils.translation import ugettext as _ @@ -12,7 +11,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_ UUID4_REGEX = '[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}' -ENTERPRISE_ENROLLMENT_URL_REGEX = r'/enterprise/{}/course/{}/enroll'.format(UUID4_REGEX, settings.COURSE_KEY_REGEX) +ENTERPRISE_ENROLLMENT_URL_REGEX = fr'/enterprise/{UUID4_REGEX}/course/{settings.COURSE_KEY_REGEX}/enroll' def third_party_auth_context(request, redirect_to, tpa_hint=None): @@ -84,7 +83,7 @@ def third_party_auth_context(request, redirect_to, tpa_hint=None): for msg in messages.get_messages(request): if msg.extra_tags.split()[0] == "social-auth": # msg may or may not be translated. Try translating [again] in case we are able to: - context["errorMessage"] = _(six.text_type(msg)) # pylint: disable=E7610 + context["errorMessage"] = _(str(msg)) # pylint: disable=E7610 break return context