diff --git a/common/djangoapps/util/cache.py b/common/djangoapps/util/cache.py index 2dcb18bb51..ca2ee2050e 100644 --- a/common/djangoapps/util/cache.py +++ b/common/djangoapps/util/cache.py @@ -8,8 +8,8 @@ not migrating so as not to inconvenience users by logging them all out. from functools import wraps +from urllib.parse import urlencode -import six from django.core import cache # If we can't find a 'general' CACHE defined in settings.py, we simply fall back # to returning the default cache. This will happen with dev machines. @@ -67,8 +67,8 @@ def cache_if_anonymous(*get_parameters): if parameter_value is not None: # urlencode expects data to be of type str, and doesn't deal well with Unicode data # since it doesn't provide a way to specify an encoding. - cache_key = cache_key + '.' + six.moves.urllib.parse.urlencode({ - get_parameter: six.text_type(parameter_value).encode('utf-8') + cache_key = cache_key + '.' + urlencode({ + get_parameter: str(parameter_value).encode('utf-8') }) response = cache.get(cache_key) diff --git a/common/djangoapps/util/config_parse.py b/common/djangoapps/util/config_parse.py index dd39539c77..63c4b61690 100644 --- a/common/djangoapps/util/config_parse.py +++ b/common/djangoapps/util/config_parse.py @@ -5,8 +5,6 @@ Helper functions for configuration parsing import collections -import six - def convert_tokens(tokens): """ @@ -19,7 +17,7 @@ def convert_tokens(tokens): if tokens == 'None': return None - elif isinstance(tokens, six.string_types) or (not isinstance(tokens, collections.Iterable)): + elif isinstance(tokens, str) or (not isinstance(tokens, collections.Iterable)): return tokens elif isinstance(tokens, dict): return { diff --git a/common/djangoapps/util/course.py b/common/djangoapps/util/course.py index 51acfc7233..03793baff7 100644 --- a/common/djangoapps/util/course.py +++ b/common/djangoapps/util/course.py @@ -4,8 +4,8 @@ Utility methods related to course import logging +from urllib.parse import urlencode -import six from django.conf import settings from django.utils.timezone import now @@ -32,8 +32,8 @@ def get_encoded_course_sharing_utm_params(): Returns encoded Course Sharing UTM Parameters. """ return { - utm_source: six.moves.urllib.parse.urlencode(utm_params) - for utm_source, utm_params in six.iteritems(COURSE_SHARING_UTM_PARAMETERS) + utm_source: urlencode(utm_params) + for utm_source, utm_params in COURSE_SHARING_UTM_PARAMETERS.items() } @@ -54,9 +54,9 @@ def get_link_for_about_page(course): elif settings.FEATURES.get('ENABLE_MKTG_SITE') and getattr(course, 'marketing_url', None): course_about_url = course.marketing_url else: - course_about_url = u'{about_base_url}/courses/{course_key}/about'.format( + course_about_url = '{about_base_url}/courses/{course_key}/about'.format( about_base_url=configuration_helpers.get_value('LMS_ROOT_URL', settings.LMS_ROOT_URL), - course_key=six.text_type(course.id), + course_key=str(course.id), ) return course_about_url diff --git a/common/djangoapps/util/date_utils.py b/common/djangoapps/util/date_utils.py index 17250541da..be2b859bf7 100644 --- a/common/djangoapps/util/date_utils.py +++ b/common/djangoapps/util/date_utils.py @@ -26,14 +26,14 @@ def get_default_time_display(dtime): """ if dtime is None: - return u"" + return "" if dtime.tzinfo is not None: try: - timezone = u" " + dtime.tzinfo.tzname(dtime) # lint-amnesty, pylint: disable=redefined-outer-name + timezone = " " + dtime.tzinfo.tzname(dtime) # lint-amnesty, pylint: disable=redefined-outer-name except NotImplementedError: timezone = dtime.strftime('%z') else: - timezone = u" UTC" + timezone = " UTC" localized = strftime_localized(dtime, "DATE_TIME") return (localized + timezone).strip() diff --git a/common/djangoapps/util/db.py b/common/djangoapps/util/db.py index 594a4d16dd..bf1ab4cce8 100644 --- a/common/djangoapps/util/db.py +++ b/common/djangoapps/util/db.py @@ -55,7 +55,7 @@ class OuterAtomic(transaction.Atomic): def __init__(self, using, savepoint, read_committed=False, name=None): self.read_committed = read_committed self.name = name - super(OuterAtomic, self).__init__(using, savepoint) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(using, savepoint) def __enter__(self): @@ -88,7 +88,7 @@ class OuterAtomic(transaction.Atomic): cursor = connection.cursor() cursor.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED") - super(OuterAtomic, self).__enter__() # lint-amnesty, pylint: disable=super-with-arguments + super().__enter__() def outer_atomic(using=None, savepoint=True, read_committed=False, name=None): diff --git a/common/djangoapps/util/disable_rate_limit.py b/common/djangoapps/util/disable_rate_limit.py index c70b948f28..d649583f5f 100644 --- a/common/djangoapps/util/disable_rate_limit.py +++ b/common/djangoapps/util/disable_rate_limit.py @@ -73,7 +73,7 @@ def can_disable_rate_limit(clz): # No-op if the class isn't a Django Rest Framework view. if not issubclass(clz, APIView): msg = ( - u"{clz} is not a Django Rest Framework APIView subclass." + "{clz} is not a Django Rest Framework APIView subclass." ).format(clz=clz) LOGGER.warning(msg) return clz diff --git a/common/djangoapps/util/file.py b/common/djangoapps/util/file.py index 2533e5de74..aac1864329 100644 --- a/common/djangoapps/util/file.py +++ b/common/djangoapps/util/file.py @@ -6,7 +6,6 @@ Utility methods related to file handling. import os from datetime import datetime -import six from django.core.exceptions import PermissionDenied from django.core.files.storage import DefaultStorage, get_valid_filename from django.utils.translation import ugettext as _ @@ -99,7 +98,7 @@ def course_filename_prefix_generator(course_id, separator='_'): str: A unicode string which can safely be inserted into a filename. """ - return get_valid_filename(six.text_type(separator).join([course_id.org, course_id.course, course_id.run])) + return get_valid_filename(str(separator).join([course_id.org, course_id.course, course_id.run])) def course_and_time_based_filename_generator(course_id, base_name): @@ -118,14 +117,14 @@ def course_and_time_based_filename_generator(course_id, base_name): and the current time. Note that there will be no extension. """ - return u"{course_prefix}_{base_name}_{timestamp_str}".format( + return "{course_prefix}_{base_name}_{timestamp_str}".format( course_prefix=course_filename_prefix_generator(course_id), base_name=get_valid_filename(base_name), timestamp_str=datetime.now(UTC).strftime("%Y-%m-%d-%H%M%S") ) -class UniversalNewlineIterator(object): +class UniversalNewlineIterator: """ This iterable class can be used as a wrapper around a file-like object which does not inherently support being read in @@ -143,8 +142,6 @@ class UniversalNewlineIterator(object): """ Replace CR and CRLF with LF within `string`. """ - if six.PY2: - return string.replace('\r\n', '\n').replace('\r', '\n') return string.replace('\r\n', '\n').replace('\r', '\n').encode('utf-8') def generate_lines(self): @@ -165,7 +162,7 @@ class UniversalNewlineIterator(object): line = char yield self.sanitize(last_line) else: - line += six.text_type(char) if isinstance(char, int) else char + line += str(char) if isinstance(char, int) else char buf = self.original_file.read(self.buffer_size) if not buf and line: yield self.sanitize(line) diff --git a/common/djangoapps/util/json_request.py b/common/djangoapps/util/json_request.py index 36edd2ac32..3c9646b130 100644 --- a/common/djangoapps/util/json_request.py +++ b/common/djangoapps/util/json_request.py @@ -31,7 +31,7 @@ class EDXJSONEncoder(DjangoJSONEncoder): return int(o) return float(o) else: - return super(EDXJSONEncoder, self).default(o) # lint-amnesty, pylint: disable=super-with-arguments + return super().default(o) def expect_json(view_function): @@ -73,7 +73,7 @@ class JsonResponse(HttpResponse): kwargs.setdefault("content_type", "application/json") if status: kwargs["status"] = status - super(JsonResponse, self).__init__(content, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(content, *args, **kwargs) class JsonResponseBadRequest(HttpResponseBadRequest): @@ -93,4 +93,4 @@ class JsonResponseBadRequest(HttpResponseBadRequest): content = json.dumps(obj, cls=encoder, indent=2, ensure_ascii=False) kwargs.setdefault("content_type", "application/json") kwargs["status"] = status - super(JsonResponseBadRequest, self).__init__(content, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(content, *args, **kwargs) diff --git a/common/djangoapps/util/memcache.py b/common/djangoapps/util/memcache.py index 9cf7b21bd9..2f439245ac 100644 --- a/common/djangoapps/util/memcache.py +++ b/common/djangoapps/util/memcache.py @@ -5,7 +5,8 @@ so that we can cache any keys, not just ones that memcache would ordinarily acce import hashlib -import six.moves.urllib.parse +from urllib.parse import quote_plus + from django.utils.encoding import smart_str @@ -23,7 +24,7 @@ def cleaned_string(val): Converts `val` to unicode and URL-encodes special characters (including quotes and spaces) """ - return six.moves.urllib.parse.quote_plus(smart_str(val)) + return quote_plus(smart_str(val)) def safe_key(key, key_prefix, version): diff --git a/common/djangoapps/util/migrations/0001_initial.py b/common/djangoapps/util/migrations/0001_initial.py index e894753038..749a40d494 100644 --- a/common/djangoapps/util/migrations/0001_initial.py +++ b/common/djangoapps/util/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import django.db.models.deletion from django.conf import settings from django.db import migrations, models diff --git a/common/djangoapps/util/migrations/0002_data__default_rate_limit_config.py b/common/djangoapps/util/migrations/0002_data__default_rate_limit_config.py index 6558104f13..108724debb 100644 --- a/common/djangoapps/util/migrations/0002_data__default_rate_limit_config.py +++ b/common/djangoapps/util/migrations/0002_data__default_rate_limit_config.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models # Converted from the original South migration 0002_default_rate_limit_config.py diff --git a/common/djangoapps/util/milestones_helpers.py b/common/djangoapps/util/milestones_helpers.py index 278de5cee3..60a7c14296 100644 --- a/common/djangoapps/util/milestones_helpers.py +++ b/common/djangoapps/util/milestones_helpers.py @@ -1,9 +1,6 @@ """ Utility library for working with the edx-milestones app """ - - -import six from django.conf import settings from django.utils.translation import ugettext as _ from edx_toggles.toggles import SettingDictToggle @@ -63,12 +60,12 @@ def add_prerequisite_course(course_key, prerequisite_course_key): if not is_prerequisite_courses_enabled(): return None milestone_name = _('Course {course_id} requires {prerequisite_course_id}').format( - course_id=six.text_type(course_key), - prerequisite_course_id=six.text_type(prerequisite_course_key) + course_id=str(course_key), + prerequisite_course_id=str(prerequisite_course_key) ) milestone = milestones_api.add_milestone({ 'name': milestone_name, - 'namespace': six.text_type(prerequisite_course_key), + 'namespace': str(prerequisite_course_key), 'description': _('System defined milestone'), }) # add requirement course milestone @@ -222,7 +219,7 @@ def get_required_content(course_key, user): """ required_content = [] if ENABLE_MILESTONES_APP.is_enabled(): - course_run_id = six.text_type(course_key) + course_run_id = str(course_key) if user.is_authenticated: # Get all of the outstanding milestones for this course, for this user @@ -287,7 +284,7 @@ def generate_milestone_namespace(namespace, course_key=None): """ if namespace in list(NAMESPACE_CHOICES.values()): if namespace == 'entrance_exams': - return '{}.{}'.format(six.text_type(course_key), NAMESPACE_CHOICES['ENTRANCE_EXAM']) + return '{}.{}'.format(str(course_key), NAMESPACE_CHOICES['ENTRANCE_EXAM']) def serialize_user(user): @@ -382,7 +379,7 @@ def get_course_content_milestones(course_id, content_id=None, relationship='requ if content_id is None: return request_cache_dict[user_id][relationship] - return [m for m in request_cache_dict[user_id][relationship] if m['content_id'] == six.text_type(content_id)] + return [m for m in request_cache_dict[user_id][relationship] if m['content_id'] == str(content_id)] def remove_course_content_user_milestones(course_key, content_key, user, relationship): diff --git a/common/djangoapps/util/model_utils.py b/common/djangoapps/util/model_utils.py index 9bcda3f3ef..8cdbb7fa6e 100644 --- a/common/djangoapps/util/model_utils.py +++ b/common/djangoapps/util/model_utils.py @@ -4,14 +4,13 @@ Utilities for django models. from typing import Dict, Any, Tuple -import six from django.conf import settings from django.dispatch import Signal from django_countries.fields import Country from eventtracking import tracker # The setting name used for events when "settings" (account settings, preferences, profile information) change. -USER_SETTINGS_CHANGED_EVENT_NAME = u'edx.user.settings.changed' +USER_SETTINGS_CHANGED_EVENT_NAME = 'edx.user.settings.changed' # Used to signal a field value change USER_FIELD_CHANGED = Signal(providing_args=["user", "table", "setting", "old_value", "new_value"]) USER_FIELDS_CHANGED = Signal(providing_args=["user", "table", "changed_values"]) @@ -170,7 +169,7 @@ def _get_truncated_setting_value(value, max_length=None): truncated_value (object): the possibly truncated version of the value. was_truncated (bool): returns true if the serialized value was truncated. """ - if isinstance(value, six.string_types) and max_length is not None and len(value) > max_length: + if isinstance(value, str) and max_length is not None and len(value) > max_length: return value[0:max_length], True else: return value, False diff --git a/common/djangoapps/util/models.py b/common/djangoapps/util/models.py index bbf07819f9..9f55d41b8e 100644 --- a/common/djangoapps/util/models.py +++ b/common/djangoapps/util/models.py @@ -5,7 +5,6 @@ import gzip import logging from io import BytesIO -import six from config_models.models import ConfigurationModel from django.db import models from django.utils.text import compress_string @@ -58,7 +57,7 @@ class CompressedTextField(CreatorMixin, models.TextField): Compress the text data. """ if value is not None: - if isinstance(value, six.text_type): + if isinstance(value, str): value = value.encode('utf8') value = compress_string(value) value = value.encode('base64').decode('utf8') @@ -68,7 +67,7 @@ class CompressedTextField(CreatorMixin, models.TextField): """ Decompresses the value from the database. """ - if isinstance(value, six.text_type): + if isinstance(value, str): value = decompress_string(value) return value diff --git a/common/djangoapps/util/password_policy_validators.py b/common/djangoapps/util/password_policy_validators.py index 66e0f34aa3..9bb2372915 100644 --- a/common/djangoapps/util/password_policy_validators.py +++ b/common/djangoapps/util/password_policy_validators.py @@ -13,7 +13,6 @@ from django.contrib.auth.password_validation import validate_password as django_ from django.core.exceptions import ValidationError from django.utils.translation import ugettext as _ from django.utils.translation import ungettext -from six import text_type log = logging.getLogger(__name__) @@ -71,7 +70,7 @@ def password_validators_instruction_texts(): complexity_instructions=' & '.join(complexity_instructions) ) else: - return _('Your password must contain {length_instruction}.'.format(length_instruction=length_instruction)) # lint-amnesty, pylint: disable=translation-of-non-string + return _(f'Your password must contain {length_instruction}.') # lint-amnesty, pylint: disable=translation-of-non-string def password_validators_restrictions(): @@ -93,10 +92,10 @@ def normalize_password(password): Normalize all passwords to 'NFKC' across the platform to prevent mismatched hash strings when comparing entered passwords on login. See LEARNER-4283 for more context. """ - if not isinstance(password, text_type): + if not isinstance(password, str): try: # some checks rely on unicode semantics (e.g. length) - password = text_type(password, encoding='utf8') + password = str(password, encoding='utf8') except UnicodeDecodeError: # no reason to get into weeds raise ValidationError([_('Invalid password.')]) # lint-amnesty, pylint: disable=raise-missing-from @@ -159,7 +158,7 @@ class MinimumLengthValidator(DjangoMinimumLengthValidator): # lint-amnesty, pyl return 'min_length', self.min_length -class MaximumLengthValidator(object): +class MaximumLengthValidator: """ Validate whether the password is shorter than a maximum length. @@ -195,7 +194,7 @@ class MaximumLengthValidator(object): return 'max_length', self.max_length -class AlphabeticValidator(object): +class AlphabeticValidator: """ Validate whether the password contains at least min_alphabetic letters. @@ -243,7 +242,7 @@ class AlphabeticValidator(object): return 'min_alphabetic', self.min_alphabetic -class NumericValidator(object): +class NumericValidator: """ Validate whether the password contains at least min_numeric numbers. @@ -291,7 +290,7 @@ class NumericValidator(object): return 'min_numeric', self.min_numeric -class UppercaseValidator(object): +class UppercaseValidator: """ Validate whether the password contains at least min_upper uppercase letters. @@ -339,7 +338,7 @@ class UppercaseValidator(object): return 'min_upper', self.min_upper -class LowercaseValidator(object): +class LowercaseValidator: """ Validate whether the password contains at least min_lower lowercase letters. @@ -387,7 +386,7 @@ class LowercaseValidator(object): return 'min_lower', self.min_lower -class PunctuationValidator(object): +class PunctuationValidator: """ Validate whether the password contains at least min_punctuation punctuation marks as defined by unicode categories. @@ -436,7 +435,7 @@ class PunctuationValidator(object): return 'min_punctuation', self.min_punctuation -class SymbolValidator(object): +class SymbolValidator: """ Validate whether the password contains at least min_symbol symbols as defined by unicode categories. diff --git a/common/djangoapps/util/testing.py b/common/djangoapps/util/testing.py index 9a3b0f52b0..b47654dd2a 100644 --- a/common/djangoapps/util/testing.py +++ b/common/djangoapps/util/testing.py @@ -2,23 +2,19 @@ Utility Mixins for unit tests """ - import json import sys +from importlib import reload +from unittest.mock import patch -import six from django.conf import settings from django.test import TestCase from django.urls import clear_url_caches, resolve -from mock import patch from common.djangoapps.util.db import OuterAtomic -if six.PY3: - from importlib import reload - -class UrlResetMixin(object): +class UrlResetMixin: """Mixin to reset urls.py before and after a test Django memoizes the function that reads the urls module (whatever module @@ -69,18 +65,18 @@ class UrlResetMixin(object): URLCONF_MODULES = ['myapp.url', 'another_app.urls'] """ - super(UrlResetMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.reset_urls() self.addCleanup(self.reset_urls) -class EventTestMixin(object): +class EventTestMixin: """ Generic mixin for verifying that events were emitted during a test. """ def setUp(self, tracker): - super(EventTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() patcher = patch(tracker) self.mock_tracker = patcher.start() self.addCleanup(patcher.stop) @@ -124,7 +120,7 @@ class EventTestMixin(object): return self.mock_tracker.emit.call_args[0] -class PatchMediaTypeMixin(object): +class PatchMediaTypeMixin: """ Generic mixin for verifying unsupported media type in PATCH """ diff --git a/common/djangoapps/util/tests/mixins/discovery.py b/common/djangoapps/util/tests/mixins/discovery.py index 4b77834871..b47a2c9fe1 100644 --- a/common/djangoapps/util/tests/mixins/discovery.py +++ b/common/djangoapps/util/tests/mixins/discovery.py @@ -10,7 +10,7 @@ from django.conf import settings from django.core.cache import cache -class CourseCatalogServiceMockMixin(object): +class CourseCatalogServiceMockMixin: """ Mocks for the Open edX service 'Course Catalog Service' responses. """ @@ -19,7 +19,7 @@ class CourseCatalogServiceMockMixin(object): ) def setUp(self): - super(CourseCatalogServiceMockMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() cache.clear() def mock_course_discovery_api_for_catalog_contains(self, catalog_id=1, course_run_ids=None): diff --git a/common/djangoapps/util/tests/test_course.py b/common/djangoapps/util/tests/test_course.py index 6ef70a16bd..d1873fd73f 100644 --- a/common/djangoapps/util/tests/test_course.py +++ b/common/djangoapps/util/tests/test_course.py @@ -1,10 +1,9 @@ """ Tests for course utils. """ - +from unittest import mock import ddt -import mock from django.conf import settings from openedx.core.djangoapps.content.course_overviews.models import CourseOverview @@ -20,7 +19,7 @@ class TestCourseSharingLinks(ModuleStoreTestCase): Tests for course sharing links. """ def setUp(self): - super(TestCourseSharingLinks, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # create test mongo course self.course = CourseFactory.create( @@ -70,7 +69,7 @@ class TestCourseSharingLinks(ModuleStoreTestCase): (True, True, 'test_social_sharing_url'), (False, True, 'test_marketing_url'), (True, False, 'test_social_sharing_url'), - (False, False, '{}/courses/course-v1:test_org+test_number+test_run/about'.format(settings.LMS_ROOT_URL)), + (False, False, f'{settings.LMS_ROOT_URL}/courses/course-v1:test_org+test_number+test_run/about'), ) @ddt.unpack def test_sharing_link_with_settings(self, enable_social_sharing, enable_mktg_site, expected_course_sharing_link): @@ -88,7 +87,7 @@ class TestCourseSharingLinks(ModuleStoreTestCase): (['marketing_url'], 'test_social_sharing_url'), ( ['social_sharing_url', 'marketing_url'], - '{}/courses/course-v1:test_org+test_number+test_run/about'.format(settings.LMS_ROOT_URL) + f'{settings.LMS_ROOT_URL}/courses/course-v1:test_org+test_number+test_run/about' ), ) @ddt.unpack @@ -112,7 +111,7 @@ class TestCourseSharingLinks(ModuleStoreTestCase): (True, 'test_social_sharing_url'), ( False, - '{}/courses/course-v1:test_org+test_number+test_run/about'.format(settings.LMS_ROOT_URL) + f'{settings.LMS_ROOT_URL}/courses/course-v1:test_org+test_number+test_run/about' ), ) @ddt.unpack diff --git a/common/djangoapps/util/tests/test_date_utils.py b/common/djangoapps/util/tests/test_date_utils.py index 13a69deb14..2e64ae622d 100644 --- a/common/djangoapps/util/tests/test_date_utils.py +++ b/common/djangoapps/util/tests/test_date_utils.py @@ -1,15 +1,14 @@ -# -*- coding: utf-8 -*- """ Tests for util.date_utils """ - import unittest from datetime import datetime, timedelta, tzinfo -import pytest +from unittest.mock import patch + import ddt +import pytest from markupsafe import Markup -from mock import patch from pytz import utc from common.djangoapps.util.date_utils import ( @@ -127,7 +126,7 @@ class StrftimeLocalizedTest(unittest.TestCase): ("%Y", "2013"), ("%m/%d/%y", "02/14/13"), ("hello", "hello"), - (u'%Y년 %m월 %d일', u"2013년 02월 14일"), + ('%Y년 %m월 %d일', "2013년 02월 14일"), ("%a, %b %d, %Y", "Thu, Feb 14, 2013"), ("%I:%M:%S %p", "04:41:17 PM"), ("%A at %-I%P", "Thursday at 4pm"), diff --git a/common/djangoapps/util/tests/test_db.py b/common/djangoapps/util/tests/test_db.py index e1b67b6712..f3e3db4539 100644 --- a/common/djangoapps/util/tests/test_db.py +++ b/common/djangoapps/util/tests/test_db.py @@ -4,6 +4,7 @@ import threading import time import unittest +from io import StringIO import ddt from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user @@ -12,8 +13,6 @@ from django.db import IntegrityError, connection from django.db.transaction import TransactionManagementError, atomic from django.test import TestCase, TransactionTestCase from django.test.utils import override_settings -from django.utils.six import StringIO -from six.moves import range from common.djangoapps.util.db import enable_named_outer_atomic, generate_int_id, outer_atomic @@ -54,7 +53,7 @@ class TransactionManagersTestCase(TransactionTestCase): class RequestThread(threading.Thread): """ A thread which runs a dummy view.""" def __init__(self, delay, **kwargs): - super(RequestThread, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) self.delay = delay self.status = {} @@ -189,7 +188,7 @@ class GenerateIntIdTestCase(TestCase): used_ids = {2, 4, 6, 8} for __ in range(times): int_id = generate_int_id(minimum, maximum, used_ids) - assert int_id in list((set(range(minimum, (maximum + 1))) - used_ids)) + assert int_id in list(set(range(minimum, (maximum + 1))) - used_ids) class MigrationTests(TestCase): diff --git a/common/djangoapps/util/tests/test_disable_rate_limit.py b/common/djangoapps/util/tests/test_disable_rate_limit.py index 35d7b122b2..988eecc1f2 100644 --- a/common/djangoapps/util/tests/test_disable_rate_limit.py +++ b/common/djangoapps/util/tests/test_disable_rate_limit.py @@ -2,9 +2,9 @@ import unittest +from unittest import mock import pytest -import mock from django.conf import settings from django.core.cache import cache from django.test import TestCase @@ -33,7 +33,7 @@ class DisableRateLimitTest(TestCase): """Check that we can disable rate limiting for perf testing. """ def setUp(self): - super(DisableRateLimitTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() cache.clear() self.view = FakeApiView() diff --git a/common/djangoapps/util/tests/test_django_utils.py b/common/djangoapps/util/tests/test_django_utils.py index 22f0d7d945..9a22bb8852 100644 --- a/common/djangoapps/util/tests/test_django_utils.py +++ b/common/djangoapps/util/tests/test_django_utils.py @@ -13,7 +13,7 @@ from django.core.cache import caches from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase -class CacheCheckMixin(object): +class CacheCheckMixin: """Base mixin that does our cache check.""" def check_caches(self, key): diff --git a/common/djangoapps/util/tests/test_file.py b/common/djangoapps/util/tests/test_file.py index 4e391df539..1bb033798c 100644 --- a/common/djangoapps/util/tests/test_file.py +++ b/common/djangoapps/util/tests/test_file.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Tests for file.py """ @@ -7,17 +6,17 @@ Tests for file.py import os from datetime import datetime from io import StringIO +from unittest.mock import Mock, patch + import pytest import ddt from django.core import exceptions from django.core.files.uploadedfile import SimpleUploadedFile from django.http import HttpRequest from django.test import TestCase -from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import CourseLocator from pytz import UTC -from six import text_type import common.djangoapps.util.file from common.djangoapps.util.file import ( @@ -36,11 +35,11 @@ class FilenamePrefixGeneratorTestCase(TestCase): """ @ddt.data(CourseLocator(org='foo', course='bar', run='baz'), CourseKey.from_string('foo/bar/baz')) def test_locators(self, course_key): - assert course_filename_prefix_generator(course_key) == u'foo_bar_baz' + assert course_filename_prefix_generator(course_key) == 'foo_bar_baz' @ddt.data(CourseLocator(org='foo', course='bar', run='baz'), CourseKey.from_string('foo/bar/baz')) def test_custom_separator(self, course_key): - assert course_filename_prefix_generator(course_key, separator='-') == u'foo-bar-baz' + assert course_filename_prefix_generator(course_key, separator='-') == 'foo-bar-baz' @ddt.ddt @@ -51,7 +50,7 @@ class FilenameGeneratorTestCase(TestCase): NOW = datetime.strptime('1974-06-22T01:02:03', '%Y-%m-%dT%H:%M:%S').replace(tzinfo=UTC) def setUp(self): - super(FilenameGeneratorTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() datetime_patcher = patch.object( common.djangoapps.util.file, 'datetime', Mock(wraps=datetime) @@ -65,9 +64,9 @@ class FilenameGeneratorTestCase(TestCase): """ Tests that the generator creates names based on course_id, base name, and date. """ - assert u'foo_bar_baz_file_1974-06-22-010203' == course_and_time_based_filename_generator(course_key, 'file') + assert 'foo_bar_baz_file_1974-06-22-010203' == course_and_time_based_filename_generator(course_key, 'file') - assert u'foo_bar_baz_base_name_ø_1974-06-22-010203' ==\ + assert 'foo_bar_baz_base_name_ø_1974-06-22-010203' ==\ course_and_time_based_filename_generator(course_key, ' base` name ø ') @@ -77,7 +76,7 @@ class StoreUploadedFileTestCase(TestCase): """ def setUp(self): - super(StoreUploadedFileTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.request = Mock(spec=HttpRequest) self.file_content = b"test file content" self.stored_file_name = None @@ -85,7 +84,7 @@ class StoreUploadedFileTestCase(TestCase): self.default_max_size = 2000000 def tearDown(self): - super(StoreUploadedFileTestCase, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() if self.file_storage and self.stored_file_name: self.file_storage.delete(self.stored_file_name) @@ -93,7 +92,7 @@ class StoreUploadedFileTestCase(TestCase): """ Helper method to verify exception text. """ - assert expected_message == text_type(error.value) + assert expected_message == str(error.value) def test_error_conditions(self): """ @@ -226,39 +225,39 @@ class TestUniversalNewlineIterator(TestCase): @ddt.data(1, 2, 999) def test_line_feeds(self, buffer_size): assert [thing.decode('utf-8') for thing - in UniversalNewlineIterator(StringIO(u'foo\nbar\n'), buffer_size=buffer_size)] == ['foo\n', 'bar\n'] + in UniversalNewlineIterator(StringIO('foo\nbar\n'), buffer_size=buffer_size)] == ['foo\n', 'bar\n'] @ddt.data(1, 2, 999) def test_carriage_returns(self, buffer_size): assert [thing.decode('utf-8') for thing in - UniversalNewlineIterator(StringIO(u'foo\rbar\r'), buffer_size=buffer_size)] == ['foo\n', 'bar\n'] + UniversalNewlineIterator(StringIO('foo\rbar\r'), buffer_size=buffer_size)] == ['foo\n', 'bar\n'] @ddt.data(1, 2, 999) def test_carriage_returns_and_line_feeds(self, buffer_size): assert [thing.decode('utf-8') for thing in - UniversalNewlineIterator(StringIO(u'foo\r\nbar\r\n'), buffer_size=buffer_size)] == ['foo\n', 'bar\n'] + UniversalNewlineIterator(StringIO('foo\r\nbar\r\n'), buffer_size=buffer_size)] == ['foo\n', 'bar\n'] @ddt.data(1, 2, 999) def test_no_trailing_newline(self, buffer_size): assert [thing.decode('utf-8') for thing in - UniversalNewlineIterator(StringIO(u'foo\nbar'), buffer_size=buffer_size)] == ['foo\n', 'bar'] + UniversalNewlineIterator(StringIO('foo\nbar'), buffer_size=buffer_size)] == ['foo\n', 'bar'] @ddt.data(1, 2, 999) def test_only_one_line(self, buffer_size): assert [thing.decode('utf-8') for thing in - UniversalNewlineIterator(StringIO(u'foo\n'), buffer_size=buffer_size)] == ['foo\n'] + UniversalNewlineIterator(StringIO('foo\n'), buffer_size=buffer_size)] == ['foo\n'] @ddt.data(1, 2, 999) def test_only_one_line_no_trailing_newline(self, buffer_size): assert [thing.decode('utf-8') for thing in - UniversalNewlineIterator(StringIO(u'foo'), buffer_size=buffer_size)] == ['foo'] + UniversalNewlineIterator(StringIO('foo'), buffer_size=buffer_size)] == ['foo'] @ddt.data(1, 2, 999) def test_empty_file(self, buffer_size): assert [thing.decode('utf-8') for thing in - UniversalNewlineIterator(StringIO(u''), buffer_size=buffer_size)] == [] + UniversalNewlineIterator(StringIO(''), buffer_size=buffer_size)] == [] @ddt.data(1, 2, 999) def test_unicode_data(self, buffer_size): assert [thing.decode('utf-8') for thing - in UniversalNewlineIterator(StringIO(u'héllø wo®ld'), buffer_size=buffer_size)] == [u'héllø wo®ld'] + in UniversalNewlineIterator(StringIO('héllø wo®ld'), buffer_size=buffer_size)] == ['héllø wo®ld'] diff --git a/common/djangoapps/util/tests/test_json_request.py b/common/djangoapps/util/tests/test_json_request.py index ec0563f412..ad4ec9156b 100644 --- a/common/djangoapps/util/tests/test_json_request.py +++ b/common/djangoapps/util/tests/test_json_request.py @@ -6,7 +6,7 @@ Test for JsonResponse and JsonResponseBadRequest util classes. import json import unittest -import mock +from unittest import mock from django.http import HttpResponse, HttpResponseBadRequest from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadRequest diff --git a/common/djangoapps/util/tests/test_keyword_sub_utils.py b/common/djangoapps/util/tests/test_keyword_sub_utils.py index 2010a74b93..40429783df 100644 --- a/common/djangoapps/util/tests/test_keyword_sub_utils.py +++ b/common/djangoapps/util/tests/test_keyword_sub_utils.py @@ -1,11 +1,9 @@ """ Tests for keyword_substitution.py """ +from unittest.mock import patch - -import six from ddt import ddt, file_data -from mock import patch from common.djangoapps.student.tests.factories import UserFactory from common.djangoapps.util import keyword_substitution as Ks @@ -21,7 +19,7 @@ class KeywordSubTest(ModuleStoreTestCase): CREATE_USER = False def setUp(self): - super(KeywordSubTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create( email="testuser@edx.org", username="testuser", @@ -115,14 +113,14 @@ class KeywordSubTest(ModuleStoreTestCase): """ test_string = 'This string should not be subbed here %%USER_ID%%' - no_course_context = dict( - (key, value) for key, value in six.iteritems(self.context) if key != 'course_title' - ) + no_course_context = { + key: value for key, value in self.context.items() if key != 'course_title' + } result = Ks.substitute_keywords_with_data(test_string, no_course_context) assert test_string == result - no_user_id_context = dict( - (key, value) for key, value in six.iteritems(self.context) if key != 'user_id' - ) + no_user_id_context = { + key: value for key, value in self.context.items() if key != 'user_id' + } result = Ks.substitute_keywords_with_data(test_string, no_user_id_context) assert test_string == result diff --git a/common/djangoapps/util/tests/test_memcache.py b/common/djangoapps/util/tests/test_memcache.py index c636d43e57..8854d6b8c5 100644 --- a/common/djangoapps/util/tests/test_memcache.py +++ b/common/djangoapps/util/tests/test_memcache.py @@ -5,8 +5,6 @@ Tests for memcache in util app from django.core.cache import caches from django.test import TestCase -from six import unichr -from six.moves import range from common.djangoapps.util.memcache import safe_key @@ -21,7 +19,7 @@ class MemcacheTest(TestCase): [129, 500, 2 ** 8 - 1, 2 ** 8 + 1, 2 ** 16 - 1]) def setUp(self): - super(MemcacheTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.cache = caches['default'] def test_safe_key(self): @@ -51,7 +49,7 @@ class MemcacheTest(TestCase): key = safe_key(key, '', '') # The key should now be valid - assert self._is_valid_key(key), 'Failed for key length {0}'.format(length) + assert self._is_valid_key(key), f'Failed for key length {length}' def test_long_key_prefix_version(self): @@ -72,39 +70,39 @@ class MemcacheTest(TestCase): for unicode_char in self.UNICODE_CHAR_CODES: # Generate a key with that character - key = unichr(unicode_char) + key = chr(unicode_char) # Make the key safe key = safe_key(key, '', '') # The key should now be valid - assert self._is_valid_key(key), 'Failed for unicode character {0}'.format(unicode_char) + assert self._is_valid_key(key), f'Failed for unicode character {unicode_char}' def test_safe_key_prefix_unicode(self): for unicode_char in self.UNICODE_CHAR_CODES: # Generate a prefix with that character - prefix = unichr(unicode_char) + prefix = chr(unicode_char) # Make the key safe key = safe_key('test', prefix, '') # The key should now be valid - assert self._is_valid_key(key), 'Failed for unicode character {0}'.format(unicode_char) + assert self._is_valid_key(key), f'Failed for unicode character {unicode_char}' def test_safe_key_version_unicode(self): for unicode_char in self.UNICODE_CHAR_CODES: # Generate a version with that character - version = unichr(unicode_char) + version = chr(unicode_char) # Make the key safe key = safe_key('test', '', version) # The key should now be valid - assert self._is_valid_key(key), 'Failed for unicode character {0}'.format(unicode_char) + assert self._is_valid_key(key), f'Failed for unicode character {unicode_char}' def _is_valid_key(self, key): """ diff --git a/common/djangoapps/util/tests/test_milestones_helpers.py b/common/djangoapps/util/tests/test_milestones_helpers.py index 1758cb55dd..436f8a92d3 100644 --- a/common/djangoapps/util/tests/test_milestones_helpers.py +++ b/common/djangoapps/util/tests/test_milestones_helpers.py @@ -1,17 +1,15 @@ """ Tests for the milestones helpers library, which is the integration point for the edx_milestones API """ - +from unittest.mock import patch import ddt import pytest -import six from django.conf import settings from django.contrib.auth.models import AnonymousUser from milestones import api as milestones_api from milestones.exceptions import InvalidCourseKeyException, InvalidUserException from milestones.models import MilestoneRelationshipType -from mock import patch from common.djangoapps.util import milestones_helpers from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -31,7 +29,7 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): """ Test case scaffolding """ - super(MilestonesHelpersTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create( metadata={ 'entrance_exam_enabled': True, @@ -80,16 +78,16 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): assert len(response) == 0 def test_add_course_milestone_returns_none_when_app_disabled(self): - response = milestones_helpers.add_course_milestone(six.text_type(self.course.id), 'requires', self.milestone) + response = milestones_helpers.add_course_milestone(str(self.course.id), 'requires', self.milestone) assert response is None def test_get_course_milestones_returns_none_when_app_disabled(self): - response = milestones_helpers.get_course_milestones(six.text_type(self.course.id)) + response = milestones_helpers.get_course_milestones(str(self.course.id)) assert len(response) == 0 def test_add_course_content_milestone_returns_none_when_app_disabled(self): response = milestones_helpers.add_course_content_milestone( - six.text_type(self.course.id), + str(self.course.id), 'i4x://any/content/id', 'requires', self.milestone @@ -98,7 +96,7 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): def test_get_course_content_milestones_returns_none_when_app_disabled(self): response = milestones_helpers.get_course_content_milestones( - six.text_type(self.course.id), + str(self.course.id), 'i4x://doesnt/matter/for/this/test', 'requires' ) @@ -113,7 +111,7 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): assert 'ENTRANCE_EXAM' in response def test_get_course_milestones_fulfillment_paths_returns_none_when_app_disabled(self): - response = milestones_helpers.get_course_milestones_fulfillment_paths(six.text_type(self.course.id), self.user) + response = milestones_helpers.get_course_milestones_fulfillment_paths(str(self.course.id), self.user) assert response is None def test_add_user_milestone_returns_none_when_app_disabled(self): diff --git a/common/djangoapps/util/tests/test_password_policy_validators.py b/common/djangoapps/util/tests/test_password_policy_validators.py index 3b11fadde5..e316049379 100644 --- a/common/djangoapps/util/tests/test_password_policy_validators.py +++ b/common/djangoapps/util/tests/test_password_policy_validators.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Tests for util.password_policy_validators module.""" @@ -48,7 +47,7 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): def test_unicode_password(self): """ Tests that validate_password enforces unicode """ - unicode_str = u'𤭮' + unicode_str = '𤭮' byte_str = unicode_str.encode('utf-8') # Sanity checks and demonstration of why this test is useful @@ -65,7 +64,7 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): def test_password_unicode_normalization(self): """ Tests that validate_password normalizes passwords """ # s ̣ ̇ (s with combining dot below and combining dot above) - not_normalized_password = u'\u0073\u0323\u0307' + not_normalized_password = '\u0073\u0323\u0307' assert len(not_normalized_password) == 3 # When we normalize we expect the not_normalized password to fail @@ -102,10 +101,10 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): assert msg in password_validators_instruction_texts() @data( - (u'userna', u'username', 'test@example.com', 'The password is too similar to the username.'), - (u'password', u'username', 'password@example.com', 'The password is too similar to the email address.'), - (u'password', u'username', 'test@password.com', 'The password is too similar to the email address.'), - (u'password', u'username', 'test@example.com', None), + ('userna', 'username', 'test@example.com', 'The password is too similar to the username.'), + ('password', 'username', 'password@example.com', 'The password is too similar to the email address.'), + ('password', 'username', 'test@password.com', 'The password is too similar to the email address.'), + ('password', 'username', 'test@example.com', None), ) @unpack @override_settings(AUTH_PASSWORD_VALIDATORS=[ @@ -118,13 +117,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.MinimumLengthValidator', {'min_length': 1})], # lint-amnesty, pylint: disable=line-too-long - u'', 'This password is too short. It must contain at least 1 character.'), + '', 'This password is too short. It must contain at least 1 character.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.MinimumLengthValidator', {'min_length': 8})], # lint-amnesty, pylint: disable=line-too-long - u'd', 'This password is too short. It must contain at least 8 characters.'), + 'd', 'This password is too short. It must contain at least 8 characters.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.MinimumLengthValidator', {'min_length': 8})], # lint-amnesty, pylint: disable=line-too-long - u'longpassword', None), + 'longpassword', None), ) @unpack def test_minimum_length_validation_errors(self, config, password, msg): @@ -134,13 +133,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.MaximumLengthValidator', {'max_length': 1})], # lint-amnesty, pylint: disable=line-too-long - u'longpassword', 'This password is too long. It must contain no more than 1 character.'), + 'longpassword', 'This password is too long. It must contain no more than 1 character.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.MaximumLengthValidator', {'max_length': 10})], # lint-amnesty, pylint: disable=line-too-long - u'longpassword', 'This password is too long. It must contain no more than 10 characters.'), + 'longpassword', 'This password is too long. It must contain no more than 10 characters.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.MaximumLengthValidator', {'max_length': 20})], # lint-amnesty, pylint: disable=line-too-long - u'shortpassword', None), + 'shortpassword', None), ) @unpack def test_maximum_length_validation_errors(self, config, password, msg): @@ -149,8 +148,8 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): self.validation_errors_checker(password, msg) @data( - (u'password', 'This password is too common.'), - (u'good_password', None), + ('password', 'This password is too common.'), + ('good_password', None), ) @unpack @override_settings(AUTH_PASSWORD_VALIDATORS=[ @@ -162,13 +161,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.AlphabeticValidator', {'min_alphabetic': 1})], # lint-amnesty, pylint: disable=line-too-long - u'12345', 'This password must contain at least 1 letter.'), + '12345', 'This password must contain at least 1 letter.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.AlphabeticValidator', {'min_alphabetic': 5})], # lint-amnesty, pylint: disable=line-too-long - u'test123', 'This password must contain at least 5 letters.'), + 'test123', 'This password must contain at least 5 letters.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.AlphabeticValidator', {'min_alphabetic': 2})], # lint-amnesty, pylint: disable=line-too-long - u'password', None), + 'password', None), ) @unpack def test_alphabetic_validation_errors(self, config, password, msg): @@ -178,13 +177,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.NumericValidator', {'min_numeric': 1})], # lint-amnesty, pylint: disable=line-too-long - u'test', 'This password must contain at least 1 number.'), + 'test', 'This password must contain at least 1 number.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.NumericValidator', {'min_numeric': 4})], # lint-amnesty, pylint: disable=line-too-long - u'test123', 'This password must contain at least 4 numbers.'), + 'test123', 'This password must contain at least 4 numbers.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.NumericValidator', {'min_numeric': 2})], # lint-amnesty, pylint: disable=line-too-long - u'password123', None), + 'password123', None), ) @unpack def test_numeric_validation_errors(self, config, password, msg): @@ -194,13 +193,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.UppercaseValidator', {'min_upper': 1})], # lint-amnesty, pylint: disable=line-too-long - u'lowercase', 'This password must contain at least 1 uppercase letter.'), + 'lowercase', 'This password must contain at least 1 uppercase letter.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.UppercaseValidator', {'min_upper': 6})], # lint-amnesty, pylint: disable=line-too-long - u'NOTenough', 'This password must contain at least 6 uppercase letters.'), + 'NOTenough', 'This password must contain at least 6 uppercase letters.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.UppercaseValidator', {'min_upper': 1})], # lint-amnesty, pylint: disable=line-too-long - u'camelCase', None), + 'camelCase', None), ) @unpack def test_upper_case_validation_errors(self, config, password, msg): @@ -210,13 +209,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.LowercaseValidator', {'min_lower': 1})], # lint-amnesty, pylint: disable=line-too-long - u'UPPERCASE', 'This password must contain at least 1 lowercase letter.'), + 'UPPERCASE', 'This password must contain at least 1 lowercase letter.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.LowercaseValidator', {'min_lower': 4})], # lint-amnesty, pylint: disable=line-too-long - u'notENOUGH', 'This password must contain at least 4 lowercase letters.'), + 'notENOUGH', 'This password must contain at least 4 lowercase letters.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.LowercaseValidator', {'min_lower': 1})], # lint-amnesty, pylint: disable=line-too-long - u'goodPassword', None), + 'goodPassword', None), ) @unpack def test_lower_case_validation_errors(self, config, password, msg): @@ -226,13 +225,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.PunctuationValidator', {'min_punctuation': 1})], # lint-amnesty, pylint: disable=line-too-long - u'no punctuation', 'This password must contain at least 1 punctuation mark.'), + 'no punctuation', 'This password must contain at least 1 punctuation mark.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.PunctuationValidator', {'min_punctuation': 7})], # lint-amnesty, pylint: disable=line-too-long - u'p@$$w0rd$!', 'This password must contain at least 7 punctuation marks.'), + 'p@$$w0rd$!', 'This password must contain at least 7 punctuation marks.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.PunctuationValidator', {'min_punctuation': 3})], # lint-amnesty, pylint: disable=line-too-long - u'excl@m@t!on', None), + 'excl@m@t!on', None), ) @unpack def test_punctuation_validation_errors(self, config, password, msg): @@ -242,13 +241,13 @@ class PasswordPolicyValidatorsTestCase(unittest.TestCase): @data( ([create_validator_config('common.djangoapps.util.password_policy_validators.SymbolValidator', {'min_symbol': 1})], # lint-amnesty, pylint: disable=line-too-long - u'no symbol', 'This password must contain at least 1 symbol.'), + 'no symbol', 'This password must contain at least 1 symbol.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.SymbolValidator', {'min_symbol': 3})], # lint-amnesty, pylint: disable=line-too-long - u'☹️boo☹️', 'This password must contain at least 3 symbols.'), + '☹️boo☹️', 'This password must contain at least 3 symbols.'), ([create_validator_config('common.djangoapps.util.password_policy_validators.SymbolValidator', {'min_symbol': 2})], # lint-amnesty, pylint: disable=line-too-long - u'☪symbols!☹️', None), + '☪symbols!☹️', None), ) @unpack def test_symbol_validation_errors(self, config, password, msg): diff --git a/common/djangoapps/util/url.py b/common/djangoapps/util/url.py index 1240791cd1..11cb0485cd 100644 --- a/common/djangoapps/util/url.py +++ b/common/djangoapps/util/url.py @@ -4,15 +4,11 @@ Utility functions related to urls. import sys -from importlib import import_module +from importlib import import_module, reload -import six from django.conf import settings from django.urls import set_urlconf -if six.PY3: - from importlib import reload - def reload_django_url_config(): """ diff --git a/common/djangoapps/util/validate_on_save.py b/common/djangoapps/util/validate_on_save.py index 08a0ad57d4..4527c73104 100644 --- a/common/djangoapps/util/validate_on_save.py +++ b/common/djangoapps/util/validate_on_save.py @@ -1,7 +1,7 @@ """ Utility mixin; forces models to validate *before* saving to db """ -class ValidateOnSaveMixin(object): +class ValidateOnSaveMixin: """ Forces models to call their full_clean method prior to saving """ @@ -11,4 +11,4 @@ class ValidateOnSaveMixin(object): """ if not (force_insert or force_update): self.full_clean() - super(ValidateOnSaveMixin, self).save(force_insert, force_update, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().save(force_insert, force_update, **kwargs) diff --git a/common/djangoapps/util/views.py b/common/djangoapps/util/views.py index 36e8129835..73a164561c 100644 --- a/common/djangoapps/util/views.py +++ b/common/djangoapps/util/views.py @@ -14,7 +14,6 @@ from django.views.defaults import server_error from django.shortcuts import redirect from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey, UsageKey -from six.moves import map from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.masquerade import setup_masquerade @@ -75,7 +74,7 @@ def require_global_staff(func): return func(request, *args, **kwargs) else: return HttpResponseForbidden( - u"Must be {platform_name} staff to perform this action.".format( + "Must be {platform_name} staff to perform this action.".format( platform_name=settings.PLATFORM_NAME ) ) diff --git a/common/djangoapps/xblock_django/migrations/0001_initial.py b/common/djangoapps/xblock_django/migrations/0001_initial.py index 5490aa16b2..a0d948211d 100644 --- a/common/djangoapps/xblock_django/migrations/0001_initial.py +++ b/common/djangoapps/xblock_django/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import django.db.models.deletion from django.conf import settings from django.db import migrations, models @@ -19,7 +16,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')), ('enabled', models.BooleanField(default=False, verbose_name='Enabled')), - ('disabled_blocks', models.TextField(default=u'', help_text='Space-separated list of XBlocks which should not render.', blank=True)), + ('disabled_blocks', models.TextField(default='', help_text='Space-separated list of XBlocks which should not render.', blank=True)), ('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')), ], options={ diff --git a/common/djangoapps/xblock_django/migrations/0002_auto_20160204_0809.py b/common/djangoapps/xblock_django/migrations/0002_auto_20160204_0809.py index 69a5f84ae2..e3b9a67e6c 100644 --- a/common/djangoapps/xblock_django/migrations/0002_auto_20160204_0809.py +++ b/common/djangoapps/xblock_django/migrations/0002_auto_20160204_0809.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models @@ -14,6 +11,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='xblockdisableconfig', name='disabled_create_blocks', - field=models.TextField(default=u'', help_text='Space-separated list of XBlock types whose creation to disable in Studio.', blank=True), + field=models.TextField(default='', help_text='Space-separated list of XBlock types whose creation to disable in Studio.', blank=True), ), ] diff --git a/common/djangoapps/xblock_django/migrations/0003_add_new_config_models.py b/common/djangoapps/xblock_django/migrations/0003_add_new_config_models.py index 880f40943a..a5a00002b3 100644 --- a/common/djangoapps/xblock_django/migrations/0003_add_new_config_models.py +++ b/common/djangoapps/xblock_django/migrations/0003_add_new_config_models.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import django.db.models.deletion from django.conf import settings from django.db import migrations, models @@ -36,8 +33,8 @@ class Migration(migrations.Migration): ('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')), ('enabled', models.BooleanField(default=False, verbose_name='Enabled')), ('name', models.CharField(max_length=255, db_index=True)), - ('template', models.CharField(default=u'', max_length=255, blank=True)), - ('support_level', models.CharField(default=u'us', max_length=2, choices=[(u'fs', 'Fully Supported'), (u'ps', 'Provisionally Supported'), (u'us', 'Unsupported')])), + ('template', models.CharField(default='', max_length=255, blank=True)), + ('support_level', models.CharField(default='us', max_length=2, choices=[('fs', 'Fully Supported'), ('ps', 'Provisionally Supported'), ('us', 'Unsupported')])), ('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')), ], ), diff --git a/common/djangoapps/xblock_django/migrations/0004_delete_xblock_disable_config.py b/common/djangoapps/xblock_django/migrations/0004_delete_xblock_disable_config.py index c2e0084b2e..0994309858 100644 --- a/common/djangoapps/xblock_django/migrations/0004_delete_xblock_disable_config.py +++ b/common/djangoapps/xblock_django/migrations/0004_delete_xblock_disable_config.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models diff --git a/common/djangoapps/xblock_django/models.py b/common/djangoapps/xblock_django/models.py index 5df96dcb58..d663953d65 100644 --- a/common/djangoapps/xblock_django/models.py +++ b/common/djangoapps/xblock_django/models.py @@ -40,13 +40,13 @@ class XBlockStudioConfigurationFlag(ConfigurationModel): .. no_pii: """ - class Meta(object): + class Meta: app_label = "xblock_django" # boolean field 'enabled' inherited from parent ConfigurationModel def __str__(self): - return "XBlockStudioConfigurationFlag(enabled={})".format(self.enabled) + return f"XBlockStudioConfigurationFlag(enabled={self.enabled})" class XBlockStudioConfiguration(ConfigurationModel): @@ -57,9 +57,9 @@ class XBlockStudioConfiguration(ConfigurationModel): """ KEY_FIELDS = ('name', 'template') # xblock name/template combination is unique - FULL_SUPPORT = u'fs' - PROVISIONAL_SUPPORT = u'ps' - UNSUPPORTED = u'us' + FULL_SUPPORT = 'fs' + PROVISIONAL_SUPPORT = 'ps' + UNSUPPORTED = 'us' SUPPORT_CHOICES = ( (FULL_SUPPORT, _('Fully Supported')), @@ -69,10 +69,10 @@ class XBlockStudioConfiguration(ConfigurationModel): # boolean field 'enabled' inherited from parent ConfigurationModel name = models.CharField(max_length=255, null=False, db_index=True) - template = models.CharField(max_length=255, blank=True, default=u'') + template = models.CharField(max_length=255, blank=True, default='') support_level = models.CharField(max_length=2, choices=SUPPORT_CHOICES, default=UNSUPPORTED) - class Meta(object): + class Meta: app_label = "xblock_django" def __str__(self): diff --git a/common/djangoapps/xblock_django/tests/test_api.py b/common/djangoapps/xblock_django/tests/test_api.py index 9852d0c135..886020f173 100644 --- a/common/djangoapps/xblock_django/tests/test_api.py +++ b/common/djangoapps/xblock_django/tests/test_api.py @@ -1,10 +1,6 @@ """ Tests related to XBlock support API. """ - - -import six - from openedx.core.djangolib.testing.utils import CacheIsolationTestCase from common.djangoapps.xblock_django.api import authorable_xblocks, deprecated_xblocks, disabled_xblocks from common.djangoapps.xblock_django.models import XBlockConfiguration, XBlockStudioConfiguration, XBlockStudioConfigurationFlag # lint-amnesty, pylint: disable=line-too-long @@ -15,7 +11,7 @@ class XBlockSupportTestCase(CacheIsolationTestCase): Tests for XBlock Support methods. """ def setUp(self): - super(XBlockSupportTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Set up XBlockConfigurations for disabled and deprecated states block_config = [ @@ -47,23 +43,23 @@ class XBlockSupportTestCase(CacheIsolationTestCase): """ Tests the deprecated_xblocks method """ deprecated_xblock_names = [block.name for block in deprecated_xblocks()] - six.assertCountEqual(self, ["poll", "survey"], deprecated_xblock_names) + self.assertCountEqual(["poll", "survey"], deprecated_xblock_names) XBlockConfiguration(name="poll", enabled=True, deprecated=False).save() deprecated_xblock_names = [block.name for block in deprecated_xblocks()] - six.assertCountEqual(self, ["survey"], deprecated_xblock_names) + self.assertCountEqual(["survey"], deprecated_xblock_names) def test_disabled_blocks(self): """ Tests the disabled_xblocks method """ disabled_xblock_names = [block.name for block in disabled_xblocks()] - six.assertCountEqual(self, ["survey"], disabled_xblock_names) + self.assertCountEqual(["survey"], disabled_xblock_names) XBlockConfiguration(name="poll", enabled=False, deprecated=True).save() disabled_xblock_names = [block.name for block in disabled_xblocks()] - six.assertCountEqual(self, ["survey", "poll"], disabled_xblock_names) + self.assertCountEqual(["survey", "poll"], disabled_xblock_names) def test_authorable_blocks_empty_model(self): """ @@ -81,7 +77,7 @@ class XBlockSupportTestCase(CacheIsolationTestCase): Tests authorable_xblocks when name is not specified. """ authorable_xblock_names = [block.name for block in authorable_xblocks()] - six.assertCountEqual(self, ["done", "problem", "problem", "html"], authorable_xblock_names) + self.assertCountEqual(["done", "problem", "problem", "html"], authorable_xblock_names) # Note that "survey" is disabled in XBlockConfiguration, but it is still returned by # authorable_xblocks because it is marked as enabled and unsupported in XBlockStudioConfiguration. @@ -89,8 +85,7 @@ class XBlockSupportTestCase(CacheIsolationTestCase): # is a whitelist and uses a combination of xblock type and template (and in addition has a global feature flag), # it is expected that Studio code will need to filter by both disabled_xblocks and authorable_xblocks. authorable_xblock_names = [block.name for block in authorable_xblocks(allow_unsupported=True)] - six.assertCountEqual( - self, + self.assertCountEqual( ["survey", "done", "problem", "problem", "problem", "html", "split_module"], authorable_xblock_names ) diff --git a/common/djangoapps/xblock_django/tests/test_user_service.py b/common/djangoapps/xblock_django/tests/test_user_service.py index 8edf900093..6d090417c5 100644 --- a/common/djangoapps/xblock_django/tests/test_user_service.py +++ b/common/djangoapps/xblock_django/tests/test_user_service.py @@ -26,7 +26,7 @@ class UserServiceTestCase(TestCase): Tests for the DjangoXBlockUserService. """ def setUp(self): - super(UserServiceTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory(username="tester", email="test@tester.com") self.user.profile.name = "Test Tester" set_user_preference(self.user, 'pref-lang', 'en') @@ -52,7 +52,7 @@ class UserServiceTestCase(TestCase): assert xb_user.opt_attrs[ATTR_KEY_USERNAME] == dj_user.username assert xb_user.opt_attrs[ATTR_KEY_USER_ID] == dj_user.id assert not xb_user.opt_attrs[ATTR_KEY_USER_IS_STAFF] - assert all(((pref in USER_PREFERENCES_WHITE_LIST) for pref in xb_user.opt_attrs[ATTR_KEY_USER_PREFERENCES])) + assert all((pref in USER_PREFERENCES_WHITE_LIST) for pref in xb_user.opt_attrs[ATTR_KEY_USER_PREFERENCES]) def test_convert_anon_user(self): """ diff --git a/common/djangoapps/xblock_django/user_service.py b/common/djangoapps/xblock_django/user_service.py index bf3643ff36..23af5ca273 100644 --- a/common/djangoapps/xblock_django/user_service.py +++ b/common/djangoapps/xblock_django/user_service.py @@ -24,7 +24,7 @@ class DjangoXBlockUserService(UserService): A user service that converts Django users to XBlockUser """ def __init__(self, django_user, **kwargs): - super(DjangoXBlockUserService, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) self._django_user = django_user if self._django_user: self._django_user.user_is_staff = kwargs.get('user_is_staff', False)