diff --git a/common/lib/xmodule/xmodule/tests/test_content.py b/common/lib/xmodule/xmodule/tests/test_content.py index 5963c2f478..93a50e4e35 100644 --- a/common/lib/xmodule/xmodule/tests/test_content.py +++ b/common/lib/xmodule/xmodule/tests/test_content.py @@ -3,9 +3,9 @@ import os import unittest +from unittest.mock import Mock, patch import ddt -from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import AssetLocator, CourseLocator from path import Path as path @@ -54,7 +54,7 @@ injected humour and the like). """ -class Content(object): +class Content: """ A class with location and content_type members """ @@ -64,7 +64,7 @@ class Content(object): self.data = None -class FakeGridFsItem(object): +class FakeGridFsItem: """ This class provides the basic methods to get data from a GridFS item """ @@ -112,19 +112,19 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c assert content.thumbnail_location is None @ddt.data( - (u"monsters__.jpg", u"monsters__.jpg"), - (u"monsters__.png", u"monsters__-png.jpg"), - (u"dots.in.name.jpg", u"dots.in.name.jpg"), - (u"dots.in.name.png", u"dots.in.name-png.jpg"), + ("monsters__.jpg", "monsters__.jpg"), + ("monsters__.png", "monsters__-png.jpg"), + ("dots.in.name.jpg", "dots.in.name.jpg"), + ("dots.in.name.png", "dots.in.name-png.jpg"), ) @ddt.unpack def test_generate_thumbnail_image(self, original_filename, thumbnail_filename): content_store = ContentStore() - content = Content(AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'asset', original_filename), + content = Content(AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'asset', original_filename), None) (thumbnail_content, thumbnail_file_location) = content_store.generate_thumbnail(content) assert thumbnail_content is None - assert AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename) ==\ + assert AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'thumbnail', thumbnail_filename) ==\ thumbnail_file_location @patch('xmodule.contentstore.content.Image') @@ -135,7 +135,7 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c image_class_mock.open.return_value = mock_image content_store = ContentStore() - content = Content(AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'asset', "monsters.jpg"), + content = Content(AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'asset', "monsters.jpg"), "image/jpeg") content.data = b'mock data' content_store.generate_thumbnail(content) @@ -147,13 +147,13 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c # SVG files should be stored in original form for thumbnail purposes. content_store = ContentStore() content_store.save = Mock() - thumbnail_filename = u'test.svg' - content = Content(AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'asset', u'test.svg'), + thumbnail_filename = 'test.svg' + content = Content(AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'asset', 'test.svg'), 'image/svg+xml') content.data = b'mock svg file' (thumbnail_content, thumbnail_file_location) = content_store.generate_thumbnail(content) assert thumbnail_content.data.read() == b'mock svg file' - assert AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename) ==\ + assert AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'thumbnail', thumbnail_filename) ==\ thumbnail_file_location def test_compute_location(self): @@ -162,13 +162,13 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c asset_location = StaticContent.compute_location( CourseKey.from_string('mitX/400/ignore'), 'subs__1eo_jXvZnE .srt.sjson' ) - assert AssetLocator(CourseLocator(u'mitX', u'400', u'ignore', deprecated=True), - u'asset', u'subs__1eo_jXvZnE_.srt.sjson') == asset_location + assert AssetLocator(CourseLocator('mitX', '400', 'ignore', deprecated=True), + 'asset', 'subs__1eo_jXvZnE_.srt.sjson') == asset_location def test_get_location_from_path(self): - asset_location = StaticContent.get_location_from_path(u'/c4x/a/b/asset/images_course_image.jpg') - assert AssetLocator(CourseLocator(u'a', u'b', None, deprecated=True), - u'asset', u'images_course_image.jpg', deprecated=True) == asset_location + asset_location = StaticContent.get_location_from_path('/c4x/a/b/asset/images_course_image.jpg') + assert AssetLocator(CourseLocator('a', 'b', None, deprecated=True), + 'asset', 'images_course_image.jpg', deprecated=True) == asset_location def test_static_content_stream_stream_data(self): """ @@ -210,8 +210,8 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c """ Test that only one filename starts with 000. """ - output_root = path(u'common/static/xmodule/descriptors/js') + output_root = path('common/static/xmodule/descriptors/js') file_owners = _write_js(output_root, _list_descriptors(), 'get_studio_view_js') - js_file_paths = set(file_path for file_path in sum(list(file_owners.values()), []) if os.path.basename(file_path).startswith('000-')) # lint-amnesty, pylint: disable=line-too-long + js_file_paths = {file_path for file_path in sum(list(file_owners.values()), []) if os.path.basename(file_path).startswith('000-')} # lint-amnesty, pylint: disable=line-too-long assert len(js_file_paths) == 1 assert 'XModule.Descriptor = (function() {' in open(js_file_paths.pop()).read() diff --git a/common/lib/xmodule/xmodule/tests/test_course_metadata_utils.py b/common/lib/xmodule/xmodule/tests/test_course_metadata_utils.py index f4f06c31fc..0019e443c8 100644 --- a/common/lib/xmodule/xmodule/tests/test_course_metadata_utils.py +++ b/common/lib/xmodule/xmodule/tests/test_course_metadata_utils.py @@ -44,7 +44,7 @@ class CourseMetadataUtilsTestCase(TestCase): """ Set up module store testing capabilities and initialize test courses. """ - super(CourseMetadataUtilsTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() mongo_builder = MongoModulestoreBuilder() split_builder = VersioningModulestoreBuilder() diff --git a/common/lib/xmodule/xmodule/tests/test_course_module.py b/common/lib/xmodule/xmodule/tests/test_course_module.py index 974ff7d07d..54361635a4 100644 --- a/common/lib/xmodule/xmodule/tests/test_course_module.py +++ b/common/lib/xmodule/xmodule/tests/test_course_module.py @@ -4,13 +4,14 @@ import itertools import unittest from datetime import datetime, timedelta +from unittest.mock import Mock, patch + import pytest import ddt from dateutil import parser from django.conf import settings from django.test import override_settings from fs.memoryfs import MemoryFS -from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from pytz import utc from xblock.runtime import DictKeyValueStore, KvsFieldData @@ -46,7 +47,7 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho course_dir = "test_dir" error_tracker = Mock() - super(DummySystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( xmlstore=xmlstore, course_id=course_id, course_dir=course_dir, @@ -62,7 +63,7 @@ def get_dummy_course(start, announcement=None, is_new=None, advertised_start=Non system = DummySystem(load_error_modules=True) def to_attrb(n, v): - return '' if v is None else '{0}="{1}"'.format(n, v).lower() + return '' if v is None else f'{n}="{v}"'.lower() is_new = to_attrb('is_new', is_new) announcement = to_attrb('announcement', announcement) @@ -100,7 +101,7 @@ class HasEndedMayCertifyTestCase(unittest.TestCase): """Double check the semantics around when to finalize courses.""" def setUp(self): - super(HasEndedMayCertifyTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() system = DummySystem(load_error_modules=True) # lint-amnesty, pylint: disable=unused-variable #sample_xml = """ @@ -161,7 +162,7 @@ class IsNewCourseTestCase(unittest.TestCase): """Make sure the property is_new works on courses""" def setUp(self): - super(IsNewCourseTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Needed for test_is_newish datetime_patcher = patch.object( @@ -210,13 +211,13 @@ class IsNewCourseTestCase(unittest.TestCase): for a, b, assertion in dates: a_score = get_dummy_course(start=a[0], announcement=a[1], advertised_start=a[2]).sorting_score b_score = get_dummy_course(start=b[0], announcement=b[1], advertised_start=b[2]).sorting_score - print("Comparing %s to %s" % (a, b)) + print(f"Comparing {a} to {b}") assertion(a_score, b_score) start_advertised_settings = [ # start, advertised, result, is_still_default, date_time_result - ('2012-12-02T12:00', None, 'Dec 02, 2012', False, u'Dec 02, 2012 at 12:00 UTC'), - ('2012-12-02T12:00', '2011-11-01T12:00', 'Nov 01, 2011', False, u'Nov 01, 2011 at 12:00 UTC'), + ('2012-12-02T12:00', None, 'Dec 02, 2012', False, 'Dec 02, 2012 at 12:00 UTC'), + ('2012-12-02T12:00', '2011-11-01T12:00', 'Nov 01, 2011', False, 'Nov 01, 2011 at 12:00 UTC'), ('2012-12-02T12:00', 'Spring 2012', 'Spring 2012', False, 'Spring 2012'), ('2012-12-02T12:00', 'November, 2011', 'November, 2011', False, 'November, 2011'), (xmodule.course_module.CourseFields.start.default, None, 'TBD', True, 'TBD'), @@ -231,12 +232,12 @@ class IsNewCourseTestCase(unittest.TestCase): def test_display_organization(self): descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True) assert descriptor.location.org != descriptor.display_org_with_default - assert descriptor.display_org_with_default == '{0}_display'.format(ORG) + assert descriptor.display_org_with_default == f'{ORG}_display' def test_display_coursenumber(self): descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True) assert descriptor.location.course != descriptor.display_number_with_default - assert descriptor.display_number_with_default == '{0}_display'.format(COURSE) + assert descriptor.display_number_with_default == f'{COURSE}_display' def test_is_newish(self): descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True) @@ -274,7 +275,7 @@ class TeamsConfigurationTestCase(unittest.TestCase): """ def setUp(self): - super(TeamsConfigurationTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = get_dummy_course('2012-12-02T12:00') self.course.teams_configuration = TeamsConfig(None) self.count = itertools.count() @@ -290,9 +291,9 @@ class TeamsConfigurationTestCase(unittest.TestCase): def make_topic(self): """ Make a sample topic dictionary. """ next_num = next(self.count) - topic_id = "topic_id_{}".format(next_num) - name = "Name {}".format(next_num) - description = "Description {}".format(next_num) + topic_id = f"topic_id_{next_num}" + name = f"Name {next_num}" + description = f"Description {next_num}" return { "name": name, "description": description, @@ -363,7 +364,7 @@ class SelfPacedTestCase(unittest.TestCase): """Tests for self-paced courses.""" def setUp(self): - super(SelfPacedTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = get_dummy_course('2012-12-02T12:00') def test_default(self): @@ -427,7 +428,7 @@ class ProctoringProviderTestCase(unittest.TestCase): """ Initialize dummy testing course. """ - super(ProctoringProviderTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.proctoring_provider = xmodule.course_module.ProctoringProvider() def test_from_json_with_platform_default(self): @@ -447,7 +448,7 @@ class ProctoringProviderTestCase(unittest.TestCase): throws a ValueError with the correct error message. """ provider = 'invalid-provider' - allowed_proctoring_providers = [u'mock', u'mock_proctoring_without_rules'] + allowed_proctoring_providers = ['mock', 'mock_proctoring_without_rules'] with pytest.raises(ValueError) as context_manager: self.proctoring_provider.from_json(provider) diff --git a/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py b/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py index 8f636ba6e1..480437a1c8 100644 --- a/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py +++ b/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py @@ -11,9 +11,9 @@ submissions" setting is set to different values import datetime import textwrap import unittest +from unittest.mock import Mock import pytest -from mock import Mock from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from pytz import UTC from xblock.field_data import DictFieldData @@ -26,7 +26,7 @@ from xmodule.capa_module import ProblemBlock from . import get_test_system -class CapaFactoryWithDelay(object): +class CapaFactoryWithDelay: """ Create problem modules class, specialized for delay_between_attempts test cases. This factory seems different enough from the one in @@ -88,7 +88,7 @@ class CapaFactoryWithDelay(object): Optional parameters here are cut down to what we actually use vs. the regular CapaFactory. """ location = BlockUsageLocator(CourseLocator('edX', 'capa_test', 'run', deprecated=True), - 'problem', 'SampleProblem{0}'.format(cls.next_num()), deprecated=True) + 'problem', f'SampleProblem{cls.next_num()}', deprecated=True) field_data = {'data': cls.sample_problem_xml} if max_attempts is not None: diff --git a/common/lib/xmodule/xmodule/tests/test_editing_module.py b/common/lib/xmodule/xmodule/tests/test_editing_module.py index fd870d0164..2515adf119 100644 --- a/common/lib/xmodule/xmodule/tests/test_editing_module.py +++ b/common/lib/xmodule/xmodule/tests/test_editing_module.py @@ -4,8 +4,8 @@ import logging import os import unittest +from unittest.mock import Mock -from mock import Mock from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from pkg_resources import resource_string from xblock.field_data import DictFieldData @@ -21,7 +21,7 @@ class TabsEditingDescriptorTestCase(unittest.TestCase): """ Testing TabsEditingDescriptor""" def setUp(self): - super(TabsEditingDescriptorTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() system = get_test_descriptor_system() system.render_template = Mock(return_value="
Test Template HTML
") self.tabs = [ diff --git a/common/lib/xmodule/xmodule/tests/test_error_module.py b/common/lib/xmodule/xmodule/tests/test_error_module.py index 9bbc0046fc..7e266bd95c 100644 --- a/common/lib/xmodule/xmodule/tests/test_error_module.py +++ b/common/lib/xmodule/xmodule/tests/test_error_module.py @@ -4,9 +4,9 @@ Tests for ErrorBlock and NonStaffErrorBlock import unittest +from unittest.mock import MagicMock, Mock, patch import pytest -from mock import MagicMock, Mock, patch from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from xblock.field_data import DictFieldData from xblock.fields import ScopeIds @@ -27,7 +27,7 @@ class SetupTestErrorBlock(unittest.TestCase): self.system = get_test_system() self.course_id = CourseLocator('org', 'course', 'run') self.location = self.course_id.make_usage_key('foo', 'bar') - self.valid_xml = u"ABC \N{SNOWMAN}" + self.valid_xml = "ABC \N{SNOWMAN}" self.error_msg = "Error" @@ -107,7 +107,7 @@ class TestNonStaffErrorBlock(SetupTestErrorBlock): class BrokenModule(XModule): # lint-amnesty, pylint: disable=abstract-method def __init__(self, *args, **kwargs): - super(BrokenModule, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) raise Exception("This is a broken xmodule") diff --git a/common/lib/xmodule/xmodule/tests/test_export.py b/common/lib/xmodule/xmodule/tests/test_export.py index a399ea3521..c34dd52b4e 100644 --- a/common/lib/xmodule/xmodule/tests/test_export.py +++ b/common/lib/xmodule/xmodule/tests/test_export.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Tests of XML export """ @@ -9,17 +8,16 @@ import unittest from datetime import datetime, timedelta, tzinfo from tempfile import mkdtemp from textwrap import dedent +from unittest import mock + import pytest import ddt import lxml.etree -import mock import pytz -import six from django.utils.translation import ugettext_lazy from fs.osfs import OSFS from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from path import Path as path -from six import text_type from xblock.core import XBlock from xblock.fields import Integer, Scope, String from xblock.test.tools import blocks_are_equivalent @@ -34,7 +32,7 @@ def strip_filenames(descriptor): """ Recursively strips 'filename' from all children's definitions. """ - print("strip filename from {desc}".format(desc=text_type(descriptor.location))) + print("strip filename from {desc}".format(desc=str(descriptor.location))) if descriptor._field_data.has(descriptor, 'filename'): # lint-amnesty, pylint: disable=protected-access descriptor._field_data.delete(descriptor, 'filename') # lint-amnesty, pylint: disable=protected-access @@ -67,7 +65,7 @@ class RoundTripTestCase(unittest.TestCase): """ def setUp(self): - super(RoundTripTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.maxDiff = None self.temp_dir = mkdtemp() self.addCleanup(shutil.rmtree, self.temp_dir) @@ -75,14 +73,14 @@ class RoundTripTestCase(unittest.TestCase): @mock.patch('xmodule.video_module.video_module.edxval_api', None) @mock.patch('xmodule.course_module.requests.get') @ddt.data( - u"toy", - u"simple", - u"conditional_and_poll", - u"conditional", - u"self_assessment", - u"test_exam_registration", - u"word_cloud", - u"pure_xblock", + "toy", + "simple", + "conditional_and_poll", + "conditional", + "self_assessment", + "test_exam_registration", + "word_cloud", + "pure_xblock", ) @XBlock.register_temp_plugin(PureXBlock, 'pure') def test_export_roundtrip(self, course_dir, mock_get): @@ -95,7 +93,7 @@ class RoundTripTestCase(unittest.TestCase): """).strip() root_dir = path(self.temp_dir) - print("Copying test course to temp dir {0}".format(root_dir)) + print(f"Copying test course to temp dir {root_dir}") data_dir = path(DATA_DIR) shutil.copytree(data_dir / course_dir, root_dir / course_dir) @@ -137,8 +135,7 @@ class RoundTripTestCase(unittest.TestCase): course_id = initial_course.id print("Checking key equality") - six.assertCountEqual( - self, + self.assertCountEqual( list(initial_import.modules[course_id].keys()), list(second_import.modules[course_id].keys()) ) @@ -156,7 +153,7 @@ class TestEdxJsonEncoder(unittest.TestCase): """ def setUp(self): - super(TestEdxJsonEncoder, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.encoder = EdxJSONEncoder() @@ -175,10 +172,10 @@ class TestEdxJsonEncoder(unittest.TestCase): def test_encode_location(self): loc = BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'category', 'name') - assert text_type(loc) == self.encoder.default(loc) + assert str(loc) == self.encoder.default(loc) loc = BlockUsageLocator(CourseLocator('org', 'course', 'run', branch='version'), 'category', 'name') - assert text_type(loc) == self.encoder.default(loc) + assert str(loc) == self.encoder.default(loc) def test_encode_naive_datetime(self): assert '2013-05-03T10:20:30.000100' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 100)) @@ -204,7 +201,7 @@ class TestEdxJsonEncoder(unittest.TestCase): """ # Initializing a lazy text object with Unicode - unicode_text = u"Your 𝓟𝓵𝓪𝓽𝓯𝓸𝓻𝓶 Name Here" + unicode_text = "Your 𝓟𝓵𝓪𝓽𝓯𝓸𝓻𝓶 Name Here" lazy_text = ugettext_lazy(unicode_text) # lint-amnesty, pylint: disable=translation-of-non-string assert unicode_text == self.encoder.default(lazy_text) diff --git a/common/lib/xmodule/xmodule/tests/test_fields.py b/common/lib/xmodule/xmodule/tests/test_fields.py index 3e8efb3227..50796dbd54 100644 --- a/common/lib/xmodule/xmodule/tests/test_fields.py +++ b/common/lib/xmodule/xmodule/tests/test_fields.py @@ -78,7 +78,7 @@ class DateTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-clas """ now = datetime.datetime.now(UTC) delta = now - datetime.datetime.fromtimestamp(0, UTC) - assert DateTest.date.from_json((delta.total_seconds() * 1000)) == now + assert DateTest.date.from_json(delta.total_seconds() * 1000) == now yesterday = datetime.datetime.now(UTC) - datetime.timedelta(days=-1) assert DateTest.date.from_json(yesterday) == yesterday diff --git a/common/lib/xmodule/xmodule/tests/test_graders.py b/common/lib/xmodule/xmodule/tests/test_graders.py index ddbe9b8873..5073052b1b 100644 --- a/common/lib/xmodule/xmodule/tests/test_graders.py +++ b/common/lib/xmodule/xmodule/tests/test_graders.py @@ -8,8 +8,6 @@ from datetime import datetime, timedelta import pytest import ddt from pytz import UTC -import six -from six import text_type from lms.djangoapps.grades.scores import compute_percent from xmodule import graders @@ -68,7 +66,7 @@ class GraderTest(unittest.TestCase): 'Midterm': {}, } - class MockGrade(object): + class MockGrade: """ Mock class for SubsectionGrade object. """ @@ -319,25 +317,25 @@ class GraderTest(unittest.TestCase): ( # empty {}, - u"Configuration has no appropriate grader class." + "Configuration has no appropriate grader class." ), ( # no min_count {'type': "Homework", 'drop_count': 0}, - u"Configuration has no appropriate grader class." + "Configuration has no appropriate grader class." ), ( # no drop_count {'type': "Homework", 'min_count': 0}, # pylint: disable=line-too-long - u"__init__() takes at least 4 arguments (3 given)" if six.PY2 else u"__init__() missing 1 required positional argument: 'drop_count'" + "__init__() missing 1 required positional argument: 'drop_count'" ), ) @ddt.unpack def test_grader_with_invalid_conf(self, invalid_conf, expected_error_message): with pytest.raises(ValueError) as error: graders.grader_from_conf([invalid_conf]) - assert expected_error_message in text_type(error.value) + assert expected_error_message in str(error.value) @ddt.ddt @@ -347,7 +345,7 @@ class ShowCorrectnessTest(unittest.TestCase): """ def setUp(self): - super(ShowCorrectnessTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() now = datetime.now(UTC) day_delta = timedelta(days=1) diff --git a/common/lib/xmodule/xmodule/tests/test_html_module.py b/common/lib/xmodule/xmodule/tests/test_html_module.py index 28123b712b..bec6bf5026 100644 --- a/common/lib/xmodule/xmodule/tests/test_html_module.py +++ b/common/lib/xmodule/xmodule/tests/test_html_module.py @@ -1,10 +1,10 @@ # lint-amnesty, pylint: disable=missing-module-docstring import unittest +from unittest.mock import Mock import ddt from django.test.utils import override_settings -from mock import Mock from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from xblock.field_data import DictFieldData from xblock.fields import ScopeIds @@ -312,7 +312,7 @@ class CourseInfoBlockTestCase(unittest.TestCase): ], 'hidden_updates': [], } - template_name = "{0}/course_updates.html".format(info_module.TEMPLATE_DIR) + template_name = f"{info_module.TEMPLATE_DIR}/course_updates.html" info_module.get_html() # Assertion to validate that render function is called with the expected context info_module.system.render_template.assert_called_once_with( diff --git a/common/lib/xmodule/xmodule/tests/test_import.py b/common/lib/xmodule/xmodule/tests/test_import.py index 0626797b1a..f9f5cd548d 100644 --- a/common/lib/xmodule/xmodule/tests/test_import.py +++ b/common/lib/xmodule/xmodule/tests/test_import.py @@ -1,19 +1,17 @@ # lint-amnesty, pylint: disable=missing-module-docstring -# -*- coding: utf-8 -*- import datetime from tempfile import mkdtemp +from unittest.mock import Mock, patch import ddt from django.test import TestCase from fs.osfs import OSFS from lxml import etree -from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from pytz import UTC -from six import text_type from xblock.core import XBlock from xblock.fields import Integer, Scope, String from xblock.runtime import DictKeyValueStore, KvsFieldData @@ -44,7 +42,7 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho course_dir = "test_dir" error_tracker = Mock() - super(DummySystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( xmlstore=xmlstore, course_id=course_id, course_dir=course_dir, @@ -68,7 +66,7 @@ class BaseCourseTestCase(TestCase): def get_course(self, name): """Get a test course by directory name. If there's more than one, error.""" - print("Importing {0}".format(name)) + print(f"Importing {name}") modulestore = XMLModuleStore( DATA_DIR, @@ -126,7 +124,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi '''Check that malformed xml loads as an ErrorBlock.''' # Use an exotic character to also flush out Unicode issues. - bad_xml = u'''''' + bad_xml = '''''' system = self.get_system() descriptor = system.process_xml(bad_xml) @@ -208,7 +206,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi # Now export and check things file_system = OSFS(mkdtemp()) - descriptor.runtime.export_fs = file_system.makedir(u'course', recreate=True) + descriptor.runtime.export_fs = file_system.makedir('course', recreate=True) node = etree.Element('unknown') descriptor.add_xml_to_node(node) @@ -220,7 +218,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi assert node.attrib['org'] == ORG # Does the course still have unicorns? - with descriptor.runtime.export_fs.open(u'course/{course_run}.xml'.format(course_run=course_run)) as f: + with descriptor.runtime.export_fs.open(f'course/{course_run}.xml') as f: course_xml = etree.fromstring(f.read()) assert course_xml.attrib['unicorn'] == unicorn_color @@ -234,7 +232,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi # Does the chapter tag now have a due attribute? # hardcoded path to child - with descriptor.runtime.export_fs.open(u'chapter/ch.xml') as f: + with descriptor.runtime.export_fs.open('chapter/ch.xml') as f: chapter_xml = etree.fromstring(f.read()) assert chapter_xml.tag == 'chapter' assert 'due' not in chapter_xml.attrib @@ -426,11 +424,11 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi """] for xml_str in yes: - print("should be True for {0}".format(xml_str)) + print(f"should be True for {xml_str}") assert is_pointer_tag(etree.fromstring(xml_str)) for xml_str in no: - print("should be False for {0}".format(xml_str)) + print(f"should be False for {xml_str}") assert not is_pointer_tag(etree.fromstring(xml_str)) def test_metadata_inherit(self): @@ -441,7 +439,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi def check_for_key(key, node, value): "recursive check for presence of key" - print("Checking {0}".format(text_type(node.location))) + print("Checking {}".format(str(node.location))) assert getattr(node, key) == value for c in node.get_children(): check_for_key(key, c, value) @@ -561,7 +559,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi in modulestore.get_course_errors(course.id) ] - assert any((((expect in msg) or (expect in err)) for (msg, err) in errors)) + assert any(((expect in msg) or (expect in err)) for (msg, err) in errors) chapters = course.get_children() assert len(chapters) == 4 @@ -584,7 +582,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi for i in (2, 3): video = sections[i] # Name should be 'video_{hash}' - print("video {0} url_name: {1}".format(i, video.url_name)) + print(f"video {i} url_name: {video.url_name}") assert len(video.url_name) == (len('video_') + 12) def test_poll_and_conditional_import(self): @@ -608,7 +606,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi assert module.poll_answer == '' assert module.poll_answers == {} assert module.answers ==\ - [{'text': u'Yes', 'id': 'Yes'}, {'text': u'No', 'id': 'No'}, {'text': u"Don't know", 'id': 'Dont_know'}] + [{'text': 'Yes', 'id': 'Yes'}, {'text': 'No', 'id': 'No'}, {'text': "Don't know", 'id': 'Dont_know'}] def test_error_on_import(self): '''Check that when load_error_module is false, an exception is raised, rather than returning an ErrorBlock''' diff --git a/common/lib/xmodule/xmodule/tests/test_import_static.py b/common/lib/xmodule/xmodule/tests/test_import_static.py index aa65bdb760..b8d3e387c7 100644 --- a/common/lib/xmodule/xmodule/tests/test_import_static.py +++ b/common/lib/xmodule/xmodule/tests/test_import_static.py @@ -4,8 +4,8 @@ Tests that check that we ignore the appropriate files when importing courses. import unittest +from unittest.mock import Mock -from mock import Mock from opaque_keys.edx.locator import CourseLocator from xmodule.modulestore.tests.utils import ( @@ -26,7 +26,7 @@ class IgnoredFilesTestCase(unittest.TestCase): dict_list = [DOT_FILES_DICT, TILDA_FILES_DICT] def setUp(self): - super(IgnoredFilesTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() for dictionary in self.dict_list: self.addCleanup(remove_temp_files_from_list, list(dictionary.keys()), self.course_dir / "static") add_temp_files_from_dict(dictionary, self.course_dir / "static") diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index b4b7531060..8a287acf88 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -1,18 +1,14 @@ -# -*- coding: utf-8 -*- """ Basic unit tests for LibraryContentBlock Higher-level tests are in `cms/djangoapps/contentstore/tests/test_libraries.py`. """ +from unittest.mock import Mock, patch - -import six from bson.objectid import ObjectId from fs.memoryfs import MemoryFS from lxml import etree -from mock import Mock, patch from search.search_engine_base import SearchEngine -from six.moves import range from web_fragments.fragment import Fragment from xblock.runtime import Runtime as VanillaRuntime @@ -35,12 +31,12 @@ class LibraryContentTest(MixedSplitTestCase): Base class for tests of LibraryContentBlock (library_content_block.py) """ def setUp(self): - super(LibraryContentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.tools = LibraryToolsService(self.store, self.user_id) self.library = LibraryFactory.create(modulestore=self.store) self.lib_blocks = [ - self.make_block("html", self.library, data="Hello world from block {}".format(i)) + self.make_block("html", self.library, data=f"Hello world from block {i}") for i in range(1, 5) ] self.course = CourseFactory.create(modulestore=self.store) @@ -51,7 +47,7 @@ class LibraryContentTest(MixedSplitTestCase): "library_content", self.vertical, max_count=1, - source_library_id=six.text_type(self.library.location.library_key) + source_library_id=str(self.library.location.library_key) ) def _bind_course_module(self, module): @@ -138,7 +134,7 @@ class TestLibraryContentExportImport(LibraryContentTest): assert imported_lc_block.children == lc_block.children -class LibraryContentBlockTestMixin(object): +class LibraryContentBlockTestMixin: """ Basic unit tests for LibraryContentBlock """ @@ -222,7 +218,7 @@ class LibraryContentBlockTestMixin(object): assert 'invalid' in result.summary.text # When source_library_id is set but the block needs to be updated, the summary should say so: - self.lc_block.source_library_id = six.text_type(self.library.location.library_key) + self.lc_block.source_library_id = str(self.library.location.library_key) result = self.lc_block.validate() assert not result # Validation fails due to at least one warning/message @@ -385,7 +381,7 @@ class TestLibraryContentBlockWithSearchIndex(LibraryContentBlockTestMixin, Libra def setUp(self): """ Sets up search engine mock """ - super(TestLibraryContentBlockWithSearchIndex, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() search_index_mock.search = Mock(side_effect=self._get_search_response) @@ -427,7 +423,7 @@ class TestLibraryContentAnalytics(LibraryContentTest): """ def setUp(self): - super(TestLibraryContentAnalytics, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.publisher = Mock() self.lc_block.refresh_children() self.lc_block = self.store.get_item(self.lc_block.location) @@ -441,8 +437,8 @@ class TestLibraryContentAnalytics(LibraryContentTest): assert self.publisher.called assert len(self.publisher.call_args[0]) == 3 # pylint:disable=unsubscriptable-object _, event_name, event_data = self.publisher.call_args[0] # pylint:disable=unsubscriptable-object - assert event_name == 'edx.librarycontentblock.content.{}'.format(event_type) - assert event_data['location'] == six.text_type(self.lc_block.location) + assert event_name == f'edx.librarycontentblock.content.{event_type}' + assert event_data['location'] == str(self.lc_block.location) return event_data def test_assigned_event(self): @@ -455,13 +451,13 @@ class TestLibraryContentAnalytics(LibraryContentTest): assert isinstance(child_lib_version, ObjectId) event_data = self._assert_event_was_published("assigned") block_info = { - "usage_key": six.text_type(child.location), - "original_usage_key": six.text_type(child_lib_location), - "original_usage_version": six.text_type(child_lib_version), + "usage_key": str(child.location), + "original_usage_key": str(child_lib_location), + "original_usage_version": str(child_lib_version), "descendants": [], } assert event_data ==\ - {'location': six.text_type(self.lc_block.location), + {'location': str(self.lc_block.location), 'added': [block_info], 'result': [block_info], 'previous_count': 0, 'max_count': 1} @@ -473,7 +469,7 @@ class TestLibraryContentAnalytics(LibraryContentTest): assert len(children) == 2 child, new_child = children if children[0].location == child.location else reversed(children) event_data = self._assert_event_was_published("assigned") - assert event_data['added'][0]['usage_key'] == six.text_type(new_child.location) + assert event_data['added'][0]['usage_key'] == str(new_child.location) assert len(event_data['result']) == 2 assert event_data['previous_count'] == 1 assert event_data['max_count'] == 2 @@ -521,7 +517,7 @@ class TestLibraryContentAnalytics(LibraryContentTest): for block_list in (event_data["added"], event_data["result"]): assert len(block_list) == 1 # main_vertical is the only root block added, and is the only result. - assert block_list[0]['usage_key'] == six.text_type(course_usage_main_vertical) + assert block_list[0]['usage_key'] == str(course_usage_main_vertical) # Check that "descendants" is a flat, unordered list of all of main_vertical's descendants: descendants_expected = ( @@ -531,10 +527,10 @@ class TestLibraryContentAnalytics(LibraryContentTest): ) descendant_data_expected = {} for lib_key, course_usage_key in descendants_expected: - descendant_data_expected[six.text_type(course_usage_key)] = { - "usage_key": six.text_type(course_usage_key), - "original_usage_key": six.text_type(lib_key), - "original_usage_version": six.text_type(self.store.get_block_original_usage(course_usage_key)[1]), + descendant_data_expected[str(course_usage_key)] = { + "usage_key": str(course_usage_key), + "original_usage_key": str(lib_key), + "original_usage_version": str(self.store.get_block_original_usage(course_usage_key)[1]), } assert len(block_list[0]['descendants']) == len(descendant_data_expected) for descendant in block_list[0]["descendants"]: @@ -585,12 +581,12 @@ class TestLibraryContentAnalytics(LibraryContentTest): assert len(children) == 1 event_data = self._assert_event_was_published("removed") assert event_data['removed'] ==\ - [{'usage_key': six.text_type(deleted_block_key), + [{'usage_key': str(deleted_block_key), 'original_usage_key': None, 'original_usage_version': None, 'descendants': []}] assert event_data['result'] ==\ - [{'usage_key': six.text_type(keep_block_key), - 'original_usage_key': six.text_type(keep_block_lib_usage_key), - 'original_usage_version': six.text_type(keep_block_lib_version), 'descendants': []}] + [{'usage_key': str(keep_block_key), + 'original_usage_key': str(keep_block_lib_usage_key), + 'original_usage_version': str(keep_block_lib_version), 'descendants': []}] assert event_data['reason'] == 'invalid' diff --git a/common/lib/xmodule/xmodule/tests/test_library_root.py b/common/lib/xmodule/xmodule/tests/test_library_root.py index 152078ba2c..c1eaded51c 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_root.py +++ b/common/lib/xmodule/xmodule/tests/test_library_root.py @@ -1,11 +1,9 @@ -# -*- coding: utf-8 -*- """ Basic unit tests for LibraryRoot """ -from mock import patch -from six.moves import range +from unittest.mock import patch from web_fragments.fragment import Fragment from xblock.runtime import Runtime as VanillaRuntime @@ -34,7 +32,7 @@ class TestLibraryRoot(MixedSplitTestCase): We have to patch the runtime (module system) in order to be able to render blocks in our test environment. """ - message = u"Hello world" + message = "Hello world" library = LibraryFactory.create(modulestore=self.store) # Add one HTML block to the library: ItemFactory.create( diff --git a/common/lib/xmodule/xmodule/tests/test_library_sourced_block.py b/common/lib/xmodule/xmodule/tests/test_library_sourced_block.py index b60d637a03..246a6fa05a 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_sourced_block.py +++ b/common/lib/xmodule/xmodule/tests/test_library_sourced_block.py @@ -28,7 +28,7 @@ class LibrarySourcedBlockTestCase(ContentLibrariesRestApiTest): user_id=self.user.id, modulestore=self.store ) - self.submit_url = '/xblock/{0}/handler/submit_studio_edits'.format(self.source_block.scope_ids.usage_id) + self.submit_url = f'/xblock/{self.source_block.scope_ids.usage_id}/handler/submit_studio_edits' def test_block_views(self): # Create a blockstore content library @@ -52,7 +52,7 @@ class LibrarySourcedBlockTestCase(ContentLibrariesRestApiTest): # Create a blockstore content library library = self._create_library(slug="testlib2_preview", title="Test Library 2", description="Testing XBlocks") # Add content to the library - blocks = [self._add_block_to_library(library["id"], "html", "block_{0}".format(i))["id"] for i in range(11)] + blocks = [self._add_block_to_library(library["id"], "html", f"block_{i}")["id"] for i in range(11)] # Import the html blocks from the library to the course post_data = {"values": {"source_block_ids": blocks}, "defaults": ["display_name"]} diff --git a/common/lib/xmodule/xmodule/tests/test_lti20_unit.py b/common/lib/xmodule/xmodule/tests/test_lti20_unit.py index 426dc639ff..c1c43fd17f 100644 --- a/common/lib/xmodule/xmodule/tests/test_lti20_unit.py +++ b/common/lib/xmodule/xmodule/tests/test_lti20_unit.py @@ -1,12 +1,11 @@ -# -*- coding: utf-8 -*- """Tests for LTI Xmodule LTIv2.0 functional logic.""" import datetime import textwrap import unittest +from unittest.mock import Mock -from mock import Mock from pytz import UTC from xblock.field_data import DictFieldData @@ -20,7 +19,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): """Logic tests for LTI module. LTI2.0 REST ResultService""" def setUp(self): - super(LTI20RESTResultServiceTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.system = get_test_system() self.environ = {'wsgi.url_scheme': 'http', 'REQUEST_METHOD': 'POST'} self.system.get_real_user = Mock() @@ -43,9 +42,9 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.xmodule.lti_id = "lti_id" test_cases = ( # (before sanitize, after sanitize) - (u"plaintext", u"plaintext"), - (u"a ", u"a <script>alert(3)</script>"), # encodes scripts - (u"bold 包", u"bold 包"), # unicode, and tags pass through + ("plaintext", "plaintext"), + ("a ", "a <script>alert(3)</script>"), # encodes scripts + ("bold 包", "bold 包"), # unicode, and tags pass through ) for case in test_cases: self.xmodule.score_comment = case[0] @@ -56,7 +55,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): Input with bad content type """ with self.assertRaisesRegex(LTIError, "Content-Type must be"): - request = Mock(headers={u'Content-Type': u'Non-existent'}) + request = Mock(headers={'Content-Type': 'Non-existent'}) self.xmodule.verify_lti_2_0_result_rest_headers(request) def test_lti20_rest_failed_oauth_body_verify(self): @@ -66,7 +65,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): err_msg = "OAuth body verification failed" self.xmodule.verify_oauth_body_sign = Mock(side_effect=LTIError(err_msg)) with self.assertRaisesRegex(LTIError, err_msg): - request = Mock(headers={u'Content-Type': u'application/vnd.ims.lis.v2.result+json'}) + request = Mock(headers={'Content-Type': 'application/vnd.ims.lis.v2.result+json'}) self.xmodule.verify_lti_2_0_result_rest_headers(request) def test_lti20_rest_good_headers(self): @@ -75,21 +74,21 @@ class LTI20RESTResultServiceTest(unittest.TestCase): """ self.xmodule.verify_oauth_body_sign = Mock(return_value=True) - request = Mock(headers={u'Content-Type': u'application/vnd.ims.lis.v2.result+json'}) + request = Mock(headers={'Content-Type': 'application/vnd.ims.lis.v2.result+json'}) self.xmodule.verify_lti_2_0_result_rest_headers(request) # We just want the above call to complete without exceptions, and to have called verify_oauth_body_sign assert self.xmodule.verify_oauth_body_sign.called BAD_DISPATCH_INPUTS = [ None, - u"", - u"abcd" - u"notuser/abcd" - u"user/" - u"user//" - u"user/gbere/" - u"user/gbere/xsdf" - u"user/ಠ益ಠ" # not alphanumeric + "", + "abcd" + "notuser/abcd" + "user/" + "user//" + "user/gbere/" + "user/gbere/xsdf" + "user/ಠ益ಠ" # not alphanumeric ] def test_lti20_rest_bad_dispatch(self): @@ -102,8 +101,8 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.xmodule.parse_lti_2_0_handler_suffix(einput) GOOD_DISPATCH_INPUTS = [ - (u"user/abcd3", u"abcd3"), - (u"user/Äbcdè2", u"Äbcdè2"), # unicode, just to make sure + ("user/abcd3", "abcd3"), + ("user/Äbcdè2", "Äbcdè2"), # unicode, just to make sure ] def test_lti20_rest_good_dispatch(self): @@ -117,40 +116,40 @@ class LTI20RESTResultServiceTest(unittest.TestCase): BAD_JSON_INPUTS = [ # (bad inputs, error message expected) ([ - u"kk", # ValueError - u"{{}", # ValueError - u"{}}", # ValueError + "kk", # ValueError + "{{}", # ValueError + "{}}", # ValueError 3, # TypeError {}, # TypeError - ], u"Supplied JSON string in request body could not be decoded"), + ], "Supplied JSON string in request body could not be decoded"), ([ - u"3", # valid json, not array or object - u"[]", # valid json, array too small - u"[3, {}]", # valid json, 1st element not an object - ], u"Supplied JSON string is a list that does not contain an object as the first element"), + "3", # valid json, not array or object + "[]", # valid json, array too small + "[3, {}]", # valid json, 1st element not an object + ], "Supplied JSON string is a list that does not contain an object as the first element"), ([ - u'{"@type": "NOTResult"}', # @type key must have value 'Result' - ], u"JSON object does not contain correct @type attribute"), + '{"@type": "NOTResult"}', # @type key must have value 'Result' + ], "JSON object does not contain correct @type attribute"), ([ # @context missing - u'{"@type": "Result", "resultScore": 0.1}', - ], u"JSON object does not contain required key"), + '{"@type": "Result", "resultScore": 0.1}', + ], "JSON object does not contain required key"), ([ - u''' + ''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "resultScore": 100}''' # score out of range - ], u"score value outside the permitted range of 0-1."), + ], "score value outside the permitted range of 0-1."), ([ - u''' + ''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "resultScore": "1b"}''', # score ValueError - u''' + ''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "resultScore": {}}''', # score TypeError - ], u"Could not convert resultScore to float"), + ], "Could not convert resultScore to float"), ] def test_lti20_bad_json(self): @@ -163,20 +162,20 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.xmodule.parse_lti_2_0_result_json(einput) GOOD_JSON_INPUTS = [ - (u''' + (''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", - "resultScore": 0.1}''', u""), # no comment means we expect "" - (u''' + "resultScore": 0.1}''', ""), # no comment means we expect "" + (''' [{"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "@id": "anon_id:abcdef0123456789", - "resultScore": 0.1}]''', u""), # OK to have array of objects -- just take the first. @id is okay too - (u''' + "resultScore": 0.1}]''', ""), # OK to have array of objects -- just take the first. @id is okay too + (''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "resultScore": 0.1, - "comment": "ಠ益ಠ"}''', u"ಠ益ಠ"), # unicode comment + "comment": "ಠ益ಠ"}''', "ಠ益ಠ"), # unicode comment ] def test_lti20_good_json(self): @@ -188,7 +187,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): assert score == 0.1 assert comment == expected_comment - GOOD_JSON_PUT = textwrap.dedent(u""" + GOOD_JSON_PUT = textwrap.dedent(""" {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "@id": "anon_id:abcdef0123456789", @@ -196,14 +195,14 @@ class LTI20RESTResultServiceTest(unittest.TestCase): "comment": "ಠ益ಠ"} """).encode('utf-8') - GOOD_JSON_PUT_LIKE_DELETE = textwrap.dedent(u""" + GOOD_JSON_PUT_LIKE_DELETE = textwrap.dedent(""" {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "@id": "anon_id:abcdef0123456789", "comment": "ಠ益ಠ"} """).encode('utf-8') - def get_signed_lti20_mock_request(self, body, method=u'PUT'): + def get_signed_lti20_mock_request(self, body, method='PUT'): """ Example of signed from LTI 2.0 Provider. Signatures and hashes are example only and won't verify """ @@ -211,15 +210,15 @@ class LTI20RESTResultServiceTest(unittest.TestCase): mock_request.headers = { 'Content-Type': 'application/vnd.ims.lis.v2.result+json', 'Authorization': ( - u'OAuth oauth_nonce="135685044251684026041377608307", ' - u'oauth_timestamp="1234567890", oauth_version="1.0", ' - u'oauth_signature_method="HMAC-SHA1", ' - u'oauth_consumer_key="test_client_key", ' - u'oauth_signature="my_signature%3D", ' - u'oauth_body_hash="gz+PeJZuF2//n9hNUnDj2v5kN70="' + 'OAuth oauth_nonce="135685044251684026041377608307", ' + 'oauth_timestamp="1234567890", oauth_version="1.0", ' + 'oauth_signature_method="HMAC-SHA1", ' + 'oauth_consumer_key="test_client_key", ' + 'oauth_signature="my_signature%3D", ' + 'oauth_body_hash="gz+PeJZuF2//n9hNUnDj2v5kN70="' ) } - mock_request.url = u'http://testurl' + mock_request.url = 'http://testurl' mock_request.http_method = method mock_request.method = method mock_request.body = body @@ -234,7 +233,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): """ self.system.get_real_user = Mock(return_value=self.USER_STANDIN) self.xmodule.max_score = Mock(return_value=1.0) - self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', u'test_client_secret')) + self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret')) self.xmodule.verify_oauth_body_sign = Mock() def test_lti20_put_like_delete_success(self): @@ -243,16 +242,16 @@ class LTI20RESTResultServiceTest(unittest.TestCase): """ self.setup_system_xmodule_mocks_for_lti20_request_test() SCORE = 0.55 # pylint: disable=invalid-name - COMMENT = u"ಠ益ಠ" # pylint: disable=invalid-name + COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name self.xmodule.module_score = SCORE self.xmodule.score_comment = COMMENT mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT_LIKE_DELETE) # Now call the handler - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") # Now assert there's no score assert response.status_code == 200 assert self.xmodule.module_score is None - assert self.xmodule.score_comment == u'' + assert self.xmodule.score_comment == '' (_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence assert called_grade_obj ==\ {'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True} @@ -264,16 +263,16 @@ class LTI20RESTResultServiceTest(unittest.TestCase): """ self.setup_system_xmodule_mocks_for_lti20_request_test() SCORE = 0.55 # pylint: disable=invalid-name - COMMENT = u"ಠ益ಠ" # pylint: disable=invalid-name + COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name self.xmodule.module_score = SCORE self.xmodule.score_comment = COMMENT - mock_request = self.get_signed_lti20_mock_request(b"", method=u'DELETE') + mock_request = self.get_signed_lti20_mock_request(b"", method='DELETE') # Now call the handler - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") # Now assert there's no score assert response.status_code == 200 assert self.xmodule.module_score is None - assert self.xmodule.score_comment == u'' + assert self.xmodule.score_comment == '' (_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence assert called_grade_obj ==\ {'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True} @@ -286,11 +285,11 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.setup_system_xmodule_mocks_for_lti20_request_test() mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) # Now call the handler - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") # Now assert assert response.status_code == 200 assert self.xmodule.module_score == 0.1 - assert self.xmodule.score_comment == u'ಠ益ಠ' + assert self.xmodule.score_comment == 'ಠ益ಠ' (_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence assert evt_type == 'grade' assert called_grade_obj ==\ @@ -301,9 +300,9 @@ class LTI20RESTResultServiceTest(unittest.TestCase): The happy path for LTI 2.0 GET when there's no score """ self.setup_system_xmodule_mocks_for_lti20_request_test() - mock_request = self.get_signed_lti20_mock_request(b"", method=u'GET') + mock_request = self.get_signed_lti20_mock_request(b"", method='GET') # Now call the handler - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") # Now assert assert response.status_code == 200 assert response.json == {'@context': 'http://purl.imsglobal.org/ctx/lis/v2/Result', '@type': 'Result'} @@ -314,12 +313,12 @@ class LTI20RESTResultServiceTest(unittest.TestCase): """ self.setup_system_xmodule_mocks_for_lti20_request_test() SCORE = 0.55 # pylint: disable=invalid-name - COMMENT = u"ಠ益ಠ" # pylint: disable=invalid-name + COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name self.xmodule.module_score = SCORE self.xmodule.score_comment = COMMENT - mock_request = self.get_signed_lti20_mock_request(b"", method=u'GET') + mock_request = self.get_signed_lti20_mock_request(b"", method='GET') # Now call the handler - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") # Now assert assert response.status_code == 200 assert response.json ==\ @@ -336,7 +335,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) for bad_method in self.UNSUPPORTED_HTTP_METHODS: mock_request.method = bad_method - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") assert response.status_code == 404 def test_lti20_request_handler_bad_headers(self): @@ -346,7 +345,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.setup_system_xmodule_mocks_for_lti20_request_test() self.xmodule.verify_lti_2_0_result_rest_headers = Mock(side_effect=LTIError()) mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") assert response.status_code == 401 def test_lti20_request_handler_bad_dispatch_user(self): @@ -365,7 +364,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.setup_system_xmodule_mocks_for_lti20_request_test() self.xmodule.parse_lti_2_0_result_json = Mock(side_effect=LTIError()) mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") assert response.status_code == 404 def test_lti20_request_handler_bad_user(self): @@ -375,7 +374,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.setup_system_xmodule_mocks_for_lti20_request_test() self.system.get_real_user = Mock(return_value=None) mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") assert response.status_code == 404 def test_lti20_request_handler_grade_past_due(self): @@ -386,5 +385,5 @@ class LTI20RESTResultServiceTest(unittest.TestCase): self.xmodule.due = datetime.datetime.now(UTC) self.xmodule.accept_grades_past_due = False mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) - response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd") + response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") assert response.status_code == 404 diff --git a/common/lib/xmodule/xmodule/tests/test_lti_unit.py b/common/lib/xmodule/xmodule/tests/test_lti_unit.py index f240245d23..53d173bf3d 100644 --- a/common/lib/xmodule/xmodule/tests/test_lti_unit.py +++ b/common/lib/xmodule/xmodule/tests/test_lti_unit.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Test for LTI Xmodule functional logic.""" @@ -6,14 +5,13 @@ import datetime import textwrap import unittest from copy import copy +from unittest.mock import Mock, PropertyMock, patch +from urllib import parse import pytest -import six from lxml import etree -from mock import Mock, PropertyMock, patch from opaque_keys.edx.locator import BlockUsageLocator from pytz import UTC -from six import text_type from webob.request import Request from xblock.field_data import DictFieldData from xblock.fields import ScopeIds @@ -31,7 +29,7 @@ class LTIBlockTest(unittest.TestCase): def setUp(self): super().setUp() self.environ = {'wsgi.url_scheme': 'http', 'REQUEST_METHOD': 'POST'} - self.request_body_xml_template = textwrap.dedent(u""" + self.request_body_xml_template = textwrap.dedent(""" @@ -69,11 +67,11 @@ class LTIBlockTest(unittest.TestCase): ScopeIds(None, None, None, BlockUsageLocator(self.system.course_id, 'lti', 'name')) ) self.lti_id = self.xmodule.lti_id - self.unquoted_resource_link_id = u'{}-i4x-2-3-lti-31de800015cf4afb973356dbe81496df'.format( + self.unquoted_resource_link_id = '{}-i4x-2-3-lti-31de800015cf4afb973356dbe81496df'.format( self.xmodule.runtime.hostname ) - sourced_id = u':'.join(six.moves.urllib.parse.quote(i) for i in (self.lti_id, self.unquoted_resource_link_id, self.user_id)) # lint-amnesty, pylint: disable=line-too-long + sourced_id = ':'.join(parse.quote(i) for i in (self.lti_id, self.unquoted_resource_link_id, self.user_id)) # lint-amnesty, pylint: disable=line-too-long self.defaults = { 'namespace': "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0", @@ -121,7 +119,7 @@ class LTIBlockTest(unittest.TestCase): @patch( 'xmodule.lti_module.LTIBlock.get_client_key_secret', - return_value=('test_client_key', u'test_client_secret') + return_value=('test_client_key', 'test_client_secret') ) def test_authorization_header_not_present(self, _get_key_secret): """ @@ -145,7 +143,7 @@ class LTIBlockTest(unittest.TestCase): @patch( 'xmodule.lti_module.LTIBlock.get_client_key_secret', - return_value=('test_client_key', u'test_client_secret') + return_value=('test_client_key', 'test_client_secret') ) def test_authorization_header_empty(self, _get_key_secret): """ @@ -234,14 +232,11 @@ class LTIBlockTest(unittest.TestCase): request.body = self.get_request_body(params={'grade': '0,5'}) response = self.xmodule.grade_handler(request, '') real_response = self.get_response_values(response) - if six.PY2: - msg = u'invalid literal for float(): 0,5' - else: - msg = u"could not convert string to float: '0,5'" + msg = "could not convert string to float: '0,5'" expected_response = { 'action': None, 'code_major': 'failure', - 'description': u'Request body XML parsing error: {}'.format(msg), + 'description': f'Request body XML parsing error: {msg}', 'messageIdentifier': 'unknown', } assert response.status_code == 200 @@ -292,7 +287,7 @@ class LTIBlockTest(unittest.TestCase): assert self.xmodule.module_score == float(self.defaults['grade']) def test_user_id(self): - expected_user_id = text_type(six.moves.urllib.parse.quote(self.xmodule.runtime.anonymous_student_id)) + expected_user_id = str(parse.quote(self.xmodule.runtime.anonymous_student_id)) real_user_id = self.xmodule.get_user_id() assert real_user_id == expected_user_id @@ -311,13 +306,13 @@ class LTIBlockTest(unittest.TestCase): def test_resource_link_id(self): with patch('xmodule.lti_module.LTIBlock.location', new_callable=PropertyMock): self.xmodule.location.html_id = lambda: 'i4x-2-3-lti-31de800015cf4afb973356dbe81496df' - expected_resource_link_id = text_type(six.moves.urllib.parse.quote(self.unquoted_resource_link_id)) + expected_resource_link_id = str(parse.quote(self.unquoted_resource_link_id)) real_resource_link_id = self.xmodule.get_resource_link_id() assert real_resource_link_id == expected_resource_link_id def test_lis_result_sourcedid(self): - expected_sourced_id = u':'.join(six.moves.urllib.parse.quote(i) for i in ( - text_type(self.system.course_id), + expected_sourced_id = ':'.join(parse.quote(i) for i in ( + str(self.system.course_id), self.xmodule.get_resource_link_id(), self.user_id )) @@ -377,7 +372,7 @@ class LTIBlockTest(unittest.TestCase): @patch('xmodule.lti_module.signature.verify_hmac_sha1', Mock(return_value=True)) @patch( 'xmodule.lti_module.LTIBlock.get_client_key_secret', - Mock(return_value=('test_client_key', u'test_client_secret')) + Mock(return_value=('test_client_key', 'test_client_secret')) ) def test_successful_verify_oauth_body_sign(self): """ @@ -385,9 +380,9 @@ class LTIBlockTest(unittest.TestCase): """ self.xmodule.verify_oauth_body_sign(self.get_signed_grade_mock_request()) - @patch('xmodule.lti_module.LTIBlock.get_outcome_service_url', Mock(return_value=u'https://testurl/')) + @patch('xmodule.lti_module.LTIBlock.get_outcome_service_url', Mock(return_value='https://testurl/')) @patch('xmodule.lti_module.LTIBlock.get_client_key_secret', - Mock(return_value=(u'__consumer_key__', u'__lti_secret__'))) + Mock(return_value=('__consumer_key__', '__lti_secret__'))) def test_failed_verify_oauth_body_sign_proxy_mangle_url(self): """ Oauth signing verify fail. @@ -406,30 +401,30 @@ class LTIBlockTest(unittest.TestCase): """ mock_request = Mock() mock_request.headers = { - u'X-Requested-With': u'XMLHttpRequest', - u'Content-Type': u'application/x-www-form-urlencoded', - u'Authorization': ( - u'OAuth realm="https://testurl/", oauth_body_hash="wwzA3s8gScKD1VpJ7jMt9b%2BMj9Q%3D",' - u'oauth_nonce="18821463", oauth_timestamp="1409321145", ' - u'oauth_consumer_key="__consumer_key__", oauth_signature_method="HMAC-SHA1", ' - u'oauth_version="1.0", oauth_signature="fHsE1hhIz76/msUoMR3Lyb7Aou4%3D"' + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': ( + 'OAuth realm="https://testurl/", oauth_body_hash="wwzA3s8gScKD1VpJ7jMt9b%2BMj9Q%3D",' + 'oauth_nonce="18821463", oauth_timestamp="1409321145", ' + 'oauth_consumer_key="__consumer_key__", oauth_signature_method="HMAC-SHA1", ' + 'oauth_version="1.0", oauth_signature="fHsE1hhIz76/msUoMR3Lyb7Aou4%3D"' ) } - mock_request.url = u'https://testurl' - mock_request.http_method = u'POST' + mock_request.url = 'https://testurl' + mock_request.http_method = 'POST' mock_request.method = mock_request.http_method mock_request.body = ( - u'\n' - u'' - u'V1.0' - u'edX_fix' - u'' - u'MITxLTI/MITxLTI/201x:localhost%3A8000-i4x-MITxLTI-MITxLTI-lti-3751833a214a4f66a0d18f63234207f2' - u':363979ef768ca171b50f9d1bfb322131' - u'en0.32' - u'' - ).encode('utf-8') + b'\n' + b'' + b'V1.0' + b'edX_fix' + b'' + b'MITxLTI/MITxLTI/201x:localhost%3A8000-i4x-MITxLTI-MITxLTI-lti-3751833a214a4f66a0d18f63234207f2' + b':363979ef768ca171b50f9d1bfb322131' + b'en0.32' + b'' + ) return mock_request @@ -459,7 +454,7 @@ class LTIBlockTest(unittest.TestCase): @patch('xmodule.lti_module.signature.verify_hmac_sha1', Mock(return_value=False)) @patch( 'xmodule.lti_module.LTIBlock.get_client_key_secret', - Mock(return_value=('test_client_key', u'test_client_secret')) + Mock(return_value=('test_client_key', 'test_client_secret')) ) def test_failed_verify_oauth_body_sign(self): """ @@ -480,15 +475,15 @@ class LTIBlockTest(unittest.TestCase): mock_request.headers = { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded', - 'Authorization': u'OAuth oauth_nonce="135685044251684026041377608307", \ + 'Authorization': 'OAuth oauth_nonce="135685044251684026041377608307", \ oauth_timestamp="1234567890", oauth_version="1.0", \ oauth_signature_method="HMAC-SHA1", \ oauth_consumer_key="test_client_key", \ oauth_signature="my_signature%3D", \ oauth_body_hash="JEpIArlNCeV4ceXxric8gJQCnBw="' } - mock_request.url = u'http://testurl' - mock_request.http_method = u'POST' + mock_request.url = 'http://testurl' + mock_request.http_method = 'POST' params = {} if not namespace_lti_v1p1: @@ -508,7 +503,7 @@ class LTIBlockTest(unittest.TestCase): self.xmodule.oauth_params = Mock() self.xmodule.get_input_fields() self.xmodule.oauth_params.assert_called_with( - {u'custom_test_custom_params': u'test_custom_param_value'}, + {'custom_test_custom_params': 'test_custom_param_value'}, 'test_client_key', 'test_client_secret' ) @@ -537,4 +532,4 @@ class LTIBlockTest(unittest.TestCase): """ Tests that LTI parameter context_id is equal to course_id. """ - assert text_type(self.system.course_id) == self.xmodule.context_id + assert str(self.system.course_id) == self.xmodule.context_id diff --git a/common/lib/xmodule/xmodule/tests/test_mako_module.py b/common/lib/xmodule/xmodule/tests/test_mako_module.py index bf52c42f80..cbfb642290 100644 --- a/common/lib/xmodule/xmodule/tests/test_mako_module.py +++ b/common/lib/xmodule/xmodule/tests/test_mako_module.py @@ -2,8 +2,9 @@ from unittest import TestCase +from unittest.mock import Mock + import pytest -from mock import Mock from xmodule.mako_module import MakoModuleDescriptor diff --git a/common/lib/xmodule/xmodule/tests/test_poll.py b/common/lib/xmodule/xmodule/tests/test_poll.py index 631e8335e4..b7a58bda94 100644 --- a/common/lib/xmodule/xmodule/tests/test_poll.py +++ b/common/lib/xmodule/xmodule/tests/test_poll.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- """Test for Poll Xmodule functional logic.""" import json import unittest -from mock import Mock +from unittest.mock import Mock from xblock.field_data import DictFieldData from xblock.fields import ScopeIds diff --git a/common/lib/xmodule/xmodule/tests/test_progress.py b/common/lib/xmodule/xmodule/tests/test_progress.py index bd5dc2ac35..0b77510dfa 100644 --- a/common/lib/xmodule/xmodule/tests/test_progress.py +++ b/common/lib/xmodule/xmodule/tests/test_progress.py @@ -2,8 +2,8 @@ import unittest +from unittest.mock import Mock -from mock import Mock from xblock.field_data import DictFieldData from xmodule import x_module diff --git a/common/lib/xmodule/xmodule/tests/test_randomize_module.py b/common/lib/xmodule/xmodule/tests/test_randomize_module.py index 3fc980cfd4..e86209b8db 100644 --- a/common/lib/xmodule/xmodule/tests/test_randomize_module.py +++ b/common/lib/xmodule/xmodule/tests/test_randomize_module.py @@ -1,10 +1,10 @@ """ Test cases covering workflows and behaviors for the Randomize XModule """ +from unittest.mock import Mock from fs.memoryfs import MemoryFS from lxml import etree -from mock import Mock from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase @@ -33,7 +33,7 @@ class RandomizeBlockTest(MixedSplitTestCase): display_name="Hello Randomize", ) self.child_blocks = [ - self.make_block("html", self.randomize_block, display_name="Hello HTML {}".format(i)) + self.make_block("html", self.randomize_block, display_name=f"Hello HTML {i}") for i in range(1, 4) ] diff --git a/common/lib/xmodule/xmodule/tests/test_resource_templates.py b/common/lib/xmodule/xmodule/tests/test_resource_templates.py index 1e3702348f..e51f69ed30 100644 --- a/common/lib/xmodule/xmodule/tests/test_resource_templates.py +++ b/common/lib/xmodule/xmodule/tests/test_resource_templates.py @@ -14,12 +14,12 @@ class ResourceTemplatesTests(unittest.TestCase): """ def test_templates(self): - expected = set([ + expected = { 'latex_html.yaml', 'zooming_image.yaml', 'announcement.yaml', - 'anon_user_id.yaml']) - got = set((t['template_id'] for t in TestClass.templates())) + 'anon_user_id.yaml'} + got = {t['template_id'] for t in TestClass.templates()} assert expected == got def test_templates_no_suchdir(self): diff --git a/common/lib/xmodule/xmodule/tests/test_sequence.py b/common/lib/xmodule/xmodule/tests/test_sequence.py index 347aea79c9..20c2b4eca1 100644 --- a/common/lib/xmodule/xmodule/tests/test_sequence.py +++ b/common/lib/xmodule/xmodule/tests/test_sequence.py @@ -7,14 +7,12 @@ Tests for sequence module. import ast import json from datetime import datetime, timedelta +from unittest.mock import Mock, patch import ddt -import six from django.test.utils import override_settings from django.utils.timezone import now from freezegun import freeze_time -from mock import Mock, patch -from six.moves import range from web_fragments.fragment import Fragment from edx_toggles.toggles.testutils import override_waffle_flag @@ -136,7 +134,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest): """ Verifies that the rendered view contains the expected position. """ - assert "'position': {}".format(expected_position) in rendered_html + assert f"'position': {expected_position}" in rendered_html def test_student_view_init(self): module_system = get_test_system() @@ -158,7 +156,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest): view=view ) self._assert_view_at_position(html, expected_position=1) - assert six.text_type(self.sequence_3_1.location) in html + assert str(self.sequence_3_1.location) in html assert "'gated': False" in html assert "'next_url': 'NextSequential'" in html assert "'prev_url': 'PrevSequential'" in html @@ -236,7 +234,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest): def test_tooltip(self): html = self._get_rendered_view(self.sequence_3_1, requested_child=None) for child in self.sequence_3_1.children: - assert "'page_title': '{}'".format(child.block_id) in html + assert f"'page_title': '{child.block_id}'" in html def test_hidden_content_before_due(self): html = self._get_rendered_view(self.sequence_4_1) @@ -291,7 +289,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest): assert html['gated_content']['gated'] assert 'PrereqUrl' == html['gated_content']['prereq_url'] assert 'PrereqSectionName' == html['gated_content']['prereq_section_name'] - assert six.text_type(sequence.display_name) in html['gated_content']['gated_section_name'] + assert str(sequence.display_name) in html['gated_content']['gated_section_name'] assert 'NextSequential' == html['next_url'] assert 'PrevSequential' == html['prev_url'] @@ -303,7 +301,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest): html = self.get_context_dict_from_string(html) assert 'This section is a prerequisite. You must complete this section in order to unlock additional content.' == html['banner_text'] assert not html['gated_content']['gated'] - assert six.text_type(sequence.location) == html['item_id'] + assert str(sequence.location) == html['item_id'] assert html['gated_content']['prereq_url'] is None assert html['gated_content']['prereq_section_name'] is None assert 'NextSequential' == html['next_url'] @@ -316,7 +314,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest): assert 'seq_module.html' in html assert "'banner_text': None" in html assert "'gated': False" in html - assert six.text_type(sequence.location) in html + assert str(sequence.location) in html assert "'prereq_url': None" in html assert "'prereq_section_name': None" in html assert "'next_url': 'NextSequential'" in html @@ -377,7 +375,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest): targeted vertical through ajax call """ for child in self.sequence_3_1.get_children(): - usage_key = six.text_type(child.location) + usage_key = str(child.location) completion_return = json.loads(self.sequence_3_1.handle_ajax( 'get_completion', {'usage_key': usage_key} diff --git a/common/lib/xmodule/xmodule/tests/test_services.py b/common/lib/xmodule/xmodule/tests/test_services.py index 38fa619255..c5b5373774 100644 --- a/common/lib/xmodule/xmodule/tests/test_services.py +++ b/common/lib/xmodule/xmodule/tests/test_services.py @@ -1,14 +1,12 @@ """ Tests for SettingsService """ - - import unittest +from unittest import mock + import pytest from django.test import TestCase - import ddt -import mock from config_models.models import ConfigurationModel from django.conf import settings @@ -20,7 +18,7 @@ from xmodule.services import ConfigurationService, SettingsService, TeamsConfigu from openedx.core.lib.teams_config import TeamsConfig -class _DummyBlock(object): +class _DummyBlock: """ Dummy Xblock class """ pass # lint-amnesty, pylint: disable=unnecessary-pass @@ -33,7 +31,7 @@ class DummyConfig(ConfigurationModel): app_label = 'xmoduletestservices' -class DummyUnexpected(object): +class DummyUnexpected: """ Dummy Unexpected Class """ @@ -49,7 +47,7 @@ class TestSettingsService(unittest.TestCase): def setUp(self): """ Setting up tests """ - super(TestSettingsService, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.settings_service = SettingsService() self.xblock_mock = mock.Mock() self.xblock_mock.block_settings_key = self.xblock_setting_key1 @@ -128,7 +126,7 @@ class MockConfigurationService(TeamsConfigurationService): Mock ConfigurationService for testing. """ def __init__(self, course, **kwargs): # lint-amnesty, pylint: disable=unused-argument - super(MockConfigurationService, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() self._course = course def get_course(self, course_id): @@ -141,7 +139,7 @@ class ConfigurationServiceBaseClass(TestCase): """ def setUp(self): - super(ConfigurationServiceBaseClass, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.teams_config = TeamsConfig( {'max_size': 2, 'topics': [{'id': 'topic', 'name': 'Topic', 'description': 'A Topic'}]} diff --git a/common/lib/xmodule/xmodule/tests/test_split_test_module.py b/common/lib/xmodule/xmodule/tests/test_split_test_module.py index abfbfac0a7..9ae349f4fb 100644 --- a/common/lib/xmodule/xmodule/tests/test_split_test_module.py +++ b/common/lib/xmodule/xmodule/tests/test_split_test_module.py @@ -2,12 +2,11 @@ Tests for the Split Testing Module """ import json +from unittest.mock import Mock, patch import ddt import lxml -import six from fs.memoryfs import MemoryFS -from mock import Mock, patch from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.utils import MixedSplitTestCase @@ -97,8 +96,8 @@ class SplitTestBlockTest(XModuleXmlImportTest, PartitionTestCase): UserPartition( MINIMUM_STATIC_PARTITION_ID, 'second_partition', 'Second Partition', [ - Group(six.text_type(MINIMUM_STATIC_PARTITION_ID + 1), 'abel'), - Group(six.text_type(MINIMUM_STATIC_PARTITION_ID + 2), 'baker'), Group("103", 'charlie') + Group(str(MINIMUM_STATIC_PARTITION_ID + 1), 'abel'), + Group(str(MINIMUM_STATIC_PARTITION_ID + 2), 'baker'), Group("103", 'charlie') ], MockUserPartitionScheme() ) @@ -403,10 +402,10 @@ class SplitTestBlockStudioTest(SplitTestBlockTest): assert len(validation.messages) == 0 verify_validation_message( validation.summary, - u"The experiment is not associated with a group configuration.", + "The experiment is not associated with a group configuration.", StudioValidationMessage.NOT_CONFIGURED, 'edit-button', - u"Select a Group Configuration", + "Select a Group Configuration", ) # Verify the messages for a correctly configured split_test @@ -427,14 +426,14 @@ class SplitTestBlockStudioTest(SplitTestBlockTest): assert len(validation.messages) == 1 verify_validation_message( validation.messages[0], - u"The experiment does not contain all of the groups in the configuration.", + "The experiment does not contain all of the groups in the configuration.", StudioValidationMessage.ERROR, expected_action_runtime_event='add-missing-groups', - expected_action_label=u"Add Missing Groups" + expected_action_label="Add Missing Groups" ) verify_summary_message( validation.summary, - u"This content experiment has issues that affect content visibility.", + "This content experiment has issues that affect content visibility.", StudioValidationMessage.ERROR ) # Verify the messages for a split test with children that are not associated with any group @@ -446,12 +445,12 @@ class SplitTestBlockStudioTest(SplitTestBlockTest): assert len(validation.messages) == 1 verify_validation_message( validation.messages[0], - u"The experiment has an inactive group. Move content into active groups, then delete the inactive group.", + "The experiment has an inactive group. Move content into active groups, then delete the inactive group.", StudioValidationMessage.WARNING ) verify_summary_message( validation.summary, - u"This content experiment has issues that affect content visibility.", + "This content experiment has issues that affect content visibility.", StudioValidationMessage.WARNING ) # Verify the messages for a split test with both missing and inactive children @@ -463,20 +462,20 @@ class SplitTestBlockStudioTest(SplitTestBlockTest): assert len(validation.messages) == 2 verify_validation_message( validation.messages[0], - u"The experiment does not contain all of the groups in the configuration.", + "The experiment does not contain all of the groups in the configuration.", StudioValidationMessage.ERROR, expected_action_runtime_event='add-missing-groups', - expected_action_label=u"Add Missing Groups" + expected_action_label="Add Missing Groups" ) verify_validation_message( validation.messages[1], - u"The experiment has an inactive group. Move content into active groups, then delete the inactive group.", + "The experiment has an inactive group. Move content into active groups, then delete the inactive group.", StudioValidationMessage.WARNING ) # With two messages of type error and warning priority given to error. verify_summary_message( validation.summary, - u"This content experiment has issues that affect content visibility.", + "This content experiment has issues that affect content visibility.", StudioValidationMessage.ERROR ) @@ -486,13 +485,13 @@ class SplitTestBlockStudioTest(SplitTestBlockTest): assert len(validation.messages) == 1 verify_validation_message( validation.messages[0], - u"The experiment uses a deleted group configuration. " - u"Select a valid group configuration or delete this experiment.", + "The experiment uses a deleted group configuration. " + "Select a valid group configuration or delete this experiment.", StudioValidationMessage.ERROR ) verify_summary_message( validation.summary, - u"This content experiment has issues that affect content visibility.", + "This content experiment has issues that affect content visibility.", StudioValidationMessage.ERROR ) @@ -508,13 +507,13 @@ class SplitTestBlockStudioTest(SplitTestBlockTest): assert len(validation.messages) == 1 verify_validation_message( validation.messages[0], - u"The experiment uses a group configuration that is not supported for experiments. " - u"Select a valid group configuration or delete this experiment.", + "The experiment uses a group configuration that is not supported for experiments. " + "Select a valid group configuration or delete this experiment.", StudioValidationMessage.ERROR ) verify_summary_message( validation.summary, - u"This content experiment has issues that affect content visibility.", + "This content experiment has issues that affect content visibility.", StudioValidationMessage.ERROR ) @@ -539,7 +538,7 @@ class SplitTestBlockExportImportTest(MixedSplitTestCase): user_partition_id=2, ) self.child_blocks = [ - self.make_block("html", self.split_test_block, display_name="Hello HTML {}".format(i)) + self.make_block("html", self.split_test_block, display_name=f"Hello HTML {i}") for i in range(1, 3) ] self.split_test_block.group_id_to_child = { diff --git a/common/lib/xmodule/xmodule/tests/test_stringify.py b/common/lib/xmodule/xmodule/tests/test_stringify.py index 54a39a5fd4..a70453ce2b 100644 --- a/common/lib/xmodule/xmodule/tests/test_stringify.py +++ b/common/lib/xmodule/xmodule/tests/test_stringify.py @@ -10,7 +10,7 @@ from xmodule.stringify import stringify_children def test_stringify(): text = 'Hi
there Bruce!
' - html = '''{0}'''.format(text) + html = f'''{text}''' xml = etree.fromstring(html) out = stringify_children(xml) assert out == text diff --git a/common/lib/xmodule/xmodule/tests/test_unit_block.py b/common/lib/xmodule/xmodule/tests/test_unit_block.py index 2f71bf6d34..b330cd79e3 100644 --- a/common/lib/xmodule/xmodule/tests/test_unit_block.py +++ b/common/lib/xmodule/xmodule/tests/test_unit_block.py @@ -5,8 +5,8 @@ Tests for the Unit XBlock import re import unittest from xml.dom import minidom +from unittest.mock import patch -from mock import patch from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.completable import XBlockCompletionMode diff --git a/common/lib/xmodule/xmodule/tests/test_util_duedate.py b/common/lib/xmodule/xmodule/tests/test_util_duedate.py index f041e7a0b0..96bd878d7f 100644 --- a/common/lib/xmodule/xmodule/tests/test_util_duedate.py +++ b/common/lib/xmodule/xmodule/tests/test_util_duedate.py @@ -4,8 +4,7 @@ Tests for extended due date utilities. import unittest - -import mock +from unittest import mock from ..util import duedate diff --git a/common/lib/xmodule/xmodule/tests/test_validation.py b/common/lib/xmodule/xmodule/tests/test_validation.py index 86db783303..d32ac3fb17 100644 --- a/common/lib/xmodule/xmodule/tests/test_validation.py +++ b/common/lib/xmodule/xmodule/tests/test_validation.py @@ -21,16 +21,16 @@ class StudioValidationMessageTest(unittest.TestCase): Test that `TypeError`s are thrown for bad input parameters. """ with pytest.raises(TypeError): - StudioValidationMessage("unknown type", u"Unknown type info") + StudioValidationMessage("unknown type", "Unknown type info") with pytest.raises(TypeError): - StudioValidationMessage(StudioValidationMessage.WARNING, u"bad warning", action_class=0) + StudioValidationMessage(StudioValidationMessage.WARNING, "bad warning", action_class=0) with pytest.raises(TypeError): - StudioValidationMessage(StudioValidationMessage.WARNING, u"bad warning", action_runtime_event=0) + StudioValidationMessage(StudioValidationMessage.WARNING, "bad warning", action_runtime_event=0) with pytest.raises(TypeError): - StudioValidationMessage(StudioValidationMessage.WARNING, u"bad warning", action_label=b"Non-unicode string") + StudioValidationMessage(StudioValidationMessage.WARNING, "bad warning", action_label=b"Non-unicode string") def test_to_json(self): """ @@ -38,22 +38,22 @@ class StudioValidationMessageTest(unittest.TestCase): """ assert \ {'type': StudioValidationMessage.NOT_CONFIGURED, - 'text': u'Not Configured message', 'action_label': u'Action label'} == \ + 'text': 'Not Configured message', 'action_label': 'Action label'} == \ StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, - u'Not Configured message', action_label=u'Action label').to_json() + 'Not Configured message', action_label='Action label').to_json() assert \ {'type': StudioValidationMessage.WARNING, - 'text': u'Warning message', + 'text': 'Warning message', 'action_class': 'class-for-action'} ==\ - StudioValidationMessage(StudioValidationMessage.WARNING, u'Warning message', + StudioValidationMessage(StudioValidationMessage.WARNING, 'Warning message', action_class='class-for-action').to_json() assert \ {'type': StudioValidationMessage.ERROR, - 'text': u'Error message', 'action_runtime_event': 'do-fix-up'} ==\ + 'text': 'Error message', 'action_runtime_event': 'do-fix-up'} ==\ StudioValidationMessage(StudioValidationMessage.ERROR, - u'Error message', action_runtime_event='do-fix-up').to_json() + 'Error message', action_runtime_event='do-fix-up').to_json() class StudioValidationTest(unittest.TestCase): @@ -63,7 +63,7 @@ class StudioValidationTest(unittest.TestCase): def test_copy(self): validation = Validation("id") - validation.add(ValidationMessage(ValidationMessage.ERROR, u"Error message")) + validation.add(ValidationMessage(ValidationMessage.ERROR, "Error message")) studio_validation = StudioValidation.copy(validation) assert isinstance(studio_validation, StudioValidation) @@ -71,7 +71,7 @@ class StudioValidationTest(unittest.TestCase): assert 1 == len(studio_validation.messages) expected = { "type": StudioValidationMessage.ERROR, - "text": u"Error message" + "text": "Error message" } assert expected == studio_validation.messages[0].to_json() assert studio_validation.summary is None @@ -79,7 +79,7 @@ class StudioValidationTest(unittest.TestCase): def test_copy_studio_validation(self): validation = StudioValidation("id") validation.add( - StudioValidationMessage(StudioValidationMessage.WARNING, u"Warning message", action_label=u"Action Label") + StudioValidationMessage(StudioValidationMessage.WARNING, "Warning message", action_label="Action Label") ) validation_copy = StudioValidation.copy(validation) @@ -87,8 +87,8 @@ class StudioValidationTest(unittest.TestCase): assert 1 == len(validation_copy.messages) expected = { "type": StudioValidationMessage.WARNING, - "text": u"Warning message", - "action_label": u"Action Label" + "text": "Warning message", + "action_label": "Action Label" } assert expected == validation_copy.messages[0].to_json() @@ -105,13 +105,13 @@ class StudioValidationTest(unittest.TestCase): assert validation.empty assert validation - validation.add(StudioValidationMessage(StudioValidationMessage.ERROR, u"Error message")) + validation.add(StudioValidationMessage(StudioValidationMessage.ERROR, "Error message")) assert not validation.empty assert not validation validation_with_summary = StudioValidation("id") validation_with_summary.set_summary( - StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, u"Summary message") + StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, "Summary message") ) assert not validation.empty assert not validation @@ -121,33 +121,33 @@ class StudioValidationTest(unittest.TestCase): Test the behavior of calling `add_messages` with combination of `StudioValidation` instances. """ validation_1 = StudioValidation("id") - validation_1.set_summary(StudioValidationMessage(StudioValidationMessage.WARNING, u"Summary message")) - validation_1.add(StudioValidationMessage(StudioValidationMessage.ERROR, u"Error message")) + validation_1.set_summary(StudioValidationMessage(StudioValidationMessage.WARNING, "Summary message")) + validation_1.add(StudioValidationMessage(StudioValidationMessage.ERROR, "Error message")) validation_2 = StudioValidation("id") - validation_2.set_summary(StudioValidationMessage(StudioValidationMessage.ERROR, u"Summary 2 message")) - validation_2.add(StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, u"Not configured")) + validation_2.set_summary(StudioValidationMessage(StudioValidationMessage.ERROR, "Summary 2 message")) + validation_2.add(StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, "Not configured")) validation_1.add_messages(validation_2) assert 2 == len(validation_1.messages) assert StudioValidationMessage.ERROR == validation_1.messages[0].type - assert u'Error message' == validation_1.messages[0].text + assert 'Error message' == validation_1.messages[0].text assert StudioValidationMessage.NOT_CONFIGURED == validation_1.messages[1].type - assert u'Not configured' == validation_1.messages[1].text + assert 'Not configured' == validation_1.messages[1].text assert StudioValidationMessage.WARNING == validation_1.summary.type - assert u'Summary message' == validation_1.summary.text + assert 'Summary message' == validation_1.summary.text def test_set_summary_accepts_validation_message(self): """ Test that `set_summary` accepts a ValidationMessage. """ validation = StudioValidation("id") - validation.set_summary(ValidationMessage(ValidationMessage.WARNING, u"Summary message")) + validation.set_summary(ValidationMessage(ValidationMessage.WARNING, "Summary message")) assert ValidationMessage.WARNING == validation.summary.type - assert u'Summary message' == validation.summary.text + assert 'Summary message' == validation.summary.text def test_set_summary_errors(self): """ @@ -171,24 +171,24 @@ class StudioValidationTest(unittest.TestCase): validation.add( StudioValidationMessage( StudioValidationMessage.ERROR, - u"Error message", - action_label=u"Action label", + "Error message", + action_label="Action label", action_class="edit-button" ) ) validation.add( StudioValidationMessage( StudioValidationMessage.NOT_CONFIGURED, - u"Not configured message", - action_label=u"Action label", + "Not configured message", + action_label="Action label", action_runtime_event="make groups" ) ) validation.set_summary( StudioValidationMessage( StudioValidationMessage.WARNING, - u"Summary message", - action_label=u"Summary label", + "Summary message", + action_label="Summary label", action_runtime_event="fix everything" ) ) @@ -200,21 +200,21 @@ class StudioValidationTest(unittest.TestCase): "messages": [ { "type": "error", - "text": u"Error message", - "action_label": u"Action label", + "text": "Error message", + "action_label": "Action label", "action_class": "edit-button" }, { "type": "not-configured", - "text": u"Not configured message", - "action_label": u"Action label", + "text": "Not configured message", + "action_label": "Action label", "action_runtime_event": "make groups" } ], "summary": { "type": "warning", - "text": u"Summary message", - "action_label": u"Summary label", + "text": "Summary message", + "action_label": "Summary label", "action_runtime_event": "fix everything" }, "empty": False diff --git a/common/lib/xmodule/xmodule/tests/test_vertical.py b/common/lib/xmodule/xmodule/tests/test_vertical.py index 3034688c18..17cc6c3dc4 100644 --- a/common/lib/xmodule/xmodule/tests/test_vertical.py +++ b/common/lib/xmodule/xmodule/tests/test_vertical.py @@ -8,12 +8,11 @@ Tests for vertical module. from collections import namedtuple from datetime import datetime, timedelta import json -import pytz -import six +from unittest.mock import Mock, patch +import pytz import ddt from fs.memoryfs import MemoryFS -from mock import Mock, patch from . import get_test_system from .helpers import StubUserService @@ -36,7 +35,7 @@ def get_json_request(data): ) -class StubCompletionService(object): +class StubCompletionService: """ A stub implementation of the CompletionService for testing without access to django """ @@ -86,7 +85,7 @@ class BaseVerticalBlockTest(XModuleXmlImportTest): test_problem = 'Test Problem' def setUp(self): - super(BaseVerticalBlockTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # construct module course = xml.CourseFactory.build() sequence = xml.SequenceFactory.build(parent=course) @@ -126,7 +125,7 @@ class VerticalBlockTestCase(BaseVerticalBlockTest): Assert content has/hasn't all the bookmark info. """ assertion('bookmark_id', content) - assertion('{},{}'.format(self.username, six.text_type(self.vertical.location)), content) + assertion('{},{}'.format(self.username, str(self.vertical.location)), content) assertion('bookmarked', content) assertion('show_bookmark_button', content) @@ -170,8 +169,8 @@ class VerticalBlockTestCase(BaseVerticalBlockTest): if context: assert "'has_assignments': True" in html assert "'subsection_format': '{}'".format(context['format']) in html - assert "'completed': {}".format((completion_value == 1)) in html - assert "'past_due': {}".format((self.vertical.due < now)) in html + assert "'completed': {}".format(completion_value == 1) in html + assert "'past_due': {}".format(self.vertical.due < now) in html @ddt.data(True, False) def test_render_problem_without_score(self, has_score): diff --git a/common/lib/xmodule/xmodule/tests/test_video.py b/common/lib/xmodule/xmodule/tests/test_video.py index 0b9d508f19..c44a762142 100644 --- a/common/lib/xmodule/xmodule/tests/test_video.py +++ b/common/lib/xmodule/xmodule/tests/test_video.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # pylint: disable=protected-access """Test for Video Xmodule functional logic. These test data read from xml, not from mongo. @@ -21,19 +20,18 @@ import shutil import unittest from tempfile import mkdtemp from uuid import uuid4 +from unittest.mock import ANY, MagicMock, Mock, patch + import pytest import ddt import httpretty -import six from django.conf import settings from django.test import TestCase from django.test.utils import override_settings from fs.osfs import OSFS from lxml import etree -from mock import ANY, MagicMock, Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import CourseLocator -from six.moves import zip from xblock.field_data import DictFieldData from xblock.fields import ScopeIds @@ -79,9 +77,9 @@ MOCKED_YOUTUBE_TRANSCRIPT_API_RESPONSE = ''' ''' ALL_LANGUAGES = ( - [u"en", u"English"], - [u"eo", u"Esperanto"], - [u"ur", u"Urdu"] + ["en", "English"], + ["eo", "Esperanto"], + ["ur", "Urdu"] ) @@ -174,7 +172,7 @@ class VideoBlockTestBase(unittest.TestCase): """ def setUp(self): - super(VideoBlockTestBase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.descriptor = instantiate_descriptor() def assertXmlEqual(self, expected, xml): @@ -233,7 +231,7 @@ class TestCreateYouTubeUrl(VideoBlockTestBase): Test that passing unicode to `create_youtube_url` doesn't throw an error. """ - self.descriptor.create_youtube_url(u"üñîçø∂é") + self.descriptor.create_youtube_url("üñîçø∂é") @ddt.ddt @@ -617,7 +615,7 @@ class VideoBlockImportTestCase(TestCase): assert edx_video_id == 'test_edx_video_id' assert static_dir == EXPORT_IMPORT_STATIC_DIR assert resource_fs is not None - assert external_transcripts == {u'en': [u'subs_3_yD_cEKoCk.srt.sjson']} + assert external_transcripts == {'en': ['subs_3_yD_cEKoCk.srt.sjson']} assert course_id == 'test_course_id' return edx_video_id @@ -646,7 +644,7 @@ class VideoBlockImportTestCase(TestCase): edx_video_id, module_system.resources_fs, EXPORT_IMPORT_STATIC_DIR, - {u'en': [u'subs_3_yD_cEKoCk.srt.sjson']}, + {'en': ['subs_3_yD_cEKoCk.srt.sjson']}, course_id='test_course_id' ) @@ -672,7 +670,7 @@ class VideoExportTestCase(VideoBlockTestBase): """ def setUp(self): - super(VideoExportTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.temp_dir = mkdtemp() self.file_system = OSFS(self.temp_dir) self.addCleanup(shutil.rmtree, self.temp_dir) @@ -682,7 +680,7 @@ class VideoExportTestCase(VideoBlockTestBase): """ Test that we write the correct XML on export. """ - edx_video_id = u'test_edx_video_id' + edx_video_id = 'test_edx_video_id' mock_val_api.export_to_xml = Mock( return_value=dict( xml=etree.Element('video_asset'), @@ -733,7 +731,7 @@ class VideoExportTestCase(VideoBlockTestBase): video_id=edx_video_id, static_dir=EXPORT_IMPORT_STATIC_DIR, resource_fs=self.file_system, - course_id=six.text_type(self.descriptor.runtime.course_id.for_branch(None)), + course_id=str(self.descriptor.runtime.course_id.for_branch(None)), ) @patch('xmodule.video_module.video_module.edxval_api') @@ -814,9 +812,9 @@ class VideoExportTestCase(VideoBlockTestBase): """ Test XML export handles the unicode characters. """ - self.descriptor.display_name = u'这是文' + self.descriptor.display_name = '这是文' xml = self.descriptor.definition_to_xml(self.file_system) - assert xml.get('display_name') == u'这是文' + assert xml.get('display_name') == '这是文' @ddt.ddt @@ -875,15 +873,15 @@ class VideoBlockStudentViewDataTestCase(unittest.TestCase): def test_student_view_data_with_hls_flag(self, mock_get_video_info, mock_get_video_transcript_content): mock_get_video_info.return_value = { 'url': '/edxval/video/example', - 'edx_video_id': u'example_id', + 'edx_video_id': 'example_id', 'duration': 111.0, - 'client_video_id': u'The example video', + 'client_video_id': 'The example video', 'encoded_videos': [ { - 'url': u'http://www.meowmix.com', + 'url': 'http://www.meowmix.com', 'file_size': 25556, 'bitrate': 9600, - 'profile': u'hls' + 'profile': 'hls' } ] } @@ -901,7 +899,7 @@ class VideoBlockStudentViewDataTestCase(unittest.TestCase): descriptor.runtime.course_id = MagicMock() descriptor.runtime.handler_url = MagicMock() student_view_data = descriptor.student_view_data() - expected_video_data = {u'hls': {'url': u'http://www.meowmix.com', 'file_size': 25556}} + expected_video_data = {'hls': {'url': 'http://www.meowmix.com', 'file_size': 25556}} self.assertDictEqual(student_view_data.get('encoded_videos'), expected_video_data) @@ -985,7 +983,7 @@ class VideoBlockIndexingTestCase(unittest.TestCase): ''' yt_subs_id = 'OEoXaMPEzfM' - url = 'http://video.google.com/timedtext?lang=en&v={}'.format(yt_subs_id) + url = f'http://video.google.com/timedtext?lang=en&v={yt_subs_id}' httpretty.register_uri( method=httpretty.GET, uri=url, @@ -1020,7 +1018,7 @@ class VideoBlockIndexingTestCase(unittest.TestCase): ''' yt_subs_id = 'OEoXaMPEzfM' - url = 'http://video.google.com/timedtext?lang=en&v={}'.format(yt_subs_id) + url = f'http://video.google.com/timedtext?lang=en&v={yt_subs_id}' httpretty.register_uri( method=httpretty.GET, uri=url, diff --git a/common/lib/xmodule/xmodule/tests/test_word_cloud.py b/common/lib/xmodule/xmodule/tests/test_word_cloud.py index 9c3d6c23d0..17f91afab7 100644 --- a/common/lib/xmodule/xmodule/tests/test_word_cloud.py +++ b/common/lib/xmodule/xmodule/tests/test_word_cloud.py @@ -1,12 +1,11 @@ -# -*- coding: utf-8 -*- """Test for Word cloud Xmodule functional logic.""" import json +from unittest.mock import Mock from django.test import TestCase from fs.memoryfs import MemoryFS from lxml import etree -from mock import Mock from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from webob.multidict import MultiDict from xblock.field_data import DictFieldData @@ -57,7 +56,7 @@ class WordCloudBlockTest(TestCase): node = etree.Element("unknown_root") # This will export the olx to a separate file. block.add_xml_to_node(node) - with runtime.export_fs.open(u'word_cloud/block_id.xml') as f: + with runtime.export_fs.open('word_cloud/block_id.xml') as f: exported_xml = f.read() assert exported_xml == original_xml @@ -103,7 +102,7 @@ class WordCloudBlockTest(TestCase): {'text': 'sun', 'size': 1, 'percent': 4.0}] ) - assert 100.0 == sum((i['percent'] for i in response['top_words'])) + assert 100.0 == sum(i['percent'] for i in response['top_words']) def test_indexibility(self): """ diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py index c742448ffa..74f9fd96b8 100644 --- a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py +++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Tests for the wrapping layer that provides the XBlock API using XModule/Descriptor functionality @@ -8,6 +7,7 @@ functionality from unittest.case import SkipTest, TestCase +from unittest.mock import Mock import ddt import webob @@ -23,9 +23,7 @@ from factory import ( ) from fs.memoryfs import MemoryFS from lxml import etree -from mock import Mock from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator -from six.moves import range from xblock.core import XBlock from xblock.field_data import DictFieldData from xblock.fields import ScopeIds @@ -69,7 +67,7 @@ CONTAINER_XMODULES = { ConditionalBlock: [{}], CourseBlock: [{}], RandomizeBlock: [{'display_name': 'Test String Display'}], - SequenceBlock: [{'display_name': u'Test Unicode हिंदी Display'}], + SequenceBlock: [{'display_name': 'Test Unicode हिंदी Display'}], VerticalBlock: [{}], WrapperBlock: [{}], } @@ -98,7 +96,7 @@ class ModuleSystemFactory(Factory): performed by :func:`xmodule.tests.get_test_system`, so arguments for that function are valid factory attributes. """ - class Meta(object): + class Meta: model = ModuleSystem @classmethod @@ -114,7 +112,7 @@ class DescriptorSystemFactory(Factory): performed by :func:`xmodule.tests.get_test_descriptor_system`, so arguments for that function are valid factory attributes. """ - class Meta(object): + class Meta: model = DescriptorSystem @classmethod @@ -185,7 +183,7 @@ class LeafDescriptorFactory(Factory): Factory to generate leaf XModuleDescriptors. """ - class Meta(object): + class Meta: model = XModuleDescriptor runtime = SubFactory(DescriptorSystemFactory) @@ -260,7 +258,7 @@ class ContainerModuleFactory(LeafModuleFactory): @ddt.ddt -class XBlockWrapperTestMixin(object): +class XBlockWrapperTestMixin: """ This is a mixin for building tests of the implementation of the XBlock api by wrapping XModule native functions. @@ -374,7 +372,7 @@ class TestXModuleHandler(TestCase): """ def setUp(self): - super(TestXModuleHandler, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.module = XModule(descriptor=Mock(), field_data=Mock(), runtime=Mock(), scope_ids=Mock()) self.module.handle_ajax = Mock(return_value='{}') self.request = webob.Request({}) @@ -393,7 +391,7 @@ class TestXModuleHandler(TestCase): assert response.body.decode('utf-8') == '{}' @ddt.data( - u'{"test_key": "test_value"}', + '{"test_key": "test_value"}', '{"test_key": "test_value"}', ) def test_xmodule_handler_with_data(self, response_data): diff --git a/common/lib/xmodule/xmodule/tests/test_xml_module.py b/common/lib/xmodule/xmodule/tests/test_xml_module.py index 8906ae9260..b58fd59f68 100644 --- a/common/lib/xmodule/xmodule/tests/test_xml_module.py +++ b/common/lib/xmodule/xmodule/tests/test_xml_module.py @@ -3,10 +3,9 @@ import unittest +from unittest.mock import Mock -from mock import Mock from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator -from six.moves import range from xblock.field_data import DictFieldData from xblock.fields import Any, Boolean, Dict, Float, Integer, List, Scope, String from xblock.runtime import DictKeyValueStore, KvsFieldData @@ -28,7 +27,7 @@ class CrazyJsonString(String): return value + " JSON" -class TestFields(object): +class TestFields: # Will be returned by editable_metadata_fields. max_attempts = Integer(scope=Scope.settings, default=1000, values={'min': 1, 'max': 10}) # Will not be returned by editable_metadata_fields because filtered out by non_editable_metadata_fields. @@ -73,7 +72,7 @@ class InheritingFieldDataTest(unittest.TestCase): not_inherited = String(scope=Scope.settings, default="nothing") def setUp(self): - super(InheritingFieldDataTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.dummy_course_key = CourseLocator('test_org', 'test_123', 'test_run') self.system = get_test_descriptor_system() self.all_blocks = {} @@ -164,7 +163,7 @@ class InheritingFieldDataTest(unittest.TestCase): parent.inherited = "Changed!" assert parent.inherited == 'Changed!' for child_num in range(10): - usage_id = self.get_usage_id("vertical", "child_{}".format(child_num)) + usage_id = self.get_usage_id("vertical", f"child_{child_num}") child = self.get_a_block(usage_id=usage_id) child.parent = parent.location assert child.inherited == 'Changed!' @@ -343,7 +342,7 @@ class EditableMetadataFieldsTest(unittest.TestCase): class TestModuleDescriptor(TestFields, XmlDescriptor): # lint-amnesty, pylint: disable=abstract-method @property def non_editable_metadata_fields(self): - non_editable_fields = super(TestModuleDescriptor, self).non_editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments + non_editable_fields = super().non_editable_metadata_fields non_editable_fields.append(TestModuleDescriptor.due) return non_editable_fields diff --git a/common/lib/xmodule/xmodule/tests/xml/__init__.py b/common/lib/xmodule/xmodule/tests/xml/__init__.py index 3ebc8f6078..9918fc0d21 100644 --- a/common/lib/xmodule/xmodule/tests/xml/__init__.py +++ b/common/lib/xmodule/xmodule/tests/xml/__init__.py @@ -4,12 +4,11 @@ Xml parsing tests for XModules import pprint +from unittest.mock import Mock from django.test import TestCase from lxml import etree -from mock import Mock from opaque_keys.edx.keys import CourseKey -from six import text_type from xblock.runtime import DictKeyValueStore, KvsFieldData from xmodule.mako_module import MakoDescriptorSystem @@ -30,7 +29,7 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable """Return the policy data for the specified usage""" return xml_import_data.policy.get(policy_key(usage_id), {}) - super(InMemorySystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( get_policy=get_policy, process_xml=self.process_xml, load_item=self.load_item, @@ -50,12 +49,12 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable None, CourseLocationManager(self.course_id), ) - self._descriptors[text_type(descriptor.location)] = descriptor + self._descriptors[str(descriptor.location)] = descriptor return descriptor def load_item(self, location, for_parent=None): # pylint: disable=method-hidden, unused-argument """Return the descriptor loaded for `location`""" - return self._descriptors[text_type(location)] + return self._descriptors[str(location)] class XModuleXmlImportTest(TestCase): diff --git a/common/lib/xmodule/xmodule/tests/xml/factories.py b/common/lib/xmodule/xmodule/tests/xml/factories.py index db383ed90b..7409b0ac6d 100644 --- a/common/lib/xmodule/xmodule/tests/xml/factories.py +++ b/common/lib/xmodule/xmodule/tests/xml/factories.py @@ -16,7 +16,7 @@ from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.x_module import XModuleMixin -class XmlImportData(object): +class XmlImportData: """ Class to capture all of the data needed to actually run an XML import, so that the Factories have something to generate @@ -49,7 +49,7 @@ class XmlImportData(object): return etree.tostring(self._xml_node) def __repr__(self): - return u"XmlImportData{!r}".format(( + return "XmlImportData{!r}".format(( self._xml_node, self._xml_string, self.course_id, self.default_class, self.policy, self.filesystem, self.parent, self.xblock_mixins, @@ -67,7 +67,7 @@ class XmlImportFactory(Factory): Factory for generating XmlImportData's, which can hold all the data needed to run an XModule XML import """ - class Meta(object): + class Meta: model = XmlImportData filesystem = OSFS(mkdtemp()) diff --git a/common/lib/xmodule/xmodule/timeinfo.py b/common/lib/xmodule/xmodule/timeinfo.py index 5af457f3da..f88ed4cb3b 100644 --- a/common/lib/xmodule/xmodule/timeinfo.py +++ b/common/lib/xmodule/xmodule/timeinfo.py @@ -2,13 +2,12 @@ import logging -import six from xmodule.fields import Timedelta log = logging.getLogger(__name__) -class TimeInfo(object): +class TimeInfo: """ This is a simple object that calculates and stores datetime information for an XModule based on the due date and the grace period string @@ -29,11 +28,11 @@ class TimeInfo(object): self.display_due_date = None if grace_period_string_or_timedelta is not None and self.display_due_date: - if isinstance(grace_period_string_or_timedelta, six.string_types): + if isinstance(grace_period_string_or_timedelta, str): try: self.grace_period = TimeInfo._delta_standin.from_json(grace_period_string_or_timedelta) except: - log.error("Error parsing the grace period {0}".format(grace_period_string_or_timedelta)) + log.error(f"Error parsing the grace period {grace_period_string_or_timedelta}") raise else: self.grace_period = grace_period_string_or_timedelta diff --git a/common/lib/xmodule/xmodule/unit_block.py b/common/lib/xmodule/xmodule/unit_block.py index 712b3b2f63..2d3dacb65b 100644 --- a/common/lib/xmodule/xmodule/unit_block.py +++ b/common/lib/xmodule/xmodule/unit_block.py @@ -61,7 +61,7 @@ class UnitBlock(XBlock): """ # return key/value fields in a Python dict object # values may be numeric / string or dict - xblock_body = super(UnitBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments + xblock_body = super().index_dictionary() index_body = { "display_name": self.display_name, } diff --git a/common/lib/xmodule/xmodule/util/misc.py b/common/lib/xmodule/xmodule/util/misc.py index abc09d0111..29c2893469 100644 --- a/common/lib/xmodule/xmodule/util/misc.py +++ b/common/lib/xmodule/xmodule/util/misc.py @@ -68,7 +68,7 @@ def get_short_labeler(prefix): `prefix` to an assignment index. """ def labeler(index): - return u"{prefix} {index:02d}".format(prefix=prefix, index=index) + return f"{prefix} {index:02d}" return labeler diff --git a/common/lib/xmodule/xmodule/util/sandboxing.py b/common/lib/xmodule/xmodule/util/sandboxing.py index 49114b36b3..7dc6a9320b 100644 --- a/common/lib/xmodule/xmodule/util/sandboxing.py +++ b/common/lib/xmodule/xmodule/util/sandboxing.py @@ -2,7 +2,6 @@ import re -import six from django.conf import settings DEFAULT_PYTHON_LIB_FILENAME = 'python_lib.zip' @@ -28,7 +27,7 @@ def can_execute_unsafe_code(course_id): # To others using this: the code as-is is brittle and likely to be changed in the future, # as per the TODO, so please consider carefully before adding more values to COURSES_WITH_UNSAFE_CODE for regex in getattr(settings, 'COURSES_WITH_UNSAFE_CODE', []): - if re.match(regex, six.text_type(course_id)): + if re.match(regex, str(course_id)): return True return False diff --git a/common/lib/xmodule/xmodule/validation.py b/common/lib/xmodule/xmodule/validation.py index d52e375044..2496f54cfe 100644 --- a/common/lib/xmodule/xmodule/validation.py +++ b/common/lib/xmodule/xmodule/validation.py @@ -1,9 +1,6 @@ """ Extension of XBlock Validation class to include information for presentation in Studio. """ - - -import six from xblock.validation import Validation, ValidationMessage @@ -33,17 +30,17 @@ class StudioValidationMessage(ValidationMessage): action_runtime_event (str): An event name to be triggered on the xblock client-side runtime when the "fix-up" action is clicked (optional). """ - super(StudioValidationMessage, self).__init__(message_type, message_text) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(message_type, message_text) if action_label is not None: - if not isinstance(action_label, six.text_type): + if not isinstance(action_label, str): raise TypeError("Action label must be unicode.") self.action_label = action_label if action_class is not None: - if not isinstance(action_class, six.string_types): + if not isinstance(action_class, str): raise TypeError("Action class must be a string.") self.action_class = action_class if action_runtime_event is not None: - if not isinstance(action_runtime_event, six.string_types): + if not isinstance(action_runtime_event, str): raise TypeError("Action runtime event must be a string.") self.action_runtime_event = action_runtime_event @@ -54,7 +51,7 @@ class StudioValidationMessage(ValidationMessage): Returns: dict: A dict representation that is json-serializable. """ - serialized = super(StudioValidationMessage, self).to_json() # lint-amnesty, pylint: disable=super-with-arguments + serialized = super().to_json() if hasattr(self, "action_label"): serialized["action_label"] = self.action_label if hasattr(self, "action_class"): @@ -94,7 +91,7 @@ class StudioValidation(Validation): Args: xblock_id (object): An identification object that must support conversion to unicode. """ - super(StudioValidation, self).__init__(xblock_id) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(xblock_id) self.summary = None def set_summary(self, message): @@ -116,7 +113,7 @@ class StudioValidation(Validation): Returns: bool: True iff this instance has no validation issues and therefore has no messages or summary. """ - return super(StudioValidation, self).empty and not self.summary # lint-amnesty, pylint: disable=super-with-arguments + return super().empty and not self.summary def to_json(self): """ @@ -125,7 +122,7 @@ class StudioValidation(Validation): Returns: dict: A dict representation that is json-serializable. """ - serialized = super(StudioValidation, self).to_json() # lint-amnesty, pylint: disable=super-with-arguments + serialized = super().to_json() if self.summary: serialized["summary"] = self.summary.to_json() return serialized diff --git a/common/lib/xmodule/xmodule/vertical_block.py b/common/lib/xmodule/xmodule/vertical_block.py index 9480f39c35..ad970d6221 100644 --- a/common/lib/xmodule/xmodule/vertical_block.py +++ b/common/lib/xmodule/xmodule/vertical_block.py @@ -9,7 +9,6 @@ from datetime import datetime from functools import reduce import pytz -import six from lxml import etree from web_fragments.fragment import Fragment @@ -94,7 +93,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse fragment.add_fragment_resources(rendered_child) contents.append({ - 'id': six.text_type(child.location), + 'id': str(child.location), 'content': rendered_child.content }) @@ -120,8 +119,8 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse 'show_bookmark_button': child_context.get('show_bookmark_button', not is_child_of_vertical), 'show_title': child_context.get('show_title', True), 'bookmarked': child_context['bookmarked'], - 'bookmark_id': u"{},{}".format( - child_context['username'], six.text_type(self.location)), # pylint: disable=no-member + 'bookmark_id': "{},{}".format( + child_context['username'], str(self.location)), # pylint: disable=no-member }) fragment.add_content(self.system.render_template('vert_module.html', fragment_context)) @@ -172,7 +171,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse """ Returns the highest priority icon class. """ - child_classes = set(child.get_icon_class() for child in self.get_children()) + child_classes = {child.get_icon_class() for child in self.get_children()} new_class = 'other' for higher_class in CLASS_PRIORITY: if higher_class in child_classes: @@ -189,7 +188,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse except Exception as exc: # pylint: disable=broad-except log.exception("Unable to load child when parsing Vertical. Continuing...") if system.error_tracker is not None: - system.error_tracker(u"ERROR: {0}".format(exc)) + system.error_tracker(f"ERROR: {exc}") continue return {}, children @@ -204,14 +203,14 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse """ Gather all fields which can't be edited. """ - non_editable_fields = super(VerticalBlock, self).non_editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments + non_editable_fields = super().non_editable_metadata_fields non_editable_fields.extend([ self.fields['due'], # lint-amnesty, pylint: disable=unsubscriptable-object ]) return non_editable_fields def studio_view(self, context): - fragment = super(VerticalBlock, self).studio_view(context) # lint-amnesty, pylint: disable=super-with-arguments + fragment = super().studio_view(context) # This continues to use the old XModuleDescriptor javascript code to enabled studio editing. # TODO: Remove this when studio better supports editing of pure XBlocks. fragment.add_javascript('VerticalBlock = XModule.Descriptor;') @@ -224,7 +223,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse # return key/value fields in a Python dict object # values may be numeric / string or dict # default implementation is an empty dict - xblock_body = super(VerticalBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments + xblock_body = super().index_dictionary() index_body = { "display_name": self.display_name, } diff --git a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py index f17e019ee8..77c7f50fae 100644 --- a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py +++ b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py @@ -12,14 +12,11 @@ from functools import wraps import requests import simplejson as json -import six from django.conf import settings from lxml import etree from opaque_keys.edx.locator import BundleDefinitionLocator from pysrt import SubRipFile, SubRipItem, SubRipTime from pysrt.srtexc import Error -from six import text_type -from six.moves import range, zip from openedx.core.djangolib import blockstore_cache from openedx.core.lib import blockstore_api @@ -71,7 +68,7 @@ def exception_decorator(func): try: return func(*args, **kwds) except (TranscriptsGenerationException, UnicodeDecodeError) as ex: - log.exception(text_type(ex)) + log.exception(str(ex)) raise NotFoundError # lint-amnesty, pylint: disable=raise-missing-from return wrapper @@ -254,7 +251,7 @@ def generate_subs_from_source(speed_subs, subs_type, subs_filedata, item, langua srt_subs_obj = SubRipFile.from_string(subs_filedata) except Exception as ex: msg = _("Something wrong with SubRip transcripts file during parsing. Inner message is {error_message}").format( - error_message=text_type(ex) + error_message=str(ex) ) raise TranscriptsGenerationException(msg) # lint-amnesty, pylint: disable=raise-missing-from if not srt_subs_obj: @@ -274,7 +271,7 @@ def generate_subs_from_source(speed_subs, subs_type, subs_filedata, item, langua 'end': sub_ends, 'text': sub_texts} - for speed, subs_id in six.iteritems(speed_subs): + for speed, subs_id in speed_subs.items(): save_subs_to_store( generate_subs(speed, 1, subs), subs_id, @@ -308,7 +305,7 @@ def generate_srt_from_sjson(sjson_subs, speed): end=SubRipTime(milliseconds=sjson_speed_1['end'][i]), text=sjson_speed_1['text'][i] ) - output += (six.text_type(item)) + output += (str(item)) output += '\n' return output @@ -346,7 +343,7 @@ def copy_or_rename_transcript(new_name, old_name, item, delete_old=False, user=N If `old_name` is not found in storage, raises `NotFoundError`. If `delete_old` is True, removes `old_name` files from storage. """ - filename = u'subs_{0}.srt.sjson'.format(old_name) + filename = f'subs_{old_name}.srt.sjson' content_location = StaticContent.compute_location(item.location.course_key, filename) transcripts = contentstore().find(content_location).data.decode('utf-8') save_subs_to_store(json.loads(transcripts), new_name, item) @@ -447,7 +444,7 @@ def manage_video_subtitles_save(item, user, old_metadata=None, generate_translat generate_sjson_for_all_speeds( item, item.transcripts[lang], - {speed: subs_id for subs_id, speed in six.iteritems(youtube_speed_dict(item))}, + {speed: subs_id for subs_id, speed in youtube_speed_dict(item).items()}, lang, ) except TranscriptException as ex: # lint-amnesty, pylint: disable=unused-variable @@ -472,9 +469,9 @@ def subs_filename(subs_id, lang='en'): Generate proper filename for storage. """ if lang == 'en': - return u'subs_{0}.srt.sjson'.format(subs_id) + return f'subs_{subs_id}.srt.sjson' else: - return u'{0}_subs_{1}.srt.sjson'.format(lang, subs_id) + return f'{lang}_subs_{subs_id}.srt.sjson' def generate_sjson_for_all_speeds(item, user_filename, result_subs_dict, lang): @@ -489,7 +486,7 @@ def generate_sjson_for_all_speeds(item, user_filename, result_subs_dict, lang): srt_transcripts = contentstore().find(Transcript.asset_location(item.location, user_filename)) except NotFoundError as ex: raise TranscriptException(_("{exception_message}: Can't find uploaded transcripts: {user_filename}").format( # lint-amnesty, pylint: disable=raise-missing-from - exception_message=text_type(ex), + exception_message=str(ex), user_filename=user_filename )) @@ -545,7 +542,7 @@ def get_video_ids_info(edx_video_id, youtube_id_1_0, html5_sources): Returns: tuple: external or internal, video ids list """ - clean = lambda item: item.strip() if isinstance(item, six.string_types) else item + clean = lambda item: item.strip() if isinstance(item, str) else item external = not bool(clean(edx_video_id)) video_ids = [edx_video_id, youtube_id_1_0] + get_html5_ids(html5_sources) @@ -617,23 +614,23 @@ def convert_video_transcript(file_name, content, output_format): """ name_and_extension = os.path.splitext(file_name) basename, input_format = name_and_extension[0], name_and_extension[1][1:] - filename = u'{base_name}.{ext}'.format(base_name=basename, ext=output_format) + filename = f'{basename}.{output_format}' converted_transcript = Transcript.convert(content, input_format=input_format, output_format=output_format) return dict(filename=filename, content=converted_transcript) -class Transcript(object): +class Transcript: """ Container for transcript methods. """ - SRT = u'srt' - TXT = u'txt' - SJSON = u'sjson' + SRT = 'srt' + TXT = 'txt' + SJSON = 'sjson' mime_types = { - SRT: u'application/x-subrip; charset=utf-8', - TXT: u'text/plain; charset=utf-8', - SJSON: u'application/json', + SRT: 'application/x-subrip; charset=utf-8', + TXT: 'text/plain; charset=utf-8', + SJSON: 'application/json', } @staticmethod @@ -655,7 +652,7 @@ class Transcript(object): if input_format == 'srt': # Standardize content into bytes for later decoding. - if isinstance(content, text_type): + if isinstance(content, str): content = content.encode('utf-8') if output_format == 'txt': @@ -670,7 +667,7 @@ class Transcript(object): error_handling=SubRipFile.ERROR_RAISE ) except Error as ex: # Base exception from pysrt - raise TranscriptsGenerationException(text_type(ex)) # lint-amnesty, pylint: disable=raise-missing-from + raise TranscriptsGenerationException(str(ex)) # lint-amnesty, pylint: disable=raise-missing-from return json.dumps(generate_sjson_from_srt(srt_subs)) @@ -731,7 +728,7 @@ class Transcript(object): return StaticContent.compute_location(location.course_key, filename) -class VideoTranscriptsMixin(object): +class VideoTranscriptsMixin: """Mixin class for transcript functionality. This is necessary for VideoBlock. @@ -764,7 +761,7 @@ class VideoTranscriptsMixin(object): if sub: all_langs.update({'en': sub}) - for language, filename in six.iteritems(all_langs): + for language, filename in all_langs.items(): try: # for bumper videos, transcripts are stored in content store only if is_bumper: @@ -795,11 +792,11 @@ class VideoTranscriptsMixin(object): if self.transcript_language in other_lang: transcript_language = self.transcript_language elif sub: - transcript_language = u'en' + transcript_language = 'en' elif len(other_lang) > 0: transcript_language = sorted(other_lang)[0] else: - transcript_language = u'en' + transcript_language = 'en' return transcript_language def get_transcripts_info(self, is_bumper=False): @@ -854,7 +851,7 @@ def get_transcript_from_val(edx_video_id, lang=None, output_format=Transcript.SR """ transcript = get_video_transcript_content(edx_video_id, lang) if not transcript: - raise NotFoundError(u'Transcript not found for {}, lang: {}'.format(edx_video_id, lang)) + raise NotFoundError(f'Transcript not found for {edx_video_id}, lang: {lang}') transcript_conversion_props = dict(transcript, output_format=output_format) transcript = convert_video_transcript(**transcript_conversion_props) @@ -916,7 +913,7 @@ def get_transcript_from_contentstore(video, language, output_format, transcripts """ input_format, base_name, transcript_content = None, None, None if output_format not in (Transcript.SRT, Transcript.SJSON, Transcript.TXT): - raise NotFoundError('Invalid transcript format `{output_format}`'.format(output_format=output_format)) + raise NotFoundError(f'Invalid transcript format `{output_format}`') sub, other_languages = transcripts_info['sub'], transcripts_info['transcripts'] transcripts = dict(other_languages) @@ -925,7 +922,7 @@ def get_transcript_from_contentstore(video, language, output_format, transcripts possible_sub_ids = [youtube_id, sub, video.youtube_id_1_0] + get_html5_ids(video.html5_sources) for sub_id in possible_sub_ids: try: - transcripts[u'en'] = sub_id + transcripts['en'] = sub_id input_format, base_name, transcript_content = get_transcript_for_video( video.location, subs_id=sub_id, @@ -942,8 +939,8 @@ def get_transcript_from_contentstore(video, language, output_format, transcripts )) # add language prefix to transcript file only if language is not None - language_prefix = '{}_'.format(language) if language else '' - transcript_name = u'{}{}.{}'.format(language_prefix, base_name, output_format) + language_prefix = f'{language}_' if language else '' + transcript_name = f'{language_prefix}{base_name}.{output_format}' transcript_content = Transcript.convert(transcript_content, input_format=input_format, output_format=output_format) if not transcript_content.strip(): raise NotFoundError('No transcript content') @@ -991,7 +988,7 @@ def get_transcript_from_blockstore(video_block, language, output_format, transcr tuple containing content, filename, mimetype """ if output_format not in (Transcript.SRT, Transcript.SJSON, Transcript.TXT): - raise NotFoundError('Invalid transcript format `{output_format}`'.format(output_format=output_format)) + raise NotFoundError(f'Invalid transcript format `{output_format}`') transcripts = transcripts_info['transcripts'] if language not in transcripts: raise NotFoundError("Video {} does not have a transcript file defined for the '{}' language in its OLX.".format( @@ -1017,7 +1014,7 @@ def get_transcript_from_blockstore(video_block, language, output_format, transcr )) # Now convert the transcript data to the requested format: filename_no_extension = os.path.splitext(filename)[0] - output_filename = '{}.{}'.format(filename_no_extension, output_format) + output_filename = f'{filename_no_extension}.{output_format}' output_transcript = Transcript.convert( content_binary.decode('utf-8'), input_format=Transcript.SRT, diff --git a/common/lib/xmodule/xmodule/video_module/video_handlers.py b/common/lib/xmodule/xmodule/video_module/video_handlers.py index b8ba614acc..30660785ae 100644 --- a/common/lib/xmodule/xmodule/video_module/video_handlers.py +++ b/common/lib/xmodule/xmodule/video_module/video_handlers.py @@ -10,7 +10,6 @@ import json import logging import math -import six from django.core.files.base import ContentFile from django.utils.timezone import now from edxval.api import create_external_video, create_or_update_video_transcript, delete_video_transcript @@ -47,15 +46,15 @@ def to_boolean(value): """ Convert a value from a GET or POST request parameter to a bool """ - if isinstance(value, six.binary_type): + if isinstance(value, bytes): value = value.decode('ascii', errors='replace') - if isinstance(value, six.text_type): + if isinstance(value, str): return value.lower() == 'true' else: return bool(value) -class VideoStudentViewHandlers(object): +class VideoStudentViewHandlers: """ Handlers for video module instance. """ @@ -91,7 +90,7 @@ class VideoStudentViewHandlers(object): value = now() if key == 'speed' and math.isnan(value): - message = u"Invalid speed value {}, must be a float.".format(value) + message = f"Invalid speed value {value}, must be a float." log.warning(message) return json.dumps({'success': False, 'error': message}) @@ -102,8 +101,8 @@ class VideoStudentViewHandlers(object): return json.dumps({'success': True}) - log.debug(u"GET {0}".format(data)) - log.debug(u"DISPATCH {0}".format(dispatch)) + log.debug(f"GET {data}") + log.debug(f"DISPATCH {dispatch}") raise NotFoundError('Unexpected dispatch type') @@ -159,7 +158,7 @@ class VideoStudentViewHandlers(object): generate_sjson_for_all_speeds( self, other_lang[self.transcript_language], - {speed: youtube_id for youtube_id, speed in six.iteritems(youtube_ids)}, + {speed: youtube_id for youtube_id, speed in youtube_ids.items()}, self.transcript_language ) sjson_transcript = Transcript.asset(self.location, youtube_id, self.transcript_language).data @@ -218,7 +217,7 @@ class VideoStudentViewHandlers(object): if asset_path: response = Response( status=307, - location='/static/{0}/{1}'.format( + location='/static/{}/{}'.format( asset_path, subs_filename(transcript_name, self.transcript_language) ) @@ -240,14 +239,14 @@ class VideoStudentViewHandlers(object): """ completion_service = self.runtime.service(self, 'completion') if completion_service is None: # lint-amnesty, pylint: disable=no-else-raise - raise JsonHandlerError(500, u"No completion service found") + raise JsonHandlerError(500, "No completion service found") elif not completion_service.completion_tracking_enabled(): - raise JsonHandlerError(404, u"Completion tracking is not enabled and API calls are unexpected") + raise JsonHandlerError(404, "Completion tracking is not enabled and API calls are unexpected") if not isinstance(data['completion'], (int, float)): # lint-amnesty, pylint: disable=no-else-raise - message = u"Invalid completion value {}. Must be a float in range [0.0, 1.0]" + message = "Invalid completion value {}. Must be a float in range [0.0, 1.0]" raise JsonHandlerError(400, message.format(data['completion'])) elif not 0.0 <= data['completion'] <= 1.0: - message = u"Invalid completion value {}. Must be in range [0.0, 1.0]" + message = "Invalid completion value {}. Must be in range [0.0, 1.0]" raise JsonHandlerError(400, message.format(data['completion'])) self.runtime.publish(self, "completion", data) return {"result": "ok"} @@ -272,7 +271,7 @@ class VideoStudentViewHandlers(object): headerlist.append( ( 'Content-Disposition', - 'attachment; filename="{}"'.format(filename.encode('utf-8') if six.PY2 else filename) + f'attachment; filename="{filename}"' ) ) @@ -419,7 +418,7 @@ class VideoStudentViewHandlers(object): return response -class VideoStudioViewHandlers(object): +class VideoStudioViewHandlers: """ Handlers for Studio view. """ @@ -443,15 +442,15 @@ class VideoStudioViewHandlers(object): available_translations = self.available_translations(transcripts, verify_assets=True) if missing: - error = _(u'The following parameters are required: {missing}.').format(missing=', '.join(missing)) + error = _('The following parameters are required: {missing}.').format(missing=', '.join(missing)) elif ( data['language_code'] != data['new_language_code'] and data['new_language_code'] in available_translations ): - error = _(u'A transcript with the "{language_code}" language code already exists.'.format( # lint-amnesty, pylint: disable=translation-of-non-string + error = _('A transcript with the "{language_code}" language code already exists.'.format( # lint-amnesty, pylint: disable=translation-of-non-string language_code=data['new_language_code'] )) elif 'file' not in data: - error = _(u'A transcript file is required.') + error = _('A transcript file is required.') return error @@ -500,7 +499,7 @@ class VideoStudioViewHandlers(object): if not edx_video_id: # Back-populate the video ID for an external video. # pylint: disable=attribute-defined-outside-init - self.edx_video_id = edx_video_id = create_external_video(display_name=u'external video') + self.edx_video_id = edx_video_id = create_external_video(display_name='external video') try: # Convert SRT transcript into an SJSON format @@ -528,7 +527,7 @@ class VideoStudioViewHandlers(object): response = Response( json={ 'error': _( - u'There is a problem with this transcript file. Try to upload a different file.' + 'There is a problem with this transcript file. Try to upload a different file.' ) }, status=400 @@ -545,7 +544,7 @@ class VideoStudioViewHandlers(object): if edx_video_id: delete_video_transcript(video_id=edx_video_id, language_code=language) - if language == u'en': + if language == 'en': # remove any transcript file from content store for the video ids possible_sub_ids = [ self.sub, # pylint: disable=access-member-before-definition @@ -567,7 +566,7 @@ class VideoStudioViewHandlers(object): elif request.method == 'GET': language = request.GET.get('language_code') if not language: - return Response(json={'error': _(u'Language is required.')}, status=400) + return Response(json={'error': _('Language is required.')}, status=400) try: transcript_content, transcript_name, mime_type = get_transcript( @@ -576,9 +575,7 @@ class VideoStudioViewHandlers(object): response = Response(transcript_content, headerlist=[ ( 'Content-Disposition', - 'attachment; filename="{}"'.format( - transcript_name.encode('utf8') if six.PY2 else transcript_name - ) + f'attachment; filename="{transcript_name}"' ), ('Content-Language', language), ('Content-Type', mime_type) diff --git a/common/lib/xmodule/xmodule/video_module/video_module.py b/common/lib/xmodule/xmodule/video_module/video_module.py index f6048b811f..a5b3d07a66 100644 --- a/common/lib/xmodule/xmodule/video_module/video_module.py +++ b/common/lib/xmodule/xmodule/video_module/video_module.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Video is ungraded Xmodule for support video content. It's new improved video module, which support additional feature: - Can play non-YouTube video sources via in-browser HTML5 video player. @@ -20,7 +19,6 @@ import logging from collections import OrderedDict, defaultdict from operator import itemgetter -import six from django.conf import settings from edx_django_utils.cache import RequestCache from lxml import etree @@ -105,8 +103,8 @@ log = logging.getLogger(__name__) # `django.utils.translation.ugettext_noop` because Django cannot be imported in this file _ = lambda text: text -EXPORT_IMPORT_COURSE_DIR = u'course' -EXPORT_IMPORT_STATIC_DIR = u'static' +EXPORT_IMPORT_COURSE_DIR = 'course' +EXPORT_IMPORT_STATIC_DIR = 'static' @XBlock.wants('settings', 'completion', 'i18n', 'request_cache') @@ -338,7 +336,7 @@ class VideoBlock( if getattr(self, 'video_speed_optimizations', True) and cdn_url: branding_info = BrandingInfoConfig.get_config().get(self.system.user_location) - if self.edx_video_id and edxval_api and video_status != u'external': + if self.edx_video_id and edxval_api and video_status != 'external': for index, source_url in enumerate(sources): new_url = rewrite_video_url(cdn_url, source_url) if new_url: @@ -478,7 +476,7 @@ class VideoBlock( is the override of the general XBlock method, and it will also ask its superclass to validate. """ - validation = super(VideoBlock, self).validate() # lint-amnesty, pylint: disable=super-with-arguments + validation = super().validate() if not isinstance(validation, StudioValidation): validation = StudioValidation.copy(validation) @@ -564,7 +562,7 @@ class VideoBlock( @property def editable_metadata_fields(self): - editable_fields = super(VideoBlock, self).editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments + editable_fields = super().editable_metadata_fields settings_service = self.runtime.service(self, 'settings') if settings_service: @@ -593,7 +591,7 @@ class VideoBlock( possible_sub_ids = [self.sub, self.youtube_id_1_0] + get_html5_ids(self.html5_sources) for sub_id in possible_sub_ids: try: - _, sub_id, _ = get_transcript(self, lang=u'en', output_format=Transcript.TXT) + _, sub_id, _ = get_transcript(self, lang='en', output_format=Transcript.TXT) transcripts_info['transcripts'] = dict(transcripts_info['transcripts'], en=sub_id) break except NotFoundError: @@ -675,7 +673,7 @@ class VideoBlock( # Mild workaround to ensure that tests pass -- if a field # is set to its default value, we don't need to write it out. if youtube_string and youtube_string != '1.00:3_yD_cEKoCk': - xml.set('youtube', six.text_type(youtube_string)) + xml.set('youtube', str(youtube_string)) xml.set('url_name', self.url_name) attrs = [ ('display_name', self.display_name), @@ -692,13 +690,13 @@ class VideoBlock( if value: if key in self.fields and self.fields[key].is_set_on(self): # lint-amnesty, pylint: disable=unsubscriptable-object, unsupported-membership-test try: - xml.set(key, six.text_type(value)) + xml.set(key, str(value)) except UnicodeDecodeError: exception_message = format_xml_exception_message(self.location, key, value) log.exception(exception_message) # If exception is UnicodeDecodeError set value using unicode 'utf-8' scheme. log.info("Setting xml value using 'utf-8' scheme.") - xml.set(key, six.text_type(value, 'utf-8')) + xml.set(key, str(value, 'utf-8')) except ValueError: exception_message = format_xml_exception_message(self.location, key, value) log.exception(exception_message) @@ -740,7 +738,7 @@ class VideoBlock( video_id=edx_video_id, resource_fs=resource_fs, static_dir=EXPORT_IMPORT_STATIC_DIR, - course_id=six.text_type(self.runtime.course_id.for_branch(None)) + course_id=str(self.runtime.course_id.for_branch(None)) ) # Update xml with edxval metadata xml.append(exported_metadata['xml']) @@ -780,15 +778,15 @@ class VideoBlock( A full youtube url to the video whose ID is passed in """ if youtube_id: - return u'https://www.youtube.com/watch?v={0}'.format(youtube_id) + return f'https://www.youtube.com/watch?v={youtube_id}' else: - return u'' + return '' def get_context(self): """ Extend context by data for transcript basic tab. """ - _context = super(VideoBlock, self).get_context() # lint-amnesty, pylint: disable=super-with-arguments + _context = super().get_context() metadata_fields = copy.deepcopy(self.editable_metadata_fields) @@ -891,7 +889,7 @@ class VideoBlock( Arguments: id_generator is used to generate course-specific urls and identifiers """ - if isinstance(xml, six.string_types): + if isinstance(xml, str): xml = etree.fromstring(xml) field_data = {} @@ -937,7 +935,7 @@ class VideoBlock( normalized_speed = speed[:-1] if speed.endswith('0') else speed # If the user has specified html5 sources, make sure we don't use the default video if youtube_id != '' or 'html5_sources' in field_data: - field_data['youtube_id_{0}'.format(normalized_speed.replace('.', '_'))] = youtube_id + field_data['youtube_id_{}'.format(normalized_speed.replace('.', '_'))] = youtube_id elif attr in conversions: field_data[attr] = conversions[attr](value) elif attr not in cls.fields: # lint-amnesty, pylint: disable=unsupported-membership-test @@ -1016,7 +1014,7 @@ class VideoBlock( return edx_video_id def index_dictionary(self): - xblock_body = super(VideoBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments + xblock_body = super().index_dictionary() video_body = { "display_name": self.display_name, } @@ -1061,7 +1059,7 @@ class VideoBlock( """ Returns the VAL data for the requested video profiles for the given course. """ - return edxval_api.get_video_info_for_course_and_profiles(six.text_type(course_id), video_profile_names) + return edxval_api.get_video_info_for_course_and_profiles(str(course_id), video_profile_names) def student_view_data(self, context=None): """ diff --git a/common/lib/xmodule/xmodule/video_module/video_utils.py b/common/lib/xmodule/xmodule/video_module/video_utils.py index 19e27d4865..a8f091b14b 100644 --- a/common/lib/xmodule/xmodule/video_module/video_utils.py +++ b/common/lib/xmodule/xmodule/video_module/video_utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Module contains utils specific for video_module but not for transcripts. """ @@ -6,13 +5,11 @@ Module contains utils specific for video_module but not for transcripts. import logging from collections import OrderedDict +from urllib.parse import parse_qs, urlencode, urlparse, urlsplit, urlunsplit -import six from django.conf import settings from django.core.exceptions import ValidationError from django.core.validators import URLValidator -from six.moves import zip -from six.moves.urllib.parse import parse_qs, urlencode, urlparse, urlsplit, urlunsplit log = logging.getLogger(__name__) @@ -106,7 +103,7 @@ def format_xml_exception_message(location, key, value): when setting xml attributes. """ exception_message = "Block-location:{location}, Key:{key}, Value:{value}".format( - location=six.text_type(location), + location=str(location), key=key, value=value ) diff --git a/common/lib/xmodule/xmodule/video_module/video_xfields.py b/common/lib/xmodule/xmodule/video_module/video_xfields.py index 6430a1712f..d97fe0b3bf 100644 --- a/common/lib/xmodule/xmodule/video_module/video_xfields.py +++ b/common/lib/xmodule/xmodule/video_module/video_xfields.py @@ -14,7 +14,7 @@ from xmodule.fields import RelativeTime _ = lambda text: text -class VideoFields(object): +class VideoFields: """Fields for `VideoBlock`.""" display_name = String( help=_("The display name for this component."), diff --git a/common/lib/xmodule/xmodule/word_cloud_module.py b/common/lib/xmodule/xmodule/word_cloud_module.py index c1d63b39a8..4a72defa95 100644 --- a/common/lib/xmodule/xmodule/word_cloud_module.py +++ b/common/lib/xmodule/xmodule/word_cloud_module.py @@ -12,8 +12,6 @@ import logging from pkg_resources import resource_string -import six -from six.moves import map from web_fragments.fragment import Fragment from xblock.fields import Boolean, Dict, Integer, List, Scope, String from xmodule.editing_module import EditingMixin @@ -141,7 +139,7 @@ class WordCloudBlock( # pylint: disable=abstract-method def get_state(self): """Return success json answer for client.""" if self.submitted: - total_count = sum(six.itervalues(self.all_words)) + total_count = sum(self.all_words.values()) return json.dumps({ 'status': 'success', 'submitted': True, @@ -318,7 +316,7 @@ class WordCloudBlock( # pylint: disable=abstract-method # values may be numeric / string or dict # default implementation is an empty dict - xblock_body = super(WordCloudBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments + xblock_body = super().index_dictionary() index_body = { "display_name": self.display_name, diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 542b876327..e38c17c691 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -7,7 +7,6 @@ import time from collections import namedtuple from functools import partial -import six import yaml from contracts import contract, new_contract from django.utils.encoding import python_2_unicode_compatible @@ -16,8 +15,6 @@ from lxml import etree from opaque_keys.edx.asides import AsideDefinitionKeyV2, AsideUsageKeyV2 from opaque_keys.edx.keys import UsageKey from pkg_resources import resource_exists, resource_isdir, resource_listdir, resource_string -from six import text_type -from six.moves import map from web_fragments.fragment import Fragment from webob import Response from webob.multidict import MultiDict @@ -78,8 +75,8 @@ STUDIO_VIEW = 'studio_view' PREVIEW_VIEWS = [STUDENT_VIEW, PUBLIC_VIEW, AUTHOR_VIEW] DEFAULT_PUBLIC_VIEW_MESSAGE = ( - u'This content is only accessible to enrolled learners. ' - u'Sign in or register, and enroll in this course to view it.' + 'This content is only accessible to enrolled learners. ' + 'Sign in or register, and enroll in this course to view it.' ) # Make '_' a no-op so we can scrape strings. Using lambda instead of @@ -203,7 +200,7 @@ def dummy_track(_event_type, _event): pass -class HTMLSnippet(object): +class HTMLSnippet: """ A base class defining an interface for an object that is able to present an html snippet, along with associated javascript and css @@ -300,7 +297,7 @@ class HTMLSnippet(object): Return the html used to display this snippet """ raise NotImplementedError( - "get_html() must be provided by specific modules - not present in {0}" + "get_html() must be provided by specific modules - not present in {}" .format(self.__class__)) @@ -319,7 +316,7 @@ def shim_xmodule_js(fragment, js_module_name): add_webpack_to_fragment(fragment, 'XModuleShim') -class XModuleFields(object): +class XModuleFields: """ Common fields for XModules. """ @@ -369,7 +366,7 @@ class XModuleMixin(XModuleFields, XBlock): self.xmodule_runtime = None self._asides = [] - super(XModuleMixin, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) @property def runtime(self): @@ -484,8 +481,8 @@ class XModuleMixin(XModuleFields, XBlock): result[field.name] = field.read_json(self) except TypeError as exception: exception_message = "{message}, Block-location:{location}, Field-name:{field_name}".format( - message=text_type(exception), - location=text_type(self.location), + message=str(exception), + location=str(self.location), field_name=field.name ) raise TypeError(exception_message) # lint-amnesty, pylint: disable=raise-missing-from @@ -551,7 +548,7 @@ class XModuleMixin(XModuleFields, XBlock): return [ child for child - in super(XModuleMixin, self).get_children(usage_id_filter) # lint-amnesty, pylint: disable=super-with-arguments + in super().get_children(usage_id_filter) if child is not None ] @@ -561,9 +558,9 @@ class XModuleMixin(XModuleFields, XBlock): is an error while retrieving the block. """ try: - child = super(XModuleMixin, self).get_child(usage_id) # lint-amnesty, pylint: disable=super-with-arguments + child = super().get_child(usage_id) except ItemNotFoundError: - log.warning(u'Unable to load item %s, skipping', usage_id) + log.warning('Unable to load item %s, skipping', usage_id) return None if child is None: @@ -810,14 +807,14 @@ class XModuleMixin(XModuleFields, XBlock): Default message for blocks that don't implement public_view """ alert_html = HTML( - u'
' - u'' - u'
{}
' + '
' + '' + '
{}
' ) if self.display_name: display_text = _( - u'{display_name} is only accessible to enrolled learners. ' + '{display_name} is only accessible to enrolled learners. ' 'Sign in or register, and enroll in this course to view it.' ).format( display_name=self.display_name @@ -828,7 +825,7 @@ class XModuleMixin(XModuleFields, XBlock): return Fragment(alert_html.format(display_text)) -class ProxyAttribute(object): +class ProxyAttribute: """ A (python) descriptor that proxies attribute access. @@ -876,7 +873,7 @@ descriptor_attr = partial(ProxyAttribute, 'descriptor') # pylint: disable=inval module_runtime_attr = partial(ProxyAttribute, 'xmodule_runtime') # pylint: disable=invalid-name -class XModuleToXBlockMixin(object): +class XModuleToXBlockMixin: """ Common code needed by XModule and XBlocks converted from XModules. """ @@ -892,7 +889,7 @@ class XModuleToXBlockMixin(object): """ XBlock handler that wraps `handle_ajax` """ - class FileObjForWebobFiles(object): + class FileObjForWebobFiles: """ Turn Webob cgi.FieldStorage uploaded files into pure file objects. @@ -912,7 +909,7 @@ class XModuleToXBlockMixin(object): # WebOb requests have multiple entries for uploaded files. handle_ajax # expects a single entry as a list. request_post = MultiDict(request.POST) - for key in set(six.iterkeys(request.POST)): + for key in set(request.POST.keys()): if hasattr(request.POST[key], "file"): request_post[key] = list(map(FileObjForWebobFiles, request.POST.getall(key))) @@ -955,7 +952,7 @@ class XModule(XModuleToXBlockMixin, HTMLSnippet, XModuleMixin): # lint-amnesty, # Set the descriptor first so that we can proxy to it self.descriptor = descriptor self._runtime = None - super(XModule, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) self.runtime.xmodule_instance = self @property @@ -968,12 +965,12 @@ class XModule(XModuleToXBlockMixin, HTMLSnippet, XModuleMixin): # lint-amnesty, def __str__(self): # xss-lint: disable=python-wrap-html - return u''.format(self.id) # lint-amnesty, pylint: disable=no-member + return f'' # lint-amnesty, pylint: disable=no-member def handle_ajax(self, _dispatch, _data): """ dispatch is last part of the URL. data is a dictionary-like object with the content of the request""" - return u"" + return "" def get_child(self, usage_id): if usage_id in self._child_cache: @@ -1028,13 +1025,13 @@ def policy_key(location): Get the key for a location in a policy file. (Since the policy file is specific to a course, it doesn't need the full location url). """ - return u'{cat}/{name}'.format(cat=location.block_type, name=location.block_id) + return f'{location.block_type}/{location.block_id}' Template = namedtuple("Template", "metadata data children") -class ResourceTemplates(object): +class ResourceTemplates: """ Gets the templates associated w/ a containing cls. The cls must have a 'template_dir_name' attribute. It finds the templates as directly in this directory under 'templates'. @@ -1071,7 +1068,7 @@ class ResourceTemplates(object): if getattr(cls, 'template_dir_name', None): dirname = os.path.join('templates', cls.template_dir_name) # lint-amnesty, pylint: disable=no-member if not resource_isdir(__name__, dirname): - log.warning(u"No resource directory {dir} found when loading {cls_name} templates".format( + log.warning("No resource directory {dir} found when loading {cls_name} templates".format( dir=dirname, cls_name=cls.__name__, )) @@ -1099,7 +1096,7 @@ class ResourceTemplates(object): return template -class XModuleDescriptorToXBlockMixin(object): +class XModuleDescriptorToXBlockMixin: """ Common code needed by XModuleDescriptor and XBlocks converted from XModules. """ @@ -1133,9 +1130,9 @@ class XModuleDescriptorToXBlockMixin(object): legacy XModule code. Use the "normal" XBlock parsing code. """ try: - return super(XModuleDescriptorToXBlockMixin, cls).parse_xml_new_runtime(node, runtime, keys) + return super().parse_xml_new_runtime(node, runtime, keys) except AttributeError: - return super(XModuleDescriptorToXBlockMixin, cls).parse_xml(node, runtime, keys, id_generator=None) + return super().parse_xml(node, runtime, keys, id_generator=None) @classmethod def from_xml(cls, xml_data, system, id_generator): @@ -1226,7 +1223,7 @@ class XModuleDescriptor(XModuleDescriptorToXBlockMixin, HTMLSnippet, ResourceTem XModuleDescriptor.__init__ takes the same arguments as xblock.core:XBlock.__init__ """ - super(XModuleDescriptor, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) # update_version is the version which last updated this xblock v prev being the penultimate updater # leaving off original_version since it complicates creation w/o any obv value yet and is computable # by following previous until None @@ -1271,7 +1268,7 @@ class XModuleDescriptor(XModuleDescriptorToXBlockMixin, HTMLSnippet, ResourceTem performance if we have to rely on lists and equality rather than sets, dictionaries, and identity-based hash functions. """ - return super(XModuleDescriptor, self).__hash__() # lint-amnesty, pylint: disable=super-with-arguments + return super().__hash__() def __repr__(self): return ( @@ -1345,7 +1342,7 @@ class XModuleDescriptor(XModuleDescriptorToXBlockMixin, HTMLSnippet, ResourceTem return Fragment(self.get_html()) -class ConfigurableFragmentWrapper(object): +class ConfigurableFragmentWrapper: """ Runtime mixin that allows for composition of many `wrap_xblock` wrappers """ @@ -1357,7 +1354,7 @@ class ConfigurableFragmentWrapper(object): ... return wrapped_frag """ - super(ConfigurableFragmentWrapper, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) if wrappers is not None: self.wrappers = wrappers else: @@ -1411,7 +1408,7 @@ def descriptor_global_local_resource_url(block, uri): raise NotImplementedError("Applications must monkey-patch this function before using local_resource_url for studio_view") # lint-amnesty, pylint: disable=line-too-long -class MetricsMixin(object): +class MetricsMixin: """ Mixin for adding metric logging for render and handle methods in the DescriptorSystem and ModuleSystem. """ @@ -1420,7 +1417,7 @@ class MetricsMixin(object): start_time = time.time() try: status = "success" - return super(MetricsMixin, self).render(block, view_name, context=context) # lint-amnesty, pylint: disable=super-with-arguments + return super().render(block, view_name, context=context) except: status = "failure" @@ -1431,12 +1428,12 @@ class MetricsMixin(object): duration = end_time - start_time course_id = getattr(self, 'course_id', '') tags = [ # lint-amnesty, pylint: disable=unused-variable - u'view_name:{}'.format(view_name), - u'action:render', - u'action_status:{}'.format(status), - u'course_id:{}'.format(course_id), - u'block_type:{}'.format(block.scope_ids.block_type), - u'block_family:{}'.format(block.entry_point), + f'view_name:{view_name}', + 'action:render', + f'action_status:{status}', + f'course_id:{course_id}', + f'block_type:{block.scope_ids.block_type}', + f'block_family:{block.entry_point}', ] log.debug( "%.3fs - render %s.%s (%s)", @@ -1450,7 +1447,7 @@ class MetricsMixin(object): start_time = time.time() try: status = "success" - return super(MetricsMixin, self).handle(block, handler_name, request, suffix=suffix) # lint-amnesty, pylint: disable=super-with-arguments + return super().handle(block, handler_name, request, suffix=suffix) except: status = "failure" @@ -1461,12 +1458,12 @@ class MetricsMixin(object): duration = end_time - start_time course_id = getattr(self, 'course_id', '') tags = [ # lint-amnesty, pylint: disable=unused-variable - u'handler_name:{}'.format(handler_name), - u'action:handle', - u'action_status:{}'.format(status), - u'course_id:{}'.format(course_id), - u'block_type:{}'.format(block.scope_ids.block_type), - u'block_family:{}'.format(block.entry_point), + f'handler_name:{handler_name}', + 'action:handle', + f'action_status:{status}', + f'course_id:{course_id}', + f'block_type:{block.scope_ids.block_type}', + f'block_family:{block.entry_point}', ] log.debug( "%.3fs - handle %s.%s (%s)", @@ -1504,7 +1501,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): """ kwargs.setdefault('id_reader', OpaqueKeyReader()) kwargs.setdefault('id_generator', AsideKeyGenerator()) - super(DescriptorSystem, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) # This is used by XModules to write out separate files during xml export self.export_fs = None @@ -1529,7 +1526,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): """ if block_type in self.disabled_xblock_types(): return self.default_class - return super(DescriptorSystem, self).load_block_type(block_type) # lint-amnesty, pylint: disable=super-with-arguments + return super().load_block_type(block_type) def get_field_provenance(self, xblock, field): """ @@ -1576,7 +1573,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): """ See :meth:`xblock.runtime.Runtime:applicable_aside_types` for documentation. """ - potential_set = set(super(DescriptorSystem, self).applicable_aside_types(block)) # lint-amnesty, pylint: disable=super-with-arguments + potential_set = set(super().applicable_aside_types(block)) if getattr(block, 'xmodule_runtime', None) is not None: if hasattr(block.xmodule_runtime, 'applicable_aside_types'): application_set = set(block.xmodule_runtime.applicable_aside_types(block)) @@ -1613,7 +1610,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): An object implementing the requested service, or None. """ # getting the service from parent module. making sure of block service declarations. - service = super(DescriptorSystem, self).service(block=block, service_name=service_name) # lint-amnesty, pylint: disable=super-with-arguments + service = super().service(block=block, service_name=service_name) # Passing the block to service if it is callable e.g. ModuleI18nService. It is the responsibility of calling # service to handle the passing argument. if callable(service): @@ -1631,7 +1628,7 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr created from that xml """ - super(XMLParsingSystem, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) self.process_xml = process_xml def _usage_id_from_node(self, node, parent_id, id_generator=None): @@ -1724,7 +1721,7 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr """ course_key = xblock.scope_ids.usage_id.course_key - for field in six.itervalues(xblock.fields): + for field in xblock.fields.values(): if field.is_set_on(xblock): field_value = getattr(xblock, field.name) if field_value is None: @@ -1734,8 +1731,8 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr elif isinstance(field, ReferenceList): setattr(xblock, field.name, [self._make_usage_key(course_key, ele) for ele in field_value]) elif isinstance(field, ReferenceValueDict): - for key, subvalue in six.iteritems(field_value): - assert isinstance(subvalue, six.string_types) + for key, subvalue in field_value.items(): + assert isinstance(subvalue, str) field_value[key] = self._make_usage_key(course_key, subvalue) setattr(xblock, field.name, field_value) @@ -1833,7 +1830,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # explicit field_data during construct_xblock. kwargs.setdefault('id_reader', getattr(descriptor_runtime, 'id_reader', OpaqueKeyReader())) kwargs.setdefault('id_generator', getattr(descriptor_runtime, 'id_generator', AsideKeyGenerator())) - super(ModuleSystem, self).__init__(field_data=field_data, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(field_data=field_data, **kwargs) self.STATIC_URL = static_url self.xqueue = xqueue @@ -1885,7 +1882,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # Remove value set transiently by XBlock kwargs.pop('_view_name') - return "{}{}".format(self.__class__.__name__, kwargs) + return f"{self.__class__.__name__}{kwargs}" @property def ajax_url(self): @@ -1919,7 +1916,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): An object implementing the requested service, or None. """ # getting the service from parent module. making sure of block service declarations. - service = super(ModuleSystem, self).service(block=block, service_name=service_name) # lint-amnesty, pylint: disable=super-with-arguments + service = super().service(block=block, service_name=service_name) # Passing the block to service if it is callable e.g. ModuleI18nService. It is the responsibility of calling # service to handle the passing argument. if callable(service): @@ -1927,7 +1924,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): return service -class CombinedSystem(object): +class CombinedSystem: """ This class is a shim to allow both pure XBlocks and XModuleDescriptors that have been bound as XModules to access both the attributes of ModuleSystem @@ -2029,7 +2026,7 @@ class CombinedSystem(object): Always set the attr on the DescriptorSystem. """ if name in self.__slots__: - return super(CombinedSystem, self).__setattr__(name, value) # lint-amnesty, pylint: disable=super-with-arguments + return super().__setattr__(name, value) if self._module_system: setattr(self._module_system, name, value) @@ -2045,10 +2042,10 @@ class CombinedSystem(object): delattr(self._descriptor_system, name) def __repr__(self): - return "CombinedSystem({!r}, {!r})".format(self._module_system, self._descriptor_system) + return f"CombinedSystem({self._module_system!r}, {self._descriptor_system!r})" -class DoNothingCache(object): +class DoNothingCache: """A duck-compatible object to use in ModuleSystem when there's no cache.""" def get(self, _key): return None diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py index 3ff5997edb..e590da91eb 100644 --- a/common/lib/xmodule/xmodule/xml_module.py +++ b/common/lib/xmodule/xmodule/xml_module.py @@ -45,9 +45,9 @@ def is_pointer_tag(xml_obj): Returns a bool. """ if xml_obj.tag != "course": - expected_attr = set(['url_name']) + expected_attr = {'url_name'} else: - expected_attr = set(['url_name', 'course', 'org']) + expected_attr = {'url_name', 'course', 'org'} actual_attr = set(xml_obj.attrib.keys()) @@ -63,7 +63,7 @@ def serialize_field(value): If the value is a string, then we simply return what was passed in. Otherwise, we return json.dumps on the input value. """ - if isinstance(value, six.string_types): + if isinstance(value, str): return value return json.dumps(value, cls=EdxJSONEncoder) @@ -101,7 +101,7 @@ def deserialize_field(field, value): return value -class XmlParserMixin(object): +class XmlParserMixin: """ Class containing XML parsing functionality shared between XBlock and XModuleDescriptor. """ @@ -208,7 +208,7 @@ class XmlParserMixin(object): return cls.file_to_xml(xml_file) except Exception as err: # lint-amnesty, pylint: disable=broad-except # Add info about where we are, but keep the traceback - msg = 'Unable to load file contents at path %s for item %s: %s ' % ( + msg = 'Unable to load file contents at path {} for item {}: {} '.format( filepath, def_id, err) six.reraise(Exception, msg, sys.exc_info()[2]) @@ -275,7 +275,7 @@ class XmlParserMixin(object): Returns a dictionary {key: value}. """ metadata = {'xml_attributes': {}} - for attr, val in six.iteritems(xml_object.attrib): + for attr, val in xml_object.attrib.items(): # VS[compat]. Remove after all key translations done attr = cls._translate(attr) @@ -295,7 +295,7 @@ class XmlParserMixin(object): Add the keys in policy to metadata, after processing them through the attrmap. Updates the metadata dict in place. """ - for attr, value in six.iteritems(policy): + for attr, value in policy.items(): attr = cls._translate(attr) if attr not in cls.fields: # Store unknown attributes coming from policy.json @@ -400,9 +400,9 @@ class XmlParserMixin(object): legacy XModule code. Use the "normal" XBlock parsing code. """ try: - return super(XmlParserMixin, cls).parse_xml_new_runtime(node, runtime, keys) + return super().parse_xml_new_runtime(node, runtime, keys) except AttributeError: - return super(XmlParserMixin, cls).parse_xml(node, runtime, keys, id_generator=None) + return super().parse_xml(node, runtime, keys, id_generator=None) @classmethod def _get_url_name(cls, node): @@ -423,9 +423,7 @@ class XmlParserMixin(object): @classmethod def _format_filepath(cls, category, name): - return u'{category}/{name}.{ext}'.format(category=category, - name=name, - ext=cls.filename_extension) + return f'{category}/{name}.{cls.filename_extension}' def export_to_file(self): """If this returns True, write the definition of this descriptor to a separate @@ -472,7 +470,7 @@ class XmlParserMixin(object): xml_object.set(attr, val) except Exception: # lint-amnesty, pylint: disable=broad-except logging.exception( - u'Failed to serialize metadata attribute %s with value %s in module %s. This could mean data loss!!!', # lint-amnesty, pylint: disable=line-too-long + 'Failed to serialize metadata attribute %s with value %s in module %s. This could mean data loss!!!', # lint-amnesty, pylint: disable=line-too-long attr, val, self.url_name ) @@ -520,7 +518,7 @@ class XmlParserMixin(object): """ Return a list of all metadata fields that cannot be edited. """ - non_editable_fields = super(XmlParserMixin, self).non_editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments + non_editable_fields = super().non_editable_metadata_fields non_editable_fields.append(XmlParserMixin.xml_attributes) return non_editable_fields @@ -551,7 +549,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method # This only exists to satisfy subclasses that both: # a) define from_xml themselves # b) call super(..).from_xml(..) - return super(XmlMixin, cls).parse_xml( + return super().parse_xml( etree.fromstring(xml_data), system, None, # This is ignored by XmlParserMixin @@ -568,7 +566,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method # from XModuleDescriptor, which actually calls `from_xml`. return super(XmlParserMixin, cls).parse_xml(node, runtime, keys, id_generator) # pylint: disable=bad-super-call else: - return super(XmlMixin, cls).parse_xml(node, runtime, keys, id_generator) + return super().parse_xml(node, runtime, keys, id_generator) @classmethod def parse_xml_new_runtime(cls, node, runtime, keys): @@ -577,9 +575,9 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method legacy XModule code. Use the "normal" XBlock parsing code. """ try: - return super(XmlMixin, cls).parse_xml_new_runtime(node, runtime, keys) + return super().parse_xml_new_runtime(node, runtime, keys) except AttributeError: - return super(XmlMixin, cls).parse_xml(node, runtime, keys, id_generator=None) + return super().parse_xml(node, runtime, keys, id_generator=None) def export_to_xml(self, resource_fs): # lint-amnesty, pylint: disable=unused-argument """ @@ -599,7 +597,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method # a) define export_to_xml themselves # b) call super(..).export_to_xml(..) node = Element(self.category) - super(XmlMixin, self).add_xml_to_node(node) # lint-amnesty, pylint: disable=super-with-arguments + super().add_xml_to_node(node) return etree.tostring(node) def add_xml_to_node(self, node): @@ -612,7 +610,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method # from XModuleDescriptor, which actually calls `export_to_xml`. super(XmlParserMixin, self).add_xml_to_node(node) # pylint: disable=bad-super-call else: - super(XmlMixin, self).add_xml_to_node(node) # lint-amnesty, pylint: disable=super-with-arguments + super().add_xml_to_node(node) class XmlDescriptor(XmlMixin, XModuleDescriptor): # lint-amnesty, pylint: disable=abstract-method