refactor: Ran pyupgrade on openedx/core/djangoapps/user_api

This commit is contained in:
Usama Sadiq
2021-03-11 17:26:03 +05:00
parent c14eab1332
commit 91ea53da56
25 changed files with 298 additions and 335 deletions

View File

@@ -114,33 +114,33 @@ class RetirementTestCase(TestCase):
`responses` for performance reasons.
"""
retirement_dict = {
u'id': retirement.id,
u'user': {
u'id': retirement.user.id,
u'username': retirement.user.username,
u'email': retirement.user.email,
u'profile': {
u'id': retirement.user.profile.id,
u'name': retirement.user.profile.name
'id': retirement.id,
'user': {
'id': retirement.user.id,
'username': retirement.user.username,
'email': retirement.user.email,
'profile': {
'id': retirement.user.profile.id,
'name': retirement.user.profile.name
},
},
u'original_username': retirement.original_username,
u'original_email': retirement.original_email,
u'original_name': retirement.original_name,
u'retired_username': retirement.retired_username,
u'retired_email': retirement.retired_email,
u'current_state': {
u'id': retirement.current_state.id,
u'state_name': retirement.current_state.state_name,
u'state_execution_order': retirement.current_state.state_execution_order,
'original_username': retirement.original_username,
'original_email': retirement.original_email,
'original_name': retirement.original_name,
'retired_username': retirement.retired_username,
'retired_email': retirement.retired_email,
'current_state': {
'id': retirement.current_state.id,
'state_name': retirement.current_state.state_name,
'state_execution_order': retirement.current_state.state_execution_order,
},
u'last_state': {
u'id': retirement.last_state.id,
u'state_name': retirement.last_state.state_name,
u'state_execution_order': retirement.last_state.state_execution_order,
'last_state': {
'id': retirement.last_state.id,
'state_name': retirement.last_state.state_name,
'state_execution_order': retirement.last_state.state_execution_order,
},
u'created': retirement.created,
u'modified': retirement.modified
'created': retirement.created,
'modified': retirement.modified
}
if all_fields:

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Unit tests for behavior that is specific to the api methods (vs. the view methods).
Most of the functionality is covered in test_views.py.
@@ -7,6 +6,7 @@ Most of the functionality is covered in test_views.py.
import itertools
import unicodedata
from unittest.mock import Mock, patch
import pytest
import ddt
from django.conf import settings
@@ -16,8 +16,6 @@ from django.http import HttpResponse
from django.test import TestCase
from django.test.client import RequestFactory
from django.urls import reverse
from mock import Mock, patch
from six import iteritems
from social_django.models import UserSocialAuth
from common.djangoapps.student.models import (
AccountRecovery,
@@ -52,7 +50,7 @@ from openedx.features.enterprise_support.tests.factories import EnterpriseCustom
def mock_render_to_string(template_name, context):
"""Return a string that encodes template_name and context"""
return str((template_name, sorted(iteritems(context))))
return str((template_name, sorted(context.items())))
def mock_render_to_response(template_name):
@@ -64,7 +62,7 @@ def mock_render_to_response(template_name):
return HttpResponse(template_name)
class CreateAccountMixin(object): # lint-amnesty, pylint: disable=missing-class-docstring
class CreateAccountMixin: # lint-amnesty, pylint: disable=missing-class-docstring
def create_account(self, username, password, email):
# pylint: disable=missing-docstring
registration_url = reverse('user_api_registration')
@@ -90,7 +88,7 @@ class TestAccountApi(UserSettingsEventTestMixin, EmailTemplateTagMixin, CreateAc
password = "test"
def setUp(self):
super(TestAccountApi, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.request_factory = RequestFactory()
self.table = "student_languageproficiency"
self.user = UserFactory.create(password=self.password)
@@ -174,7 +172,7 @@ class TestAccountApi(UserSettingsEventTestMixin, EmailTemplateTagMixin, CreateAc
def test_set_single_social_link(self):
social_links = [
dict(platform="facebook", social_link="https://www.facebook.com/{}".format(self.user.username))
dict(platform="facebook", social_link=f"https://www.facebook.com/{self.user.username}")
]
update_account_settings(self.user, {"social_links": social_links})
account_settings = get_account_settings(self.default_request)[0]
@@ -182,8 +180,8 @@ class TestAccountApi(UserSettingsEventTestMixin, EmailTemplateTagMixin, CreateAc
def test_set_multiple_social_links(self):
social_links = [
dict(platform="facebook", social_link="https://www.facebook.com/{}".format(self.user.username)),
dict(platform="twitter", social_link="https://www.twitter.com/{}".format(self.user.username)),
dict(platform="facebook", social_link=f"https://www.facebook.com/{self.user.username}"),
dict(platform="twitter", social_link=f"https://www.twitter.com/{self.user.username}"),
]
update_account_settings(self.user, {"social_links": social_links})
account_settings = get_account_settings(self.default_request)[0]
@@ -191,13 +189,13 @@ class TestAccountApi(UserSettingsEventTestMixin, EmailTemplateTagMixin, CreateAc
def test_add_social_links(self):
original_social_links = [
dict(platform="facebook", social_link="https://www.facebook.com/{}".format(self.user.username))
dict(platform="facebook", social_link=f"https://www.facebook.com/{self.user.username}")
]
update_account_settings(self.user, {"social_links": original_social_links})
extra_social_links = [
dict(platform="twitter", social_link="https://www.twitter.com/{}".format(self.user.username)),
dict(platform="linkedin", social_link="https://www.linkedin.com/in/{}".format(self.user.username)),
dict(platform="twitter", social_link=f"https://www.twitter.com/{self.user.username}"),
dict(platform="linkedin", social_link=f"https://www.linkedin.com/in/{self.user.username}"),
]
update_account_settings(self.user, {"social_links": extra_social_links})
@@ -229,7 +227,7 @@ class TestAccountApi(UserSettingsEventTestMixin, EmailTemplateTagMixin, CreateAc
def test_unsupported_social_link_platform(self):
social_links = [
dict(platform="unsupported", social_link="https://www.unsupported.com/{}".format(self.user.username))
dict(platform="unsupported", social_link=f"https://www.unsupported.com/{self.user.username}")
]
with pytest.raises(AccountValidationError):
update_account_settings(self.user, {"social_links": social_links})
@@ -502,9 +500,9 @@ class TestAccountApi(UserSettingsEventTestMixin, EmailTemplateTagMixin, CreateAc
class AccountSettingsOnCreationTest(CreateAccountMixin, TestCase):
# pylint: disable=missing-docstring
USERNAME = u'frank-underwood'
PASSWORD = u'ṕáśśẃőŕd'
EMAIL = u'frank+underwood@example.com'
USERNAME = 'frank-underwood'
PASSWORD = 'ṕáśśẃőŕd'
EMAIL = 'frank+underwood@example.com'
ID = -1
def test_create_account(self):
@@ -529,10 +527,10 @@ class AccountSettingsOnCreationTest(CreateAccountMixin, TestCase):
'email': self.EMAIL,
'id': self.ID,
'name': self.USERNAME,
'gender': None, 'goals': u'',
'gender': None, 'goals': '',
'is_active': False,
'level_of_education': None,
'mailing_address': u'',
'mailing_address': '',
'year_of_birth': None,
'country': None,
'state': None,
@@ -561,11 +559,11 @@ class AccountSettingsOnCreationTest(CreateAccountMixin, TestCase):
"""
# Set user password to NFKD format so that we can test that it is normalized to
# NFKC format upon account creation.
self.create_account(self.USERNAME, unicodedata.normalize('NFKD', u'Ṗŕệṿïệẅ Ṯệẍt'), self.EMAIL)
self.create_account(self.USERNAME, unicodedata.normalize('NFKD', 'Ṗŕệṿïệẅ Ṯệẍt'), self.EMAIL)
user = User.objects.get(username=self.USERNAME)
salt_val = user.password.split('$')[1]
expected_user_password = make_password(unicodedata.normalize('NFKC', u'Ṗŕệṿïệẅ Ṯệẍt'), salt_val)
expected_user_password = make_password(unicodedata.normalize('NFKC', 'Ṗŕệṿïệẅ Ṯệẍt'), salt_val)
assert expected_user_password == user.password

View File

@@ -5,14 +5,13 @@ Tests for helpers.py
import datetime
import hashlib
from unittest.mock import patch
from django.test import TestCase
from mock import patch
from pytz import UTC
from openedx.core.djangolib.testing.utils import skip_unless_lms
from common.djangoapps.student.tests.factories import UserFactory
from six import text_type # lint-amnesty, pylint: disable=wrong-import-order
from ..image_helpers import get_profile_image_urls_for_user
@@ -28,7 +27,7 @@ class ProfileImageUrlTestCase(TestCase):
"""
def setUp(self):
super(ProfileImageUrlTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory()
# Ensure that parental controls don't apply to this user
self.user.profile.year_of_birth = 1980
@@ -46,7 +45,7 @@ class ProfileImageUrlTestCase(TestCase):
"""
Verify correct url structure for a default profile image.
"""
assert actual_url == '/static/default_{size}.png'.format(size=expected_pixels)
assert actual_url == f'/static/default_{expected_pixels}.png'
def verify_urls(self, actual_urls, expected_name, is_default=False):
"""
@@ -68,7 +67,7 @@ class ProfileImageUrlTestCase(TestCase):
self.user.profile.profile_image_uploaded_at = TEST_PROFILE_IMAGE_UPLOAD_DT
self.user.profile.save() # lint-amnesty, pylint: disable=no-member
expected_name = hashlib.md5((
'secret' + text_type(self.user.username)).encode('utf-8')).hexdigest()
'secret' + str(self.user.username)).encode('utf-8')).hexdigest()
actual_urls = get_profile_image_urls_for_user(self.user)
self.verify_urls(actual_urls, expected_name, is_default=False)

View File

@@ -13,7 +13,7 @@ class CanDeactivateUserTest(TestCase):
""" Tests for user deactivation API permissions """
def setUp(self):
super(CanDeactivateUserTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.request = RequestFactory().get('/test/url')
def test_api_permission_superuser(self):
@@ -46,7 +46,7 @@ class CanRetireUserTest(TestCase):
""" Tests for user retirement API permissions """
def setUp(self):
super(CanRetireUserTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.request = RequestFactory().get('/test/url')
def test_api_permission_superuser(self):

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Test cases to cover account retirement views
"""
@@ -7,11 +6,10 @@ Test cases to cover account retirement views
import datetime
import json
import unittest
from unittest import mock
import ddt
import mock
import pytz
import six
from consent.models import DataSharingConsent
from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
@@ -29,8 +27,6 @@ from enterprise.models import (
from integrated_channels.sap_success_factors.models import SapSuccessFactorsLearnerDataTransmissionAudit
from opaque_keys.edx.keys import CourseKey
from rest_framework import status
from six import iteritems, text_type
from six.moves import range
from social_django.models import UserSocialAuth
from wiki.models import Article, ArticleRevision
from wiki.models.pluginbase import RevisionPlugin, RevisionPluginRevision
@@ -109,7 +105,7 @@ class TestAccountDeactivation(TestCase):
"""
def setUp(self):
super(TestAccountDeactivation, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_user = UserFactory()
self.url = reverse('accounts_deactivation', kwargs={'username': self.test_user.username})
@@ -180,7 +176,7 @@ class TestDeactivateLogout(RetirementTestCase):
Tests the account deactivation/logout endpoint.
"""
def setUp(self):
super(TestDeactivateLogout, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_password = 'password'
self.test_user = UserFactory(password=self.test_password)
UserSocialAuth.objects.create(
@@ -277,7 +273,7 @@ class TestPartnerReportingCleanup(ModuleStoreTestCase):
"""
def setUp(self):
super(TestPartnerReportingCleanup, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_superuser = SuperuserFactory()
self.course = CourseFactory()
self.course_awesome_org = CourseFactory(org='awesome_org')
@@ -389,7 +385,7 @@ class TestPartnerReportingPut(RetirementTestCase, ModuleStoreTestCase):
"""
def setUp(self):
super(TestPartnerReportingPut, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_superuser = SuperuserFactory()
self.course = CourseFactory()
self.course_awesome_org = CourseFactory(org='awesome_org')
@@ -496,7 +492,7 @@ class TestPartnerReportingList(ModuleStoreTestCase):
]
def setUp(self):
super(TestPartnerReportingList, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_superuser = SuperuserFactory()
self.course = CourseFactory()
self.course_awesome_org = CourseFactory(org='awesome_org')
@@ -698,7 +694,7 @@ class TestAccountRetirementList(RetirementTestCase):
"""
def setUp(self):
super(TestAccountRetirementList, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_superuser = SuperuserFactory()
self.headers = build_jwt_headers(self.test_superuser)
self.url = reverse('accounts_retirement_queue')
@@ -737,7 +733,7 @@ class TestAccountRetirementList(RetirementTestCase):
del retirement['created']
del retirement['modified']
six.assertCountEqual(self, response_data, expected_data)
self.assertCountEqual(response_data, expected_data)
def test_empty(self):
"""
@@ -858,7 +854,7 @@ class TestAccountRetirementsByStatusAndDate(RetirementTestCase):
"""
def setUp(self):
super(TestAccountRetirementsByStatusAndDate, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_superuser = SuperuserFactory()
self.headers = build_jwt_headers(self.test_superuser)
self.url = reverse('accounts_retirements_by_status_and_date')
@@ -910,7 +906,7 @@ class TestAccountRetirementsByStatusAndDate(RetirementTestCase):
except KeyError:
pass
six.assertCountEqual(self, response_data, expected_data)
self.assertCountEqual(response_data, expected_data)
def test_empty(self):
"""
@@ -1005,7 +1001,7 @@ class TestAccountRetirementRetrieve(RetirementTestCase):
Tests the account retirement retrieval endpoint.
"""
def setUp(self):
super(TestAccountRetirementRetrieve, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_user = UserFactory()
self.test_superuser = SuperuserFactory()
self.url = reverse('accounts_retirement_retrieve', kwargs={'username': self.test_user.username})
@@ -1076,7 +1072,7 @@ class TestAccountRetirementCleanup(RetirementTestCase):
Tests the account retirement cleanup endpoint.
"""
def setUp(self):
super(TestAccountRetirementCleanup, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.pending_state = RetirementState.objects.get(state_name='PENDING')
self.complete_state = RetirementState.objects.get(state_name='COMPLETE')
self.retirements = []
@@ -1151,7 +1147,7 @@ class TestAccountRetirementUpdate(RetirementTestCase):
Tests the account retirement endpoint.
"""
def setUp(self):
super(TestAccountRetirementUpdate, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.pending_state = RetirementState.objects.get(state_name='PENDING')
self.locking_state = RetirementState.objects.get(state_name='LOCKING_ACCOUNT')
@@ -1291,7 +1287,7 @@ class TestAccountRetirementPost(RetirementTestCase):
Tests the account retirement endpoint.
"""
def setUp(self):
super(TestAccountRetirementPost, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_user = UserFactory()
self.test_superuser = SuperuserFactory()
@@ -1403,7 +1399,7 @@ class TestAccountRetirementPost(RetirementTestCase):
with mock.patch(path, side_effect=Exception('Unexpected Exception')) as mock_get_retirement:
data = {'username': self.test_user.username}
response = self.post_and_assert_status(data, status.HTTP_500_INTERNAL_SERVER_ERROR)
assert 'Unexpected Exception' == text_type(response.json())
assert 'Unexpected Exception' == str(response.json())
mock_get_retirement.assert_called_once_with(self.original_username)
def test_retire_user_where_user_already_retired(self):
@@ -1416,7 +1412,7 @@ class TestAccountRetirementPost(RetirementTestCase):
def test_retire_user_where_username_not_provided(self):
response = self.post_and_assert_status({}, status.HTTP_404_NOT_FOUND)
expected_response_message = {'message': text_type('The user was not specified.')}
expected_response_message = {'message': 'The user was not specified.'}
assert expected_response_message == response.json()
@mock.patch('openedx.core.djangoapps.user_api.accounts.views.get_profile_image_names')
@@ -1434,10 +1430,10 @@ class TestAccountRetirementPost(RetirementTestCase):
'is_active': False,
'username': self.retired_username,
}
for field, expected_value in iteritems(expected_user_values):
for field, expected_value in expected_user_values.items():
assert expected_value == getattr(self.test_user, field)
for field, expected_value in iteritems(USER_PROFILE_PII):
for field, expected_value in USER_PROFILE_PII.items():
assert expected_value == getattr(self.test_user.profile, field)
assert self.test_user.profile.profile_image_uploaded_at is None
@@ -1468,7 +1464,7 @@ class TestAccountRetirementPost(RetirementTestCase):
self.post_and_assert_status(data)
def test_deletes_pii_from_user_profile(self):
for model_field, value_to_assign in iteritems(USER_PROFILE_PII):
for model_field, value_to_assign in USER_PROFILE_PII.items():
if value_to_assign == '':
value = 'foo'
else:
@@ -1477,7 +1473,7 @@ class TestAccountRetirementPost(RetirementTestCase):
AccountRetirementView.clear_pii_from_userprofile(self.test_user)
for model_field, value_to_assign in iteritems(USER_PROFILE_PII):
for model_field, value_to_assign in USER_PROFILE_PII.items():
assert value_to_assign == getattr(self.test_user.profile, model_field)
social_links = SocialLink.objects.filter(
@@ -1570,7 +1566,7 @@ class TestLMSAccountRetirementPost(RetirementTestCase, ModuleStoreTestCase):
Tests the LMS account retirement (GDPR P2) endpoint.
"""
def setUp(self):
super(TestLMSAccountRetirementPost, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.pii_standin = 'PII here'
self.course = CourseFactory()
self.test_user = UserFactory()

View File

@@ -18,7 +18,7 @@ LOGGER_NAME = "openedx.core.djangoapps.user_api.accounts.serializers"
class UserReadOnlySerializerTest(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
def setUp(self):
super(UserReadOnlySerializerTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
request_factory = RequestFactory()
self.request = request_factory.get('/api/user/v1/accounts/')
self.user = UserFactory.build(username='test_user', email='test_user@test.com')

View File

@@ -1,8 +1,7 @@
""" Tests for views related to account settings. """
# -*- coding: utf-8 -*-
import mock
from unittest import mock
from django.conf import settings
from django.contrib import messages
from django.contrib.messages.middleware import MessageMiddleware
@@ -49,7 +48,7 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, SiteMixin, ProgramsApiCon
@mock.patch("django.conf.settings.MESSAGE_STORAGE", 'django.contrib.messages.storage.cookie.CookieStorage')
def setUp(self): # pylint: disable=arguments-differ
super(AccountSettingsViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
CommerceConfiguration.objects.create(cache_ttl=10, enabled=True)
self.client.login(username=self.USERNAME, password=self.PASSWORD)

View File

@@ -22,7 +22,7 @@ class UserAccountSettingsTest(TestCase):
"""Unit tests for setting Social Media Links."""
def setUp(self): # lint-amnesty, pylint: disable=useless-super-delegation
super(UserAccountSettingsTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
def validate_social_link(self, social_platform, link):
"""
@@ -71,7 +71,7 @@ class CompletionUtilsTestCase(SharedModuleStoreTestCase, CompletionWaffleTestMix
"""
Creates a test course that can be used for non-destructive tests
"""
super(CompletionUtilsTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.override_waffle_switch(True)
self.engaged_user = UserFactory.create()
self.cruft_user = UserFactory.create()
@@ -122,7 +122,7 @@ class CompletionUtilsTestCase(SharedModuleStoreTestCase, CompletionWaffleTestMix
self.cruft_user
)
assert block_url ==\
u'test_url:9999/courses/{org}/{course}/{run}/jump_to/i4x://{org}/{course}/vertical/{vertical_id}'.format(
'test_url:9999/courses/{org}/{course}/{run}/jump_to/i4x://{org}/{course}/vertical/{vertical_id}'.format(
org=self.course.location.course_key.org,
course=self.course.location.course_key.course,
run=self.course.location.course_key.run,

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Test cases to cover Accounts-related behaviors of the User API application
"""
@@ -8,17 +7,15 @@ import datetime
import hashlib
import json
from copy import deepcopy
from unittest import mock
import ddt
import mock
import pytz
import six
from django.conf import settings
from django.test.testcases import TransactionTestCase
from django.test.utils import override_settings
from django.urls import reverse
from rest_framework.test import APIClient, APITestCase
from six.moves import range
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user
from openedx.core.djangoapps.user_api.accounts import ACCOUNT_VISIBILITY_PREF_KEY
@@ -37,8 +34,8 @@ TEST_PROFILE_IMAGE_UPLOADED_AT = datetime.datetime(2002, 1, 9, 15, 43, 1, tzinfo
TEST_PROFILE_IMAGE_BACKEND = deepcopy(settings.PROFILE_IMAGE_BACKEND)
TEST_PROFILE_IMAGE_BACKEND['options']['base_url'] = '/profile-images/'
TEST_BIO_VALUE = u"Tired mother of twins"
TEST_LANGUAGE_PROFICIENCY_CODE = u"hi"
TEST_BIO_VALUE = "Tired mother of twins"
TEST_LANGUAGE_PROFICIENCY_CODE = "hi"
class UserAPITestCase(APITestCase):
@@ -47,7 +44,7 @@ class UserAPITestCase(APITestCase):
"""
def setUp(self):
super(UserAPITestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.anonymous_client = APIClient()
self.different_user = UserFactory.create(password=TEST_PASSWORD)
@@ -151,7 +148,7 @@ class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase):
ENABLED_CACHES = ['default']
def setUp(self):
super(TestOwnUsernameAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.url = reverse("own_username_api")
@@ -209,7 +206,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
ENABLED_CACHES = ['default']
def setUp(self):
super(TestAccountsAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.url = reverse("accounts_api", kwargs={'username': self.user.username})
@@ -341,7 +338,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
self.create_mock_profile(self.user)
set_user_preference(self.user, ACCOUNT_VISIBILITY_PREF_KEY, PRIVATE_VISIBILITY)
response = self.send_get(client, query_parameters='email={}'.format(self.user.email))
response = self.send_get(client, query_parameters=f'email={self.user.email}')
self._verify_full_account_response(response)
# Note: using getattr so that the patching works even if there is no configuration.
@@ -413,7 +410,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
response = self.send_get(client, query_parameters='view=shared')
verify_fields_visible_to_all_users(response)
response = self.send_get(client, query_parameters='view=shared&email={}'.format(self.user.email))
response = self.send_get(client, query_parameters=f'view=shared&email={self.user.email}')
verify_fields_visible_to_all_users(response)
@ddt.data(
@@ -428,7 +425,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
set_user_preference(self.user, ACCOUNT_VISIBILITY_PREF_KEY, CUSTOM_VISIBILITY)
shared_fields = ("bio", "language_proficiencies", "name")
for field_name in shared_fields:
set_user_preference(self.user, "visibility.{}".format(field_name), ALL_USERS_VISIBILITY)
set_user_preference(self.user, f"visibility.{field_name}", ALL_USERS_VISIBILITY)
# make API request
client = self.login_client(api_client, requesting_username)
@@ -465,7 +462,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
set_user_preference(self.user, ACCOUNT_VISIBILITY_PREF_KEY, CUSTOM_VISIBILITY)
shared_fields = ("bio", "language_proficiencies")
for field_name in shared_fields:
set_user_preference(self.user, "visibility.{}".format(field_name), ALL_USERS_VISIBILITY)
set_user_preference(self.user, f"visibility.{field_name}", ALL_USERS_VISIBILITY)
# make API request
client = self.login_client(api_client, requesting_username)
@@ -572,19 +569,19 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
assert 403 == response.status_code
@ddt.data(
("gender", "f", "not a gender", u'"not a gender" is not a valid choice.'),
("level_of_education", "none", u"ȻħȺɍłɇs", u'"ȻħȺɍłɇs" is not a valid choice.'),
("country", "GB", "XY", u'"XY" is not a valid choice.'),
("state", "MA", "PY", u'"PY" is not a valid choice.'),
("year_of_birth", 2009, "not_an_int", u"A valid integer is required."),
("name", "bob", "z" * 256, u"Ensure this field has no more than 255 characters."),
("name", u"ȻħȺɍłɇs", " ", u"The name field must be at least 1 character long."),
("gender", "f", "not a gender", '"not a gender" is not a valid choice.'),
("level_of_education", "none", "ȻħȺɍłɇs", '"ȻħȺɍłɇs" is not a valid choice.'),
("country", "GB", "XY", '"XY" is not a valid choice.'),
("state", "MA", "PY", '"PY" is not a valid choice.'),
("year_of_birth", 2009, "not_an_int", "A valid integer is required."),
("name", "bob", "z" * 256, "Ensure this field has no more than 255 characters."),
("name", "ȻħȺɍłɇs", " ", "The name field must be at least 1 character long."),
("goals", "Smell the roses"),
("mailing_address", "Sesame Street"),
# Note that we store the raw data, so it is up to client to escape the HTML.
(
"bio", u"<html>Lacrosse-playing superhero 壓是進界推日不復女</html>",
"z" * 301, u"The about me field must be at most 300 characters long."
"bio", "<html>Lacrosse-playing superhero 壓是進界推日不復女</html>",
"z" * 301, "The about me field must be at most 300 characters long."
),
("account_privacy", ALL_USERS_VISIBILITY),
("account_privacy", PRIVATE_VISIBILITY),
@@ -610,13 +607,13 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
if fails_validation_value:
error_response = self.send_patch(client, {field: fails_validation_value}, expected_status=400)
expected_user_message = u'This value is invalid.'
expected_user_message = 'This value is invalid.'
if field == 'bio':
expected_user_message = u"The about me field must be at most 300 characters long."
expected_user_message = "The about me field must be at most 300 characters long."
assert expected_user_message == error_response.data['field_errors'][field]['user_message']
assert u"Value '{value}' is not valid for field '{field}': {messages}"\
assert "Value '{value}' is not valid for field '{field}': {messages}"\
.format(value=fails_validation_value,
field=field,
messages=[developer_validation_message]) ==\
@@ -648,7 +645,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
Internal helper to check the error messages returned
"""
assert 'This field is not editable via this API' == data['field_errors'][field_name]['developer_message']
assert u"The '{0}' field cannot be edited."\
assert "The '{}' field cannot be edited."\
.format(field_name) == data['field_errors'][field_name]['user_message']
for field_name in ["username", "date_joined", "is_active", "profile_image", "requires_parental_consent"]:
@@ -708,7 +705,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
"""
assert 3 == len(change_info)
assert old_name == change_info[0]
assert u'Name change requested through account API by {}'.format(requester) == change_info[1]
assert f'Name change requested through account API by {requester}' == change_info[1]
assert change_info[2] is not None
# Verify the new name was also stored.
get_response = self.send_get(self.client)
@@ -812,28 +809,28 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
# than django model id.
for proficiencies in ([{"code": "en"}, {"code": "fr"}, {"code": "es"}], [{"code": "fr"}], [{"code": "aa"}], []):
response = self.send_patch(client, {"language_proficiencies": proficiencies})
six.assertCountEqual(self, response.data["language_proficiencies"], proficiencies)
self.assertCountEqual(response.data["language_proficiencies"], proficiencies)
@ddt.data(
(
u"not_a_list",
{u'non_field_errors': [u'Expected a list of items but got type "unicode".']}
"not_a_list",
{'non_field_errors': ['Expected a list of items but got type "unicode".']}
),
(
[u"not_a_JSON_object"],
[{u'non_field_errors': [u'Invalid data. Expected a dictionary, but got unicode.']}]
["not_a_JSON_object"],
[{'non_field_errors': ['Invalid data. Expected a dictionary, but got unicode.']}]
),
(
[{}],
[{'code': [u'This field is required.']}]
[{'code': ['This field is required.']}]
),
(
[{u"code": u"invalid_language_code"}],
[{'code': [u'"invalid_language_code" is not a valid choice.']}]
[{"code": "invalid_language_code"}],
[{'code': ['"invalid_language_code" is not a valid choice.']}]
),
(
[{u"code": u"kw"}, {u"code": u"el"}, {u"code": u"kw"}],
[u'The language_proficiencies field must consist of unique languages.']
[{"code": "kw"}, {"code": "el"}, {"code": "kw"}],
['The language_proficiencies field must consist of unique languages.']
),
)
@ddt.unpack
@@ -842,8 +839,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
Verify we handle error cases when patching the language_proficiencies
field.
"""
if six.PY3:
expected_error_message = six.text_type(expected_error_message).replace('unicode', 'str')
expected_error_message = str(expected_error_message).replace('unicode', 'str')
client = self.login_client("client", "user")
response = self.send_patch(client, {"language_proficiencies": patch_value}, expected_status=400)
@@ -925,7 +921,7 @@ class TestAccountAPITransactions(TransactionTestCase):
"""
def setUp(self):
super(TestAccountAPITransactions, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.client = APIClient()
self.user = UserFactory.create(password=TEST_PASSWORD)
self.url = reverse("accounts_api", kwargs={'username': self.user.username})
@@ -950,7 +946,7 @@ class TestAccountAPITransactions(TransactionTestCase):
response = self.client.get(self.url)
data = response.data
assert old_email == data['email']
assert u'm' == data['gender']
assert 'm' == data['gender']
@ddt.ddt
@@ -960,7 +956,7 @@ class UsernameReplacementViewTests(APITestCase):
SERVICE_USERNAME = 'test_replace_username_service_worker'
def setUp(self):
super(UsernameReplacementViewTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.service_user = UserFactory(username=self.SERVICE_USERNAME)
self.url = reverse("username_replacement")
@@ -969,7 +965,7 @@ class UsernameReplacementViewTests(APITestCase):
Helper function for creating headers for the JWT authentication.
"""
token = create_jwt_for_user(user)
headers = {'HTTP_AUTHORIZATION': u'JWT {}'.format(token)}
headers = {'HTTP_AUTHORIZATION': f'JWT {token}'}
return headers
def call_api(self, user, data):

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Utility functions, constants, etc. for testing.
"""
@@ -10,7 +9,7 @@ from common.djangoapps.util.password_policy_validators import DEFAULT_MAX_PASSWO
INVALID_NAMES = [
None,
'',
u''
''
]
INVALID_USERNAMES_ASCII = [
@@ -20,39 +19,39 @@ INVALID_USERNAMES_ASCII = [
]
INVALID_USERNAMES_UNICODE = [
u'invalid-unicode_fŕáńḱ',
'invalid-unicode_fŕáńḱ',
]
INVALID_USERNAMES = [
None,
u'',
u'a',
u'a' * (USERNAME_MAX_LENGTH + 1),
'',
'a',
'a' * (USERNAME_MAX_LENGTH + 1),
] + INVALID_USERNAMES_ASCII + INVALID_USERNAMES_UNICODE
INVALID_EMAILS = [
None,
u'',
u'a',
'',
'a',
'no_domain',
'no+domain',
'@',
'@domain.com',
'test@no_extension',
u'fŕáńḱ@example.com',
'fŕáńḱ@example.com',
# Long email -- subtract the length of the @domain
# except for one character (so we exceed the max length limit)
u'{user}@example.com'.format(
user=(u'e' * (EMAIL_MAX_LENGTH - 11))
'{user}@example.com'.format(
user=('e' * (EMAIL_MAX_LENGTH - 11))
)
]
INVALID_PASSWORDS = [
None,
u'',
u'a',
u'a' * (DEFAULT_MAX_PASSWORD_LENGTH + 1),
'',
'a',
'a' * (DEFAULT_MAX_PASSWORD_LENGTH + 1),
]
INVALID_COUNTRIES = [
@@ -63,25 +62,25 @@ INVALID_COUNTRIES = [
VALID_NAMES = [
'Validation Bot',
u'Validation Bot'
'Validation Bot'
]
VALID_USERNAMES_UNICODE = [
u'Enchanté',
u'username_with_@',
u'username with spaces',
u'eastern_arabic_numbers_١٢٣',
'Enchanté',
'username_with_@',
'username with spaces',
'eastern_arabic_numbers_١٢٣',
]
VALID_USERNAMES = [
u'username',
u'a' * USERNAME_MIN_LENGTH,
u'a' * USERNAME_MAX_LENGTH,
u'-' * USERNAME_MIN_LENGTH,
u'-' * USERNAME_MAX_LENGTH,
u'_username_',
u'-username-',
u'-_username_-'
'username',
'a' * USERNAME_MIN_LENGTH,
'a' * USERNAME_MAX_LENGTH,
'-' * USERNAME_MIN_LENGTH,
'-' * USERNAME_MAX_LENGTH,
'_username_',
'-username-',
'-_username_-'
]
VALID_EMAILS = [
@@ -89,11 +88,11 @@ VALID_EMAILS = [
]
VALID_PASSWORDS = [
u'good_password_339',
'good_password_339',
]
VALID_COUNTRIES = [
u'PK',
u'Pakistan',
u'US'
'PK',
'Pakistan',
'US'
]

View File

@@ -16,7 +16,7 @@ class TestCourseTagAPI(TestCase):
"""
def setUp(self):
super(TestCourseTagAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory.create()
self.course_id = CourseLocator('test_org', 'test_course_number', 'test_run')
self.test_key = 'test_key'

View File

@@ -25,7 +25,6 @@ from textwrap import dedent
from django.core.management.base import BaseCommand, CommandError
from django.db import connections
from django.db.utils import DatabaseError
from six.moves import range
log = logging.getLogger(__name__)
@@ -89,15 +88,15 @@ class Command(BaseCommand):
optout_path = options['optout_csv_path']
if chunk_size <= 0:
raise CommandError(u'Only positive chunk size is allowed ({}).'.format(chunk_size))
raise CommandError(f'Only positive chunk size is allowed ({chunk_size}).')
if sleep_between < 0:
raise CommandError(u'Only non-negative sleep between seconds is allowed ({}).'.format(sleep_between))
raise CommandError(f'Only non-negative sleep between seconds is allowed ({sleep_between}).')
# Read the CSV file. Log the number of user/org rows read.
with open(optout_path, 'r') as csv_file:
with open(optout_path) as csv_file:
optout_reader = csv.reader(csv_file)
optout_rows = list(optout_reader)
log.info(u"Read %s opt-out rows from CSV file '%s'.", len(optout_rows), optout_path)
log.info("Read %s opt-out rows from CSV file '%s'.", len(optout_rows), optout_path)
cursor = connections['default'].cursor()
@@ -108,7 +107,7 @@ class Command(BaseCommand):
start_idx = curr_row_idx
end_idx = min(start_idx + chunk_size - 1, len(optout_rows) - 1)
log.info(u"Attempting opt-out for rows (%s, %s) through (%s, %s)...",
log.info("Attempting opt-out for rows (%s, %s) through (%s, %s)...",
optout_rows[start_idx][0], optout_rows[start_idx][1],
optout_rows[end_idx][0], optout_rows[end_idx][1])
@@ -131,16 +130,16 @@ class Command(BaseCommand):
cursor.execute(query)
except DatabaseError as err:
cursor.execute('ROLLBACK;')
log.error(u"Rolled-back opt-out for rows (%s, %s) through (%s, %s): %s",
log.error("Rolled-back opt-out for rows (%s, %s) through (%s, %s): %s",
optout_rows[start_idx][0], optout_rows[start_idx][1],
optout_rows[end_idx][0], optout_rows[end_idx][1],
str(err))
raise
else:
cursor.execute('COMMIT;')
log.info(u"Committed opt-out for rows (%s, %s) through (%s, %s).",
log.info("Committed opt-out for rows (%s, %s) through (%s, %s).",
optout_rows[start_idx][0], optout_rows[start_idx][1],
optout_rows[end_idx][0], optout_rows[end_idx][1])
log.info(u"Sleeping %s seconds...", sleep_between)
log.info("Sleeping %s seconds...", sleep_between)
time.sleep(sleep_between)
curr_row_idx += chunk_size

View File

@@ -37,13 +37,13 @@ class Command(BaseCommand):
original_email=email_address
)
except UserRetirementStatus.DoesNotExist:
raise CommandError(u"No retirement request with email address '{}' exists.".format(email_address)) # lint-amnesty, pylint: disable=raise-missing-from
raise CommandError(f"No retirement request with email address '{email_address}' exists.") # lint-amnesty, pylint: disable=raise-missing-from
# Check if the user has started the retirement process -or- not.
if retirement_status.current_state.state_name != 'PENDING':
raise CommandError(
u"Retirement requests can only be cancelled for users in the PENDING state."
u" Current request state for '{}': {}".format(
"Retirement requests can only be cancelled for users in the PENDING state."
" Current request state for '{}': {}".format(
email_address,
retirement_status.current_state.state_name
)
@@ -58,4 +58,4 @@ class Command(BaseCommand):
# No need to delete the accompanying "permanent" retirement request record - it gets done via Django signal.
retirement_status.delete()
print(u"Successfully cancelled retirement request for user with email address '{}'.".format(email_address))
print(f"Successfully cancelled retirement request for user with email address '{email_address}'.")

View File

@@ -33,9 +33,6 @@ from django.core.management.base import BaseCommand, CommandError
from django.db import connections
from django.utils import timezone
from opaque_keys.edx.keys import CourseKey # lint-amnesty, pylint: disable=unused-import
import six
from six import text_type
from six.moves import range
from xmodule.modulestore.django import modulestore
@@ -88,7 +85,7 @@ class Command(BaseCommand):
QUERY_INTERVAL = 1000
# Default datetime if the user has not set a preference
DEFAULT_DATETIME_STR = datetime.datetime(year=2014, month=12, day=1).isoformat(str(' '))
DEFAULT_DATETIME_STR = datetime.datetime(year=2014, month=12, day=1).isoformat(' ')
def handle(self, *args, **options):
"""
@@ -109,7 +106,7 @@ class Command(BaseCommand):
org_list = options['org_list']
if os.path.exists(file_path):
raise CommandError("File already exists at '{path}'".format(path=file_path))
raise CommandError(f"File already exists at '{file_path}'")
only_courses = options.get("courses")
@@ -120,7 +117,7 @@ class Command(BaseCommand):
courses = self._get_courses_for_org(org_list)
# Add in organizations from the course keys, to ensure we're including orgs with different capitalizations
org_list = list(set(org_list) | set(course.org for course in courses))
org_list = list(set(org_list) | {course.org for course in courses})
else:
courses = list(set(only_courses.split(",")))
@@ -135,7 +132,7 @@ class Command(BaseCommand):
# Let the user know what's about to happen
LOGGER.info(
"Retrieving data for courses: {courses}".format(
courses=", ".join([text_type(course) for course in courses])
courses=", ".join([str(course) for course in courses])
)
)
@@ -148,7 +145,7 @@ class Command(BaseCommand):
self._write_email_opt_in_prefs(file_handle, org_list, course_group)
# Remind the user where the output file is
LOGGER.info("Output file: {file_path}".format(file_path=file_path))
LOGGER.info(f"Output file: {file_path}")
def _get_courses_for_org(self, org_aliases):
"""
@@ -176,7 +173,7 @@ class Command(BaseCommand):
start_time = time.time()
yield
execution_time = time.time() - start_time
LOGGER.info("Execution time: {time} seconds".format(time=execution_time))
LOGGER.info(f"Execution time: {execution_time} seconds")
def _write_email_opt_in_prefs(self, file_handle, org_aliases, courses):
"""
@@ -254,19 +251,19 @@ class Command(BaseCommand):
# Only encode to utf-8 in python2 because python3's csv writer can handle unicode.
writer.writerow({
"user_id": user_id,
"username": username.encode('utf-8') if six.PY2 else username,
"email": email.encode('utf-8') if six.PY2 else email,
"username": username,
"email": email,
# There should not be a case where users are without full_names. We only need this safe check because
# of ECOM-1995.
"full_name": full_name.encode('utf-8') if six.PY2 else full_name,
"course_id": course_id.encode('utf-8') if six.PY2 else course_id,
"full_name": full_name,
"course_id": course_id,
"is_opted_in_for_email": is_opted_in if is_opted_in else "True",
"preference_set_datetime": pref_set_datetime,
})
row_count += 1
# Log the number of rows we processed
LOGGER.info("Retrieved {num_rows} records for orgs {org}.".format(num_rows=row_count, org=org_aliases))
LOGGER.info(f"Retrieved {row_count} records for orgs {org_aliases}.")
def _iterate_results(self, cursor):
"""
@@ -282,14 +279,13 @@ class Command(BaseCommand):
rows = cursor.fetchmany(self.QUERY_INTERVAL)
if not rows:
break
for row in rows:
yield row
yield from rows
def _sql_list(self, values):
"""
Serialize a list of values for including in a SQL "IN" statement.
"""
return ",".join(['"{}"'.format(val) for val in values])
return ",".join([f'"{val}"' for val in values])
def _db_cursor(self):
"""

View File

@@ -62,14 +62,14 @@ class Command(BaseCommand):
langs += dark_lang_config.beta_languages_list if dark_lang_config.enable_beta_languages else []
if new_lang_code not in langs:
raise CommandError(u'{} is not a configured language code in settings.LANGUAGES '
raise CommandError('{} is not a configured language code in settings.LANGUAGES '
'or the current DarkLangConfig.'.format(new_lang_code))
max_id = UserPreference.objects.all().aggregate(Max('id'))['id__max']
print(u'Updating user language preferences from {} to {}. '
u'Start id is {}, current max id is {}. '
u'Chunk size is of {}'.format(old_lang_code, new_lang_code, start, max_id, chunk_size))
print('Updating user language preferences from {} to {}. '
'Start id is {}, current max id is {}. '
'Chunk size is of {}'.format(old_lang_code, new_lang_code, start, max_id, chunk_size))
updated_count = 0
@@ -89,7 +89,7 @@ class Command(BaseCommand):
updated_count += curr
print(u'Updated rows {} to {}, {} rows affected'.format(start, end - 1, curr))
print('Updated rows {} to {}, {} rows affected'.format(start, end - 1, curr))
if end >= max_id:
break
@@ -98,7 +98,7 @@ class Command(BaseCommand):
end += chunk_size
sleep(sleep_time_secs)
print(u'Finished! Updated {} total preferences from {} to {}'.format(
print('Finished! Updated {} total preferences from {} to {}'.format(
updated_count,
old_lang_code,
new_lang_code

View File

@@ -50,17 +50,17 @@ class Command(BaseCommand):
raise CommandError('settings.RETIREMENT_STATES does not exist or is empty.')
if not set(REQUIRED_STATES).issubset(set(new_states)):
raise CommandError(u'settings.RETIREMENT_STATES ({}) does not contain all required states '
u'({})'.format(new_states, REQ_STR))
raise CommandError('settings.RETIREMENT_STATES ({}) does not contain all required states '
'({})'.format(new_states, REQ_STR))
# Confirm that the start and end states are in the right places
if new_states.index(START_STATE) != 0:
raise CommandError(u'{} must be the first state'.format(START_STATE))
raise CommandError(f'{START_STATE} must be the first state')
num_end_states = len(END_STATES)
if new_states[-num_end_states:] != END_STATES:
raise CommandError(u'The last {} states must be these (in this order): '
raise CommandError('The last {} states must be these (in this order): '
'{}'.format(num_end_states, END_STATES))
def _check_current_users(self):
@@ -75,8 +75,8 @@ class Command(BaseCommand):
def _check_users_in_states_to_delete(self, states_to_delete):
if UserRetirementStatus.objects.filter(current_state__state_name__in=states_to_delete).exists():
raise CommandError(u'Users exist in a state that is marked for deletion! States to delete'
u'are: {}'.format(states_to_delete))
raise CommandError('Users exist in a state that is marked for deletion! States to delete'
'are: {}'.format(states_to_delete))
def _delete_old_states_and_create_new(self, new_states, dry_run=False):
"""
@@ -151,9 +151,9 @@ class Command(BaseCommand):
# Report
print("States have been synchronized. Differences:")
print(u" Added: {}".format(created))
print(u" Removed: {}".format(deleted))
print(u" Remaining: {}".format(existed))
print(f" Added: {created}")
print(f" Removed: {deleted}")
print(f" Remaining: {existed}")
print("States updated successfully. Current states:")
for state in RetirementState.objects.all():

View File

@@ -85,15 +85,15 @@ class Command(BaseCommand):
retire_dot_oauth2_models(user)
AccountRecovery.retire_recovery_email(user.id)
except KeyError:
error_message = 'Username not specified {}'.format(user)
error_message = f'Username not specified {user}'
logger.error(error_message)
raise CommandError(error_message) # lint-amnesty, pylint: disable=raise-missing-from
except user_model.DoesNotExist:
error_message = 'The user "{}" does not exist.'.format(user.username)
error_message = f'The user "{user.username}" does not exist.'
logger.error(error_message)
raise CommandError(error_message) # lint-amnesty, pylint: disable=raise-missing-from
except Exception as exc: # pylint: disable=broad-except
error_message = '500 error deactivating account {}'.format(exc)
error_message = f'500 error deactivating account {exc}'
logger.error(error_message)
raise CommandError(error_message) # lint-amnesty, pylint: disable=raise-missing-from

View File

@@ -11,7 +11,7 @@ import traceback
from datetime import datetime, timedelta
from textwrap import dedent
import six.moves.urllib.parse # pylint: disable=import-error
import urllib.parse # pylint: disable=import-error
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.management.base import BaseCommand, CommandError
from edx_rest_api_client.client import EdxRestApiClient
@@ -49,7 +49,7 @@ class Command(BaseCommand):
"""
start_date = datetime.now().date() - timedelta(initial_days)
end_date = datetime.now().date() - timedelta(1)
self.stdout.write(u'Getting users from {start} to {end}'.format(start=start_date, end=end_date))
self.stdout.write(f'Getting users from {start_date} to {end_date}')
users_qs = User.objects.filter(
date_joined__date__gte=start_date,
date_joined__date__lte=end_date
@@ -68,7 +68,7 @@ class Command(BaseCommand):
"""
self.stdout.write(
u'Fetching Users for site {site} from {start} to {end}'.format(
'Fetching Users for site {site} from {start} to {end}'.format(
site=site_domain, start=offset, end=offset + users_query_batch_size
)
)
@@ -77,7 +77,7 @@ class Command(BaseCommand):
user for user in users
if UserAttribute.get_user_attribute(user, 'created_on_site') == site_domain
]
self.stdout.write(u'\tSite Users={count}'.format(count=len(site_users)))
self.stdout.write('\tSite Users={count}'.format(count=len(site_users)))
return site_users
@@ -88,15 +88,15 @@ class Command(BaseCommand):
contacts = []
for user in users_batch:
if not hasattr(user, 'profile'):
self.stdout.write(u'skipping user {} due to no profile found'.format(user))
self.stdout.write(f'skipping user {user} due to no profile found')
continue
if not user.profile.meta:
self.stdout.write(u'skipping user {} due to no profile meta found'.format(user))
self.stdout.write(f'skipping user {user} due to no profile meta found')
continue
try:
meta = json.loads(user.profile.meta)
except ValueError:
self.stdout.write(u'skipping user {} due to invalid profile meta found'.format(user))
self.stdout.write(f'skipping user {user} due to invalid profile meta found')
continue
contact = {
@@ -139,12 +139,12 @@ class Command(BaseCommand):
contacts.append(contact)
api_key = site_conf.get_value('HUBSPOT_API_KEY')
client = EdxRestApiClient(six.moves.urllib.parse.urljoin(HUBSPOT_API_BASE_URL, 'contacts/v1/contact'))
client = EdxRestApiClient(urllib.parse.urljoin(HUBSPOT_API_BASE_URL, 'contacts/v1/contact'))
try:
client.batch.post(contacts, hapikey=api_key)
return len(contacts)
except (HttpClientError, HttpServerError) as ex:
message = u'An error occurred while syncing batch of contacts for site {domain}, {message}'.format(
message = 'An error occurred while syncing batch of contacts for site {domain}, {message}'.format(
domain=site_conf.site.domain, message=ex.message # lint-amnesty, pylint: disable=no-member
)
self.stderr.write(message)
@@ -155,7 +155,7 @@ class Command(BaseCommand):
Syncs a single site
"""
site_domain = site_conf.site.domain
self.stdout.write(u'Syncing process started for site {site}'.format(site=site_domain))
self.stdout.write(f'Syncing process started for site {site_domain}')
offset = 0
users_queue = []
@@ -165,7 +165,7 @@ class Command(BaseCommand):
while offset < users_count:
is_last_iteration = (offset + users_query_batch_size) >= users_count
self.stdout.write(
u'Syncing users batch from {start} to {end} for site {site}'.format(
'Syncing users batch from {start} to {end} for site {site}'.format(
start=offset, end=offset + users_query_batch_size, site=site_domain
)
)
@@ -177,14 +177,14 @@ class Command(BaseCommand):
successfully_synced_contacts += self._sync_with_hubspot(users_batch, site_conf)
time.sleep(0.1) # to make sure request per second could not exceed by 10
self.stdout.write(
u'Successfully synced users batch from {start} to {end} for site {site}'.format(
'Successfully synced users batch from {start} to {end} for site {site}'.format(
start=offset, end=offset + users_query_batch_size, site=site_domain
)
)
offset += users_query_batch_size
self.stdout.write(
u'{count} contacts found and sycned for site {site}'.format(
'{count} contacts found and sycned for site {site}'.format(
count=successfully_synced_contacts, site=site_domain
)
)
@@ -215,15 +215,15 @@ class Command(BaseCommand):
initial_sync_days = options['initial_sync_days']
batch_size = options['batch_size']
try:
self.stdout.write(u'Command execution started with options = {}.'.format(options))
self.stdout.write(f'Command execution started with options = {options}.')
hubspot_sites = self._get_hubspot_enabled_sites()
self.stdout.write(u'{count} hubspot enabled sites found.'.format(count=len(hubspot_sites)))
self.stdout.write('{count} hubspot enabled sites found.'.format(count=len(hubspot_sites)))
users_queryset = self._get_users_queryset(initial_sync_days)
users_count = users_queryset.count()
self.stdout.write(u'Users count={count}'.format(count=users_count))
self.stdout.write(f'Users count={users_count}')
for site_conf in hubspot_sites:
self._sync_site(site_conf, users_queryset, users_count, batch_size)
except Exception as ex:
traceback.print_exc()
raise CommandError(u'Command failed with traceback %s' % str(ex)) # lint-amnesty, pylint: disable=raise-missing-from
raise CommandError('Command failed with traceback %s' % str(ex)) # lint-amnesty, pylint: disable=raise-missing-from

View File

@@ -8,14 +8,14 @@ import os
import tempfile
from contextlib import contextmanager
import mock
from unittest import mock
import pytest
from django.core.management import call_command
pytestmark = pytest.mark.django_db
CSV_DATA = u"""1,UniversityX
CSV_DATA = """1,UniversityX
2,CollegeX
3,StateUX
"""
@@ -27,7 +27,7 @@ def _create_test_csv(csv_data):
Context manager to create and populate a CSV file - and delete it after usage.
"""
__, file_name = tempfile.mkstemp(text=True)
with io.open(file_name, 'w') as file_pointer:
with open(file_name, 'w') as file_pointer:
file_pointer.write(csv_data)
try:
yield file_name
@@ -41,12 +41,12 @@ def test_successful_dry_run(mock_logger):
Run the command with default states for a successful initial population
"""
with _create_test_csv(CSV_DATA) as tmp_csv_file:
args = ['--dry_run', '--optout_csv_path={}'.format(tmp_csv_file)]
args = ['--dry_run', f'--optout_csv_path={tmp_csv_file}']
call_command('bulk_user_org_email_optout', *args)
assert mock_logger.call_count == 3
mock_logger.assert_any_call(u"Read %s opt-out rows from CSV file '%s'.", 3, tmp_csv_file)
mock_logger.assert_any_call("Read %s opt-out rows from CSV file '%s'.", 3, tmp_csv_file)
mock_logger.assert_any_call(
u'Attempting opt-out for rows (%s, %s) through (%s, %s)...', '1', 'UniversityX', '3', 'StateUX'
'Attempting opt-out for rows (%s, %s) through (%s, %s)...', '1', 'UniversityX', '3', 'StateUX'
)
mock_logger.assert_any_call(
'INSERT INTO user_api_userorgtag (`user_id`, `org`, `key`, `value`, `created`, `modified`) \

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Tests for the email opt-in list management command. """
@@ -9,12 +8,9 @@ import tempfile
from collections import defaultdict
import ddt
import six
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.management import call_command
from django.core.management.base import CommandError
from six import text_type
from six.moves import range
from openedx.core.djangoapps.user_api.management.commands import email_opt_in_list
from openedx.core.djangoapps.user_api.models import UserOrgTag
@@ -31,10 +27,10 @@ from xmodule.modulestore.tests.factories import CourseFactory
class EmailOptInListTest(ModuleStoreTestCase):
"""Tests for the email opt-in list management command. """
USER_USERNAME = "test_user"
USER_FIRST_NAME = u"Ṫëṡẗ"
USER_LAST_NAME = u"Űśéŕ"
USER_FIRST_NAME = "Ṫëṡẗ"
USER_LAST_NAME = "Űśéŕ"
TEST_ORG = u"téśt_őŕǵ"
TEST_ORG = "téśt_őŕǵ"
OUTPUT_FILE_NAME = "test_org_email_opt_in.csv"
OUTPUT_FIELD_NAMES = [
@@ -50,7 +46,7 @@ class EmailOptInListTest(ModuleStoreTestCase):
DEFAULT_DATETIME_STR = "2014-12-01 00:00:00"
def setUp(self):
super(EmailOptInListTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory.create(
username=self.USER_USERNAME,
@@ -217,14 +213,10 @@ class EmailOptInListTest(ModuleStoreTestCase):
course_ids = []
for row in output:
course_id = row['course_id'].strip()
# Python3 takes care of the decoding in the csv object
# but python 2 doesn't
if six.PY2:
course_id = course_id.decode('utf-8')
course_ids.append(course_id)
for course in self.courses:
assert text_type(course.id) in course_ids
assert str(course.id) in course_ids
# Choose numbers before and after the query interval boundary
@ddt.data(2, 3, 4, 5, 6, 7, 8, 9)
@@ -270,11 +262,7 @@ class EmailOptInListTest(ModuleStoreTestCase):
@ddt.data(0, 1)
def test_not_enough_args(self, num_args):
args = ["dummy"] * num_args
if six.PY2:
expected_msg_regex = (
"^Error: too few arguments$"
)
elif num_args == 1:
if num_args == 1:
expected_msg_regex = (
"^Error: the following arguments are required: ORG_ALIASES$"
)
@@ -395,7 +383,7 @@ class EmailOptInListTest(ModuleStoreTestCase):
output_path = os.path.join(temp_dir_path, self.OUTPUT_FILE_NAME)
org_list = [org] + other_names
if only_courses is not None:
only_courses = ",".join(text_type(course_id) for course_id in only_courses)
only_courses = ",".join(str(course_id) for course_id in only_courses)
command = email_opt_in_list.Command()
@@ -414,8 +402,8 @@ class EmailOptInListTest(ModuleStoreTestCase):
with open(output_path) as output_file:
reader = csv.DictReader(output_file, fieldnames=self.OUTPUT_FIELD_NAMES)
rows = [row for row in reader] # lint-amnesty, pylint: disable=unnecessary-comprehension
except IOError:
self.fail(u"Could not find or open output file at '{path}'".format(path=output_path))
except OSError:
self.fail(f"Could not find or open output file at '{output_path}'")
# Return the output as a list of dictionaries
return rows
@@ -448,8 +436,8 @@ class EmailOptInListTest(ModuleStoreTestCase):
for user, course_id, opt_in_pref in args:
assert {'user_id': str(user.id), 'username': user.username, 'email': user.email,
'full_name': (user.profile.name if hasattr(user, 'profile') else ''),
'course_id': text_type(course_id),
'is_opted_in_for_email': text_type(opt_in_pref),
'course_id': str(course_id),
'is_opted_in_for_email': str(opt_in_pref),
'preference_set_datetime':
(self._latest_pref_set_datetime(self.user) if kwargs.get('expect_pref_datetime', True) else
self.DEFAULT_DATETIME_STR)} in output[1:]

View File

@@ -87,7 +87,7 @@ def test_out_of_order_start_state(settings):
del settings.RETIREMENT_STATES[0]
settings.RETIREMENT_STATES.insert(4, 'PENDING')
with pytest.raises(CommandError, match=u'{} must be the first state'.format(START_STATE)):
with pytest.raises(CommandError, match=f'{START_STATE} must be the first state'):
call_command('populate_retirement_states')

View File

@@ -5,13 +5,12 @@ Test the sync_hubspot_contacts management command
import json
from datetime import timedelta
from io import StringIO
from unittest.mock import patch
from django.core.management import call_command
from django.test import TestCase
from django.utils import timezone
from django.utils.six import StringIO
from mock import patch
from six.moves import range
from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory
from openedx.core.djangoapps.user_api.management.commands.sync_hubspot_contacts import Command as sync_command
@@ -28,7 +27,7 @@ class TestHubspotSyncCommand(TestCase):
@classmethod
def setUpClass(cls):
super(TestHubspotSyncCommand, cls).setUpClass()
super().setUpClass()
cls.site_config = SiteConfigurationFactory()
cls.hubspot_site_config = SiteConfigurationFactory.create(
site_values={'HUBSPOT_API_KEY': 'test_key'}
@@ -42,11 +41,11 @@ class TestHubspotSyncCommand(TestCase):
# Create some test users
for i in range(1, 20):
profile_meta = {
"first_name": "First Name{0}".format(i),
"last_name": "Last Name{0}".format(i),
"company": "Company{0}".format(i),
"title": "Title{0}".format(i),
"state": "State{0}".format(i),
"first_name": f"First Name{i}",
"last_name": f"Last Name{i}",
"company": f"Company{i}",
"title": f"Title{i}",
"state": f"State{i}",
"country": "US",
}
loe = UserProfile.LEVEL_OF_EDUCATION_CHOICES[0][0]

View File

@@ -1,17 +1,16 @@
# -*- coding: utf-8 -*-
"""
Unit tests for preference APIs.
"""
import datetime
from unittest.mock import patch
import pytest
import ddt
from dateutil.parser import parse as parse_datetime
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.test.utils import override_settings
from django.urls import reverse
from mock import patch
from pytz import common_timezones, utc
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms
@@ -50,7 +49,7 @@ class TestPreferenceAPI(CacheIsolationTestCase):
password = "test"
def setUp(self):
super(TestPreferenceAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory.create(password=self.password)
self.different_user = UserFactory.create(password=self.password)
self.staff_user = UserFactory.create(is_staff=True, password=self.password)
@@ -107,8 +106,8 @@ class TestPreferenceAPI(CacheIsolationTestCase):
"""
Verifies the basic behavior of set_user_preference.
"""
test_key = u'ⓟⓡⓔⓕⓔⓡⓔⓝⓒⓔ_ⓚⓔⓨ'
test_value = u'ǝnןɐʌ_ǝɔuǝɹǝɟǝɹd'
test_key = 'ⓟⓡⓔⓕⓔⓡⓔⓝⓒⓔ_ⓚⓔⓨ'
test_value = 'ǝnןɐʌ_ǝɔuǝɹǝɟǝɹd'
set_user_preference(self.user, test_key, test_value)
assert get_user_preference(self.user, test_key) == test_value
set_user_preference(self.user, test_key, "new_value", username=self.user.username)
@@ -151,11 +150,11 @@ class TestPreferenceAPI(CacheIsolationTestCase):
user_preference_save.side_effect = [Exception, None]
with pytest.raises(PreferenceUpdateError) as context_manager:
set_user_preference(self.user, u"new_key_ȻħȺɍłɇs", u"new_value_ȻħȺɍłɇs")
set_user_preference(self.user, "new_key_ȻħȺɍłɇs", "new_value_ȻħȺɍłɇs")
assert context_manager.value.developer_message ==\
u"Save failed for user preference 'new_key_ȻħȺɍłɇs' with value 'new_value_ȻħȺɍłɇs': "
"Save failed for user preference 'new_key_ȻħȺɍłɇs' with value 'new_value_ȻħȺɍłɇs': "
assert context_manager.value.user_message ==\
u"Save failed for user preference 'new_key_ȻħȺɍłɇs' with value 'new_value_ȻħȺɍłɇs'."
"Save failed for user preference 'new_key_ȻħȺɍłɇs' with value 'new_value_ȻħȺɍłɇs'."
def test_update_user_preferences(self):
"""
@@ -231,15 +230,15 @@ class TestPreferenceAPI(CacheIsolationTestCase):
with pytest.raises(PreferenceUpdateError) as context_manager:
update_user_preferences(self.user, {self.test_preference_key: "new_value"})
assert context_manager.value.developer_message ==\
u"Save failed for user preference 'test_key' with value 'new_value': "
"Save failed for user preference 'test_key' with value 'new_value': "
assert context_manager.value.user_message ==\
u"Save failed for user preference 'test_key' with value 'new_value'."
"Save failed for user preference 'test_key' with value 'new_value'."
user_preference_delete.side_effect = [Exception, None]
with pytest.raises(PreferenceUpdateError) as context_manager:
update_user_preferences(self.user, {self.test_preference_key: None})
assert context_manager.value.developer_message == u"Delete failed for user preference 'test_key': "
assert context_manager.value.user_message == u"Delete failed for user preference 'test_key'."
assert context_manager.value.developer_message == "Delete failed for user preference 'test_key': "
assert context_manager.value.user_message == "Delete failed for user preference 'test_key'."
def test_delete_user_preference(self):
"""
@@ -270,8 +269,8 @@ class TestPreferenceAPI(CacheIsolationTestCase):
user_preference_delete.side_effect = [Exception, None]
with pytest.raises(PreferenceUpdateError) as context_manager:
delete_user_preference(self.user, self.test_preference_key)
assert context_manager.value.developer_message == u"Delete failed for user preference 'test_key': "
assert context_manager.value.user_message == u"Delete failed for user preference 'test_key'."
assert context_manager.value.developer_message == "Delete failed for user preference 'test_key': "
assert context_manager.value.user_message == "Delete failed for user preference 'test_key'."
@ddt.ddt
@@ -279,9 +278,9 @@ class UpdateEmailOptInTests(ModuleStoreTestCase):
"""
Test cases to cover API-driven email list opt-in update workflows
"""
USERNAME = u'claire-underwood'
PASSWORD = u'ṕáśśẃőŕd'
EMAIL = u'claire+underwood@example.com'
USERNAME = 'claire-underwood'
PASSWORD = 'ṕáśśẃőŕd'
EMAIL = 'claire+underwood@example.com'
def _create_account(self, username, password, email):
# pylint: disable=missing-docstring
@@ -297,19 +296,19 @@ class UpdateEmailOptInTests(ModuleStoreTestCase):
@ddt.data(
# Check that a 27 year old can opt-in
(27, True, u"True"),
(27, True, "True"),
# Check that a 32-year old can opt-out
(32, False, u"False"),
(32, False, "False"),
# Check that someone 14 years old can opt-in
(14, True, u"True"),
(14, True, "True"),
# Check that someone 13 years old cannot opt-in (must have turned 13 before this year)
(13, True, u"False"),
(13, True, "False"),
# Check that someone 12 years old cannot opt-in
(12, True, u"False")
(12, True, "False")
)
@ddt.unpack
@override_settings(EMAIL_OPTIN_MINIMUM_AGE=13)
@@ -339,7 +338,7 @@ class UpdateEmailOptInTests(ModuleStoreTestCase):
update_email_opt_in(user, course.id.org, True)
result_obj = UserOrgTag.objects.get(user=user, org=course.id.org, key='email-optin')
assert result_obj.value == u'True'
assert result_obj.value == 'True'
def test_update_email_optin_anonymous_user(self):
"""Verify that the API raises an exception for a user with no profile."""
@@ -350,16 +349,16 @@ class UpdateEmailOptInTests(ModuleStoreTestCase):
@ddt.data(
# Check that a 27 year old can opt-in, then out.
(27, True, False, u"False"),
(27, True, False, "False"),
# Check that a 32-year old can opt-out, then in.
(32, False, True, u"True"),
(32, False, True, "True"),
# Check that someone 13 years old can opt-in, then out.
(13, True, False, u"False"),
(13, True, False, "False"),
# Check that someone 12 years old cannot opt-in, then explicitly out.
(12, True, False, u"False")
(12, True, False, "False")
)
@ddt.unpack
@override_settings(EMAIL_OPTIN_MINIMUM_AGE=13)
@@ -425,11 +424,11 @@ def get_expected_validation_developer_message(preference_key, preference_value):
"""
Returns the expected dict of validation messages for the specified key.
"""
return u"Value '{preference_value}' not valid for preference '{preference_key}': {error}".format(
return "Value '{preference_value}' not valid for preference '{preference_key}': {error}".format(
preference_key=preference_key,
preference_value=preference_value,
error={
"key": [u"Ensure this field has no more than 255 characters."]
"key": ["Ensure this field has no more than 255 characters."]
}
)
@@ -438,11 +437,11 @@ def get_expected_key_error_user_message(preference_key, preference_value): # li
"""
Returns the expected user message for an invalid key.
"""
return u"Invalid user preference key '{preference_key}'.".format(preference_key=preference_key)
return f"Invalid user preference key '{preference_key}'."
def get_empty_preference_message(preference_key):
"""
Returns the validation message shown for an empty preference.
"""
return u"Preference '{preference_key}' cannot be set to an empty value.".format(preference_key=preference_key)
return f"Preference '{preference_key}' cannot be set to an empty value."

View File

@@ -1,16 +1,14 @@
# -*- coding: utf-8 -*-
"""
Unit tests for preference APIs.
"""
import json
from unittest.mock import patch
import ddt
import six
from django.test.testcases import TransactionTestCase
from django.urls import reverse
from mock import patch
from rest_framework.test import APIClient
from openedx.core.djangolib.testing.utils import skip_unless_lms
@@ -20,7 +18,7 @@ from ...accounts.tests.test_views import UserAPITestCase
from ..api import set_user_preference
from .test_api import get_expected_key_error_user_message, get_expected_validation_developer_message
TOO_LONG_PREFERENCE_KEY = u"x" * 256
TOO_LONG_PREFERENCE_KEY = "x" * 256
@ddt.ddt
@@ -30,7 +28,7 @@ class TestPreferencesAPI(UserAPITestCase):
Unit tests /api/user/v1/accounts/{username}/
"""
def setUp(self):
super(TestPreferencesAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.url_endpoint_name = "preferences_api"
self.url = reverse(self.url_endpoint_name, kwargs={'username': self.user.username})
@@ -151,11 +149,8 @@ class TestPreferencesAPI(UserAPITestCase):
expected_status=204
)
response = self.send_get(self.client)
if six.PY2:
pref_dict = {u"dict_pref": u"{u'int_key': 10}", u"string_pref": u"value"}
else:
# lint-amnesty, pylint: disable=bad-option-value, unicode-format-string
pref_dict = {"dict_pref": "{'int_key': 10}", "string_pref": "value"}
# lint-amnesty, pylint: disable=bad-option-value, unicode-format-string
pref_dict = {"dict_pref": "{'int_key': 10}", "string_pref": "value"}
assert pref_dict == response.data
@ddt.data(
@@ -228,22 +223,22 @@ class TestPreferencesAPI(UserAPITestCase):
"string_pref": "updated_value",
TOO_LONG_PREFERENCE_KEY: "new_value",
"new_pref": "new_value",
u"empty_pref_ȻħȺɍłɇs": "",
"empty_pref_ȻħȺɍłɇs": "",
"time_zone": "Asia/Africa",
},
expected_status=400
)
assert response.data.get('field_errors', None)
field_errors = response.data["field_errors"]
assert field_errors == {TOO_LONG_PREFERENCE_KEY: {'developer_message': get_expected_validation_developer_message(TOO_LONG_PREFERENCE_KEY, 'new_value'), 'user_message': get_expected_key_error_user_message(TOO_LONG_PREFERENCE_KEY, 'new_value')}, u'empty_pref_ȻħȺɍłɇs': {'developer_message': u"Preference 'empty_pref_ȻħȺɍłɇs' cannot be set to an empty value.", 'user_message': u"Preference 'empty_pref_ȻħȺɍłɇs' cannot be set to an empty value."}, 'time_zone': {'developer_message': u"Value 'Asia/Africa' not valid for preference 'time_zone': Not in timezone set.", 'user_message': u"Value 'Asia/Africa' is not a valid time zone selection."}} # pylint: disable=line-too-long
assert field_errors == {TOO_LONG_PREFERENCE_KEY: {'developer_message': get_expected_validation_developer_message(TOO_LONG_PREFERENCE_KEY, 'new_value'), 'user_message': get_expected_key_error_user_message(TOO_LONG_PREFERENCE_KEY, 'new_value')}, 'empty_pref_ȻħȺɍłɇs': {'developer_message': "Preference 'empty_pref_ȻħȺɍłɇs' cannot be set to an empty value.", 'user_message': "Preference 'empty_pref_ȻħȺɍłɇs' cannot be set to an empty value."}, 'time_zone': {'developer_message': "Value 'Asia/Africa' not valid for preference 'time_zone': Not in timezone set.", 'user_message': "Value 'Asia/Africa' is not a valid time zone selection."}} # pylint: disable=line-too-long
# Verify that GET returns the original preferences
response = self.send_get(self.client)
expected_preferences = {
"dict_pref": u"{'int_key': 10}",
"string_pref": u"value",
"extra_pref": u"extra_value",
"time_zone": u"Pacific/Midway",
"dict_pref": "{'int_key': 10}",
"string_pref": "value",
"extra_pref": "extra_value",
"time_zone": "Pacific/Midway",
}
assert expected_preferences == response.data
@@ -256,14 +251,14 @@ class TestPreferencesAPI(UserAPITestCase):
# Verify a non-dict request
response = self.send_patch(self.client, "non_dict_request", expected_status=400)
assert response.data ==\
{'developer_message': u'No data provided for user preference update',
'user_message': u'No data provided for user preference update'}
{'developer_message': 'No data provided for user preference update',
'user_message': 'No data provided for user preference update'}
# Verify an empty dict request
response = self.send_patch(self.client, {}, expected_status=400)
assert response.data ==\
{'developer_message': u'No data provided for user preference update',
'user_message': u'No data provided for user preference update'}
{'developer_message': 'No data provided for user preference update',
'user_message': 'No data provided for user preference update'}
@ddt.data(
("different_client", "different_user"),
@@ -300,7 +295,7 @@ class TestPreferencesAPITransactions(TransactionTestCase):
test_password = "test"
def setUp(self):
super(TestPreferencesAPITransactions, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.client = APIClient()
self.user = UserFactory.create(password=TEST_PASSWORD)
self.url = reverse("preferences_api", kwargs={'username': self.user.username})
@@ -345,7 +340,7 @@ class TestPreferencesDetailAPI(UserAPITestCase):
Unit tests /api/user/v1/accounts/{username}/{preference_key}
"""
def setUp(self):
super(TestPreferencesDetailAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.test_pref_key = "test_key"
self.test_pref_value = "test_value"
set_user_preference(self.user, self.test_pref_key, self.test_pref_value)
@@ -428,7 +423,7 @@ class TestPreferencesDetailAPI(UserAPITestCase):
set_user_preference(self.user, "dict_pref", {"int_key": 10})
self._set_url("dict_pref")
response = self.send_get(client)
assert u"{'int_key': 10}" == response.data
assert "{'int_key': 10}" == response.data
def test_create_preference(self):
"""
@@ -470,8 +465,8 @@ class TestPreferencesDetailAPI(UserAPITestCase):
self.client.login(username=self.user.username, password=TEST_PASSWORD)
response = self.send_put(self.client, preference_value, expected_status=400)
assert response.data ==\
{'developer_message': u"Preference 'new_key' cannot be set to an empty value.",
'user_message': u"Preference 'new_key' cannot be set to an empty value."}
{'developer_message': "Preference 'new_key' cannot be set to an empty value.",
'user_message': "Preference 'new_key' cannot be set to an empty value."}
self.send_get(self.client, expected_status=404)
def test_create_preference_too_long_key(self):
@@ -504,9 +499,9 @@ class TestPreferencesDetailAPI(UserAPITestCase):
self.send_put(client, new_value, expected_status=403)
@ddt.data(
(u"new value",),
("new value",),
(10,),
({u"int_key": 10},)
({"int_key": 10},)
)
@ddt.unpack
def test_update_preference(self, preference_value):
@@ -516,7 +511,7 @@ class TestPreferencesDetailAPI(UserAPITestCase):
self.client.login(username=self.user.username, password=TEST_PASSWORD)
self.send_put(self.client, preference_value)
response = self.send_get(self.client)
assert six.text_type(preference_value) == response.data
assert str(preference_value) == response.data
@ddt.data(
("different_client", "different_user"),
@@ -543,8 +538,8 @@ class TestPreferencesDetailAPI(UserAPITestCase):
"""
self.client.login(username=self.user.username, password=TEST_PASSWORD)
response = self.send_put(self.client, preference_value, expected_status=400)
assert response.data == {'developer_message': u"Preference 'test_key' cannot be set to an empty value.",
'user_message': u"Preference 'test_key' cannot be set to an empty value."}
assert response.data == {'developer_message': "Preference 'test_key' cannot be set to an empty value.",
'user_message': "Preference 'test_key' cannot be set to an empty value."}
response = self.send_get(self.client)
assert self.test_pref_value == response.data

View File

@@ -132,7 +132,7 @@ class VerificationsDetailsViewTests(VerificationStatusViewTestsMixin, TestCase):
'status': self.photo_verification.status,
'expiration_datetime': '{}Z'.format(kwargs.get('expected_expires').isoformat()),
'message': '',
'updated_at': '{}Z'.format(self.CREATED_AT.isoformat()),
'updated_at': f'{self.CREATED_AT.isoformat()}Z',
'receipt_id': self.photo_verification.receipt_id,
}]
@@ -155,25 +155,25 @@ class VerificationsDetailsViewTests(VerificationStatusViewTestsMixin, TestCase):
{
'type': 'Software Secure',
'status': self.photo_verification.status,
'expiration_datetime': '{}Z'.format(expected_expires.isoformat()),
'expiration_datetime': f'{expected_expires.isoformat()}Z',
'message': self.photo_verification.error_msg,
'updated_at': '{}Z'.format(self.CREATED_AT.isoformat()),
'updated_at': f'{self.CREATED_AT.isoformat()}Z',
'receipt_id': self.photo_verification.receipt_id
},
{
'type': 'SSO',
'status': self.sso_verification.status,
'expiration_datetime': '{}Z'.format(expected_expires.isoformat()),
'expiration_datetime': f'{expected_expires.isoformat()}Z',
'message': '',
'updated_at': '{}Z'.format(self.CREATED_AT.isoformat()),
'updated_at': f'{self.CREATED_AT.isoformat()}Z',
'receipt_id': None,
},
{
'type': 'Manual',
'status': self.manual_verification.status,
'expiration_datetime': '{}Z'.format(expected_expires.isoformat()),
'expiration_datetime': f'{expected_expires.isoformat()}Z',
'message': self.manual_verification.reason,
'updated_at': '{}Z'.format(self.CREATED_AT.isoformat()),
'updated_at': f'{self.CREATED_AT.isoformat()}Z',
'receipt_id': None,
},
]
@@ -195,25 +195,25 @@ class VerificationsDetailsViewTests(VerificationStatusViewTestsMixin, TestCase):
{
'type': 'Software Secure',
'status': self.photo_verification.status,
'expiration_datetime': '{}Z'.format(expected_expires.isoformat()),
'expiration_datetime': f'{expected_expires.isoformat()}Z',
'message': self.photo_verification.error_msg,
'updated_at': '{}Z'.format(self.CREATED_AT.isoformat()),
'updated_at': f'{self.CREATED_AT.isoformat()}Z',
'receipt_id': self.photo_verification.receipt_id,
},
{
'type': 'Software Secure',
'status': second_ss_photo_verification.status,
'expiration_datetime': '{}Z'.format(expected_expires.isoformat()),
'expiration_datetime': f'{expected_expires.isoformat()}Z',
'message': second_ss_photo_verification.error_msg,
'updated_at': '{}Z'.format(self.CREATED_AT.isoformat()),
'updated_at': f'{self.CREATED_AT.isoformat()}Z',
'receipt_id': second_ss_photo_verification.receipt_id,
},
{
'type': 'SSO',
'status': self.sso_verification.status,
'expiration_datetime': '{}Z'.format(expected_expires.isoformat()),
'expiration_datetime': f'{expected_expires.isoformat()}Z',
'message': '',
'updated_at': '{}Z'.format(self.CREATED_AT.isoformat()),
'updated_at': f'{self.CREATED_AT.isoformat()}Z',
'receipt_id': None,
},
]