diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py index cf6be0955fd9a7acea6a57e5d5bec63e4b6257ce..baebc10a429e9eca990150dfdc9fd2dda8bb2c21 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py @@ -1,4 +1,3 @@ -# encoding: utf-8 """ Modulestore configuration for test cases. """ @@ -9,14 +8,13 @@ import functools import os from contextlib import contextmanager from enum import Enum +from unittest.mock import patch from django.conf import settings from django.contrib.auth.models import AnonymousUser, User # lint-amnesty, pylint: disable=imported-auth-user from django.db import connections from django.test import TestCase from django.test.utils import override_settings -from mock import patch -from six.moves import range from lms.djangoapps.courseware.tests.factories import StaffFactory from lms.djangoapps.courseware.field_overrides import OverrideFieldData @@ -43,7 +41,7 @@ class CourseUserType(Enum): UNENROLLED_STAFF = 'unenrolled_staff' -class StoreConstructors(object): +class StoreConstructors: """Enumeration of store constructor types.""" draft, split = list(range(2)) @@ -108,7 +106,7 @@ def draft_mongo_store_config(data_dir): 'DOC_STORE_CONFIG': { 'host': MONGO_HOST, 'port': MONGO_PORT_NUM, - 'db': 'test_xmodule_{}'.format(os.getpid()), + 'db': f'test_xmodule_{os.getpid()}', 'collection': 'modulestore', }, 'OPTIONS': modulestore_options @@ -135,7 +133,7 @@ def split_mongo_store_config(data_dir): 'DOC_STORE_CONFIG': { 'host': MONGO_HOST, 'port': MONGO_PORT_NUM, - 'db': 'test_xmodule_{}'.format(os.getpid()), + 'db': f'test_xmodule_{os.getpid()}', 'collection': 'modulestore', }, 'OPTIONS': modulestore_options @@ -154,7 +152,7 @@ def contentstore_config(): 'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore', 'DOC_STORE_CONFIG': { 'host': MONGO_HOST, - 'db': 'test_xcontent_{}'.format(os.getpid()), + 'db': f'test_xcontent_{os.getpid()}', 'port': MONGO_PORT_NUM, }, # allow for additional options that can be keyed on a name, e.g. 'trashcan' @@ -210,7 +208,7 @@ TEST_DATA_SPLIT_MODULESTORE = functools.partial( ) -class SignalIsolationMixin(object): +class SignalIsolationMixin: """ Simple utility mixin class to toggle ModuleStore signals on and off. This class operates on `SwitchedSignal` objects on the modulestore's @@ -421,7 +419,7 @@ class SharedModuleStoreTestCase( # Now yield to allow the test class to run its setUpClass() setup code. yield # Now call the base class, which calls back into the test class's setUpTestData(). - super(SharedModuleStoreTestCase, cls).setUpClass() + super().setUpClass() @classmethod def setUpClass(cls): @@ -429,19 +427,19 @@ class SharedModuleStoreTestCase( Start modulestore isolation, and then load modulestore specific test data. """ - super(SharedModuleStoreTestCase, cls).setUpClass() + super().setUpClass() cls.start_modulestore_isolation() @classmethod def tearDownClass(cls): cls.end_modulestore_isolation() - super(SharedModuleStoreTestCase, cls).tearDownClass() + super().tearDownClass() def setUp(self): # OverrideFieldData.provider_classes is always reset to `None` so # that they're recalculated for every test OverrideFieldData.provider_classes = None - super(SharedModuleStoreTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() class ModuleStoreTestCase( @@ -491,11 +489,11 @@ class ModuleStoreTestCase( @classmethod def setUpClass(cls): - super(ModuleStoreTestCase, cls).setUpClass() + super().setUpClass() @classmethod def tearDownClass(cls): - super(ModuleStoreTestCase, cls).tearDownClass() + super().tearDownClass() def setUp(self): """ @@ -511,7 +509,7 @@ class ModuleStoreTestCase( # that they're recalculated for every test OverrideFieldData.provider_classes = None - super(ModuleStoreTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.store = modulestore() diff --git a/common/lib/xmodule/xmodule/modulestore/tests/factories.py b/common/lib/xmodule/xmodule/modulestore/tests/factories.py index 37675dd84f9c6631b085e396593eedaf3e013334..7717581dd9bd9a37392a04289796943862cbb756 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/factories.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/factories.py @@ -11,13 +11,12 @@ import traceback from collections import defaultdict from contextlib import contextmanager from uuid import uuid4 -import pytz +from unittest.mock import patch import pymongo.message -import six +import pytz from factory import Factory, Sequence, lazy_attribute, lazy_attribute_sequence from factory.errors import CyclicDefinitionError -from mock import patch from opaque_keys.edx.keys import UsageKey from opaque_keys.edx.locator import BlockUsageLocator from xblock.core import XBlock @@ -31,7 +30,7 @@ from xmodule.tabs import CourseTab LOG = logging.getLogger(__name__) -class Dummy(object): +class Dummy: pass @@ -45,7 +44,7 @@ class XModuleFactoryLock(threading.local): will be called. """ def __init__(self): - super(XModuleFactoryLock, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() self._enabled = False def enable(self): @@ -81,7 +80,7 @@ class XModuleFactory(Factory): # We have to give a model for Factory. # However, the class that we create is actually determined by the category # specified in the factory - class Meta(object): + class Meta: model = Dummy @lazy_attribute @@ -155,7 +154,7 @@ class SampleCourseFactory(CourseFactory): user_id = kwargs.get('user_id', ModuleStoreEnum.UserID.test) with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, None): - course = super(SampleCourseFactory, cls)._create(target_class, **kwargs) + course = super()._create(target_class, **kwargs) def create_sub_tree(parent_loc, block_info): """Recursively creates a sub_tree on this parent_loc with this block.""" @@ -216,7 +215,7 @@ class ToyCourseFactory(SampleCourseFactory): } fields.update(kwargs) - toy_course = super(ToyCourseFactory, cls)._create( + toy_course = super()._create( target_class, **fields ) @@ -292,9 +291,9 @@ class ItemFactory(XModuleFactory): @lazy_attribute_sequence def display_name(self, n): # lint-amnesty, pylint: disable=missing-function-docstring if self.descriptive_tag: - return "{} {} - {}".format(self.category, n, self.descriptive_tag) + return f"{self.category} {n} - {self.descriptive_tag}" else: - return "{} {}".format(self.category, n) + return f"{self.category} {n}" @lazy_attribute def location(self): # lint-amnesty, pylint: disable=missing-function-docstring @@ -389,7 +388,7 @@ class ItemFactory(XModuleFactory): template = clz.get_template(template_id) assert template is not None metadata.update(template.get('metadata', {})) - if not isinstance(data, six.string_types): + if not isinstance(data, str): data.update(template.get('data')) # replace the display name with an optional parameter passed in from the caller @@ -464,7 +463,7 @@ def check_number_of_calls(object_with_method, method_name, maximum_calls, minimu ) -class StackTraceCounter(object): +class StackTraceCounter: """ A class that counts unique stack traces underneath a particular stack frame. """ @@ -505,13 +504,13 @@ class StackTraceCounter(object): try: safe_args.append(repr(arg)) except Exception as exc: - safe_args.append('<un-repr-able value: {}'.format(exc)) + safe_args.append(f'<un-repr-able value: {exc}') safe_kwargs = {} for key, kwarg in kwargs.items(): try: safe_kwargs[key] = repr(kwarg) except Exception as exc: - safe_kwargs[key] = '<un-repr-able value: {}'.format(exc) + safe_kwargs[key] = f'<un-repr-able value: {exc}' self._stacks[tuple(stack)][tuple(safe_args), tuple(safe_kwargs.items())] += 1 else: @@ -612,8 +611,8 @@ def check_sum_of_calls(object_, methods, maximum_calls, minimum_calls=1, include messages.append("\n\n") if include_arguments: for (args, kwargs), count in stack_counter[stack].items(): - messages.append(" called {} times with:\n".format(count)) - messages.append(" args: {}\n".format(args)) + messages.append(f" called {count} times with:\n") + messages.append(f" args: {args}\n") messages.append(" kwargs: {}\n\n".format(dict(kwargs))) # verify that we called the methods within the desired range diff --git a/common/lib/xmodule/xmodule/modulestore/tests/sample_courses.py b/common/lib/xmodule/xmodule/modulestore/tests/sample_courses.py index f2fb7ab50632b5ddc318092dec0abbee6feb96e5..a94f7834a99da9954c5e99475cabb57efa8cbadd 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/sample_courses.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/sample_courses.py @@ -1,4 +1,3 @@ -# encoding: utf-8 """ The data type and use of it for declaratively creating test courses. """ @@ -67,7 +66,7 @@ TOY_BLOCK_INFO_TREE = [ ), BlockInfo( "toyjumpto", "html", { - "data": u"<a href=\"/jump_to_id/vertical_test\">This is a link to another page and some Chinese 四節比分和七年å‰</a> <p>Some more Chinese 四節比分和七年å‰</p>\n", # lint-amnesty, pylint: disable=line-too-long + "data": "<a href=\"/jump_to_id/vertical_test\">This is a link to another page and some Chinese 四節比分和七年å‰</a> <p>Some more Chinese 四節比分和七年å‰</p>\n", # lint-amnesty, pylint: disable=line-too-long "xml_attributes": {"filename": ["html/toyjumpto.xml", "html/toyjumpto.xml"]} }, []), BlockInfo( @@ -129,7 +128,7 @@ TOY_BLOCK_INFO_TREE = [ "poll_test", "chapter", {}, [ BlockInfo( "T1_changemind_poll_foo", "poll_question", { - "question": u"<p>Have you changed your mind? ’</p>", + "question": "<p>Have you changed your mind? ’</p>", "answers": [{"text": "Yes", "id": "yes"}, {"text": "No", "id": "no"}], "xml_attributes": {"reset": "false", "filename": ["", None]}, "display_name": "Change your answer" @@ -177,7 +176,7 @@ TOY_BLOCK_INFO_TREE = [ }, []), ]), BlockInfo("unicode", "html", { - "data": u"…", "xml_attributes": {"filename": ["", None]} + "data": "…", "xml_attributes": {"filename": ["", None]} }, []) ]), ] diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_asides.py b/common/lib/xmodule/xmodule/modulestore/tests/test_asides.py index e336621c2e928f4f2af9410ea2a435dd22ed613d..052fc6637e61c8e28598cfac0be7de12c9d38c99 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_asides.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_asides.py @@ -4,8 +4,8 @@ Tests for Asides from unittest import TestCase +from unittest.mock import patch -from mock import patch from web_fragments.fragment import Fragment from xblock.core import XBlockAside from xblock.fields import Scope, String @@ -17,7 +17,7 @@ class AsideTestType(XBlockAside): """ Test Aside type """ - FRAG_CONTENT = u"<p>Aside rendered</p>" + FRAG_CONTENT = "<p>Aside rendered</p>" content = String(default="default_content", scope=Scope.content) data_field = String(default="default_data", scope=Scope.settings) @@ -45,11 +45,11 @@ class TestAsidesXmlStore(TestCase): Check whether block has the expected aside w/ its fields and then recurse to the block's children """ asides = block.runtime.get_asides(block) - assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides) + assert len(asides) == 1, f'Found {asides} asides but expected only test_aside' assert isinstance(asides[0], AsideTestType) category = block.scope_ids.block_type - assert asides[0].data_field == '{} aside data'.format(category) - assert asides[0].content == '{} Aside'.format(category.capitalize()) + assert asides[0].data_field == f'{category} aside data' + assert asides[0].content == f'{category.capitalize()} Aside' for child in block.get_children(): check_block(child) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_assetstore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_assetstore.py index 24ff7f5569a75806702c0edfebf56a3f34a32655..04521b5d605825a55a93e29179d24c2ce42331fd 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_assetstore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_assetstore.py @@ -9,12 +9,10 @@ from datetime import datetime, timedelta import pytest import ddt import pytz -import six from django.test import TestCase from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import CourseLocator -from six.moves import range, zip from openedx.core.lib.tests import attr from xmodule.assetstore import AssetMetadata @@ -29,16 +27,13 @@ from xmodule.modulestore.tests.utils import ( ) -class AssetStoreTestData(object): +class AssetStoreTestData: """ Shared data for constructing test assets. """ now = datetime.now(pytz.utc) user_id = 144 - if six.PY2: - user_id_long = long(user_id) # lint-amnesty, pylint: disable=undefined-variable - else: - user_id_long = int(user_id) + user_id_long = int(user_id) user_email = "me@example.com" @@ -75,7 +70,7 @@ class TestSortedAssetList(unittest.TestCase): """ def setUp(self): - super(TestSortedAssetList, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() asset_list = [dict(list(zip(AssetStoreTestData.asset_fields, asset))) for asset in AssetStoreTestData.all_asset_data] # lint-amnesty, pylint: disable=line-too-long self.sorted_asset_list_by_filename = SortedAssetList(iterable=asset_list) self.sorted_asset_list_by_last_edit = SortedAssetList(iterable=asset_list, key=lambda x: x['edited_on']) @@ -105,7 +100,7 @@ class TestMongoAssetMetadataStorage(TestCase): } def setUp(self): - super(TestMongoAssetMetadataStorage, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.differents = (('different', 'burn.jpg'),) self.vrmls = ( @@ -560,7 +555,7 @@ class TestMongoAssetMetadataStorage(TestCase): course1.id, None, start=0, maxresults=-1, sort=('displayname', ModuleStoreEnum.SortOrder.ascending) ) - assert len(assets) == len((self.differents + self.vrmls)) + assert len(assets) == len(self.differents + self.vrmls) self._check_asset_values(assets, self.differents + self.vrmls) @ddt.data(*MODULESTORE_SETUPS) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_contentstore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_contentstore.py index 3b78556bd8e5da31e6ce358b3d9d21b5d33aeaa5..b167bc221df59fdd59a3db151ed708122487467a 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_contentstore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_contentstore.py @@ -52,7 +52,7 @@ class TestContentstore(unittest.TestCase): CourseLocator.deprecated = cls.ssck_deprecated else: del CourseLocator.deprecated - return super(TestContentstore, cls).tearDownClass() + return super().tearDownClass() def set_up_assets(self, deprecated): """ @@ -86,7 +86,7 @@ class TestContentstore(unittest.TestCase): """ Load and save the given file. """ - with open("{}/static/{}".format(DATA_DIR, filename), "rb") as f: + with open(f"{DATA_DIR}/static/{filename}", "rb") as f: content = StaticContent( asset_key, displayname, mimetypes.guess_type(filename)[0], f.read(), locked=locked @@ -115,9 +115,9 @@ class TestContentstore(unittest.TestCase): """ self.set_up_assets(deprecated) asset_key = self.course1_key.make_asset_key('asset', self.course1_files[0]) - assert self.contentstore.find(asset_key) is not None, 'Could not find {}'.format(asset_key) + assert self.contentstore.find(asset_key) is not None, f'Could not find {asset_key}' - assert self.contentstore.find(asset_key, as_stream=True) is not None, 'Could not find {}'.format(asset_key) + assert self.contentstore.find(asset_key, as_stream=True) is not None, f'Could not find {asset_key}' unknown_asset = self.course1_key.make_asset_key('asset', 'no_such_file.gif') with pytest.raises(NotFoundError): @@ -139,11 +139,11 @@ class TestContentstore(unittest.TestCase): ) for filename in self.course1_files: filepath = path.Path(root_dir / filename) - assert filepath.isfile(), '{} is not a file'.format(filepath) + assert filepath.isfile(), f'{filepath} is not a file' for filename in self.course2_files: if filename not in self.course1_files: filepath = path.Path(root_dir / filename) - assert not filepath.isfile(), '{} is unexpected exported a file'.format(filepath) + assert not filepath.isfile(), f'{filepath} is unexpected exported a file' finally: shutil.rmtree(root_dir) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py b/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py index f44516b02db7bf7fddf85476c6ace29f6831a4f2..49f607e43963d6566155a4e3d600aec01b0ef5bf 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_cross_modulestore_import_export.py @@ -17,9 +17,9 @@ import itertools import os from shutil import rmtree from tempfile import mkdtemp +from unittest.mock import patch import ddt -from mock import patch from path import Path as path from openedx.core.lib.tests import attr @@ -43,7 +43,7 @@ COURSE_DATA_NAMES = ( 'split_test_module_draft', ) -EXPORTED_COURSE_DIR_NAME = u'exported_source_course' +EXPORTED_COURSE_DIR_NAME = 'exported_source_course' @ddt.ddt @@ -55,7 +55,7 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest, PartitionTestCase): """ def setUp(self): - super(CrossStoreXMLRoundtrip, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.export_dir = mkdtemp() self.addCleanup(rmtree, self.export_dir, ignore_errors=True) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_inheritance.py b/common/lib/xmodule/xmodule/modulestore/tests/test_inheritance.py index 3a1e27972c2e188068458e0d202d058dcb2a1768..eb98cbc4f9f9116c1e5d2a32efd4c9c97ec81307 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_inheritance.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_inheritance.py @@ -4,10 +4,10 @@ Unit tests for testing inheritance mixins import unittest +from unittest.mock import Mock import ddt from django.utils.timezone import now, timedelta -from mock import Mock from xblock.core import XBlock from xblock.fields import ScopeIds from xblock.test.tools import TestRuntime @@ -38,7 +38,7 @@ class TestInheritanceMixin(unittest.TestCase): self.xblock = runtime.construct_xblock_from_class( TestXBlock, ScopeIds('user', 'TestXBlock', 'def_id', 'usage_id') ) - super(TestInheritanceMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() def add_submission_deadline_information(self, due_date, graceperiod, self_paced): """ diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py index 0ea137fc94ed9bd7f24532543c7e35abb5e09841..6cb17268a740faa6b9ae95e4fd8fc47ae9ea0171 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_libraries.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Basic unit tests related to content libraries. @@ -7,10 +6,8 @@ Higher-level tests are in `cms/djangoapps/contentstore`. import pytest import ddt -import six from bson.objectid import ObjectId from opaque_keys.edx.locator import LibraryLocator -from six.moves import range from xmodule.modulestore.exceptions import DuplicateCourseError from xmodule.modulestore.tests.factories import ItemFactory, LibraryFactory, check_mongo_calls @@ -50,15 +47,15 @@ class TestLibraries(MixedSplitTestCase): @ddt.data( "This is a test library!", - u"ΩμÎγα Βιβλιοθήκη", + "ΩμÎγα Βιβλιοθήκη", ) def test_str_repr(self, name): """ Test __unicode__() and __str__() methods of libraries """ library = LibraryFactory.create(metadata={"display_name": name}, modulestore=self.store) - assert name in six.text_type(library) - if not isinstance(name, six.text_type): + assert name in str(library) + if not isinstance(name, str): assert name in str(library) def test_display_with_default_methods(self): @@ -155,7 +152,7 @@ class TestLibraries(MixedSplitTestCase): def test_get_libraries(self): """ Test get_libraries() """ libraries = [LibraryFactory.create(modulestore=self.store) for _ in range(3)] - lib_dict = dict([(lib.location.library_key, lib) for lib in libraries]) # lint-amnesty, pylint: disable=consider-using-dict-comprehension + lib_dict = {lib.location.library_key: lib for lib in libraries} lib_list = self.store.get_libraries() diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py index d03fdfa2f49b14c517829253f548e692f5a391ba..b983a6b79f4d8e6aa8f763fd943351643c04c13f 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py @@ -12,20 +12,18 @@ from contextlib import contextmanager from shutil import rmtree from tempfile import mkdtemp from uuid import uuid4 +from unittest.mock import Mock, call, patch import ddt import pymongo import pytest -import six # Mixed modulestore depends on django, so we'll manually configure some django settings # before importing the module # TODO remove this import and the configuration -- xmodule should not depend on django! from django.conf import settings -from mock import Mock, call, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator, LibraryLocator from pytz import UTC -from six.moves import range from web_fragments.fragment import Fragment from xblock.core import XBlockAside from xblock.fields import Scope, ScopeIds, String @@ -121,7 +119,7 @@ class CommonMixedModuleStoreSetup(CourseComparisonTest): """ Set up the database for testing """ - super(CommonMixedModuleStoreSetup, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.exclude_field(None, 'wiki_slug') self.exclude_field(None, 'xml_attributes') @@ -281,7 +279,7 @@ class AsideFoo(XBlockAside): """ Test xblock aside class """ - FRAG_CONTENT = u"<p>Aside Foo rendered</p>" + FRAG_CONTENT = "<p>Aside Foo rendered</p>" field11 = String(default="aside1_default_value1", scope=Scope.content) field12 = String(default="aside1_default_value2", scope=Scope.settings) @@ -296,7 +294,7 @@ class AsideBar(XBlockAside): """ Test xblock aside class """ - FRAG_CONTENT = u"<p>Aside Bar rendered</p>" + FRAG_CONTENT = "<p>Aside Bar rendered</p>" field21 = String(default="aside2_default_value1", scope=Scope.content) field22 = String(default="aside2_default_value2", scope=Scope.settings) @@ -483,7 +481,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): items = self.store.get_items(course_key) # Check items found are either course or about type - assert set(['course', 'about']).issubset(set([item.location.block_type for item in items])) # pylint: disable=consider-using-set-comprehension, line-too-long + assert {'course', 'about'}.issubset({item.location.block_type for item in items}) # pylint: disable=line-too-long # Assert that about is a detached category found in get_items assert [item.location.block_type for item in items if item.location.block_type == 'about'][0]\ in DETACHED_XBLOCK_TYPES @@ -511,7 +509,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): items_in_tree = self.store.get_items(course_key, include_orphans=False) # Check that course and about blocks are found in get_items - assert set(['course', 'about']).issubset({item.location.block_type for item in items_in_tree}) + assert {'course', 'about'}.issubset({item.location.block_type for item in items_in_tree}) # Check orphan is found or not - this is based on mongo/split modulestore. It should be found in mongo. assert (orphan in [item.location for item in items_in_tree]) == orphan_in_items assert len(items_in_tree) == expected_items_in_tree @@ -1046,7 +1044,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): with check_mongo_calls(max_find, max_send): courses = self.store.get_courses() course_ids = [course.location for course in courses] - assert len(courses) == 1, 'Not one course: {}'.format(course_ids) + assert len(courses) == 1, f'Not one course: {course_ids}' assert self.course_locations[self.MONGO_COURSEID] in course_ids with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred): @@ -1608,7 +1606,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): # add another parent (unit) "vertical_x1b" for problem "problem_x1a_1" mongo_store.collection.update_one( self.vertical_x1b.to_deprecated_son('_id.'), # lint-amnesty, pylint: disable=no-member - {'$push': {'definition.children': six.text_type(self.problem_x1a_1)}} # lint-amnesty, pylint: disable=no-member + {'$push': {'definition.children': str(self.problem_x1a_1)}} # lint-amnesty, pylint: disable=no-member ) # convert first parent (unit) "vertical_x1a" of problem "problem_x1a_1" to draft @@ -1647,7 +1645,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): should_work = ( (self.problem_x1a_2, # lint-amnesty, pylint: disable=no-member - (course_key, u"Chapter_x", u"Sequential_x1", u'Vertical_x1a', '1', self.problem_x1a_2)), # lint-amnesty, pylint: disable=no-member + (course_key, "Chapter_x", "Sequential_x1", 'Vertical_x1a', '1', self.problem_x1a_2)), # lint-amnesty, pylint: disable=no-member (self.chapter_x, # lint-amnesty, pylint: disable=no-member (course_key, "Chapter_x", None, None, None, self.chapter_x)), # lint-amnesty, pylint: disable=no-member ) @@ -1908,7 +1906,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): with check_mongo_calls(max_find, max_send): found_orphans = self.store.get_orphans(self.course_locations[self.MONGO_COURSEID].course_key) - six.assertCountEqual(self, found_orphans, orphan_locations) + self.assertCountEqual(found_orphans, orphan_locations) @ddt.data(ModuleStoreEnum.Type.mongo) def test_get_non_orphan_parents(self, default_ms): @@ -1948,11 +1946,11 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): # add orphan vertical and sequential as another parents of problem "problem_x1a_1" mongo_store.collection.update_one( orphan_sequential.to_deprecated_son('_id.'), - {'$push': {'definition.children': six.text_type(self.problem_x1a_1)}} # lint-amnesty, pylint: disable=no-member + {'$push': {'definition.children': str(self.problem_x1a_1)}} # lint-amnesty, pylint: disable=no-member ) mongo_store.collection.update_one( orphan_vertical.to_deprecated_son('_id.'), - {'$push': {'definition.children': six.text_type(self.problem_x1a_1)}} # lint-amnesty, pylint: disable=no-member + {'$push': {'definition.children': str(self.problem_x1a_1)}} # lint-amnesty, pylint: disable=no-member ) # test that "get_parent_location" method of published branch still returns the correct non-orphan parent for # problem "problem_x1a_1" since the two other parents are orphans @@ -1961,7 +1959,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): assert parent == self.vertical_x1a # lint-amnesty, pylint: disable=no-member # now add valid published vertical as another parent of problem - mongo_store.collection.update_one(self.sequential_x1.to_deprecated_son('_id.'), {'$push': {'definition.children': six.text_type(self.problem_x1a_1)}}) # lint-amnesty, pylint: disable=no-member, line-too-long + mongo_store.collection.update_one(self.sequential_x1.to_deprecated_son('_id.'), {'$push': {'definition.children': str(self.problem_x1a_1)}}) # lint-amnesty, pylint: disable=no-member, line-too-long # now check that "get_parent_location" method of published branch raises "ReferentialIntegrityError" for # problem "problem_x1a_1" since it has now 2 valid published parents with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, course_id): @@ -1983,7 +1981,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): block_id='orphan' ) orphans = self.store.get_orphans(self.course_locations[self.MONGO_COURSEID].course_key) - assert len(orphans) == 0, 'unexpected orphans: {}'.format(orphans) + assert len(orphans) == 0, f'unexpected orphans: {orphans}' @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) def test_create_item_populates_edited_info(self, default_ms): @@ -2487,7 +2485,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): self._initialize_mixed(mappings={}) fake_store = "fake" - with self.assertRaisesRegex(Exception, "Cannot find store of type {}".format(fake_store)): + with self.assertRaisesRegex(Exception, f"Cannot find store of type {fake_store}"): with self.store.default_store(fake_store): pass # pragma: no cover @@ -2495,7 +2493,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): """ Load and save the given file. (taken from test_contentstore) """ - with open("{}/static/{}".format(DATA_DIR, asset_key.block_id), "rb") as f: + with open(f"{DATA_DIR}/static/{asset_key.block_id}", "rb") as f: content = StaticContent( asset_key, "Funky Pix", mimetypes.guess_type(asset_key.block_id)[0], f.read(), ) @@ -3002,7 +3000,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup): """ Set up the database for testing """ - super(TestPublishOverExportImport, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user_id = ModuleStoreEnum.UserID.test self.export_dir = mkdtemp() @@ -3353,11 +3351,11 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup): """ asides = block.runtime.get_asides(block) - assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides) + assert len(asides) == 1, f'Found {asides} asides but expected only test_aside' assert isinstance(asides[0], AsideTestType) category = block.scope_ids.block_type - assert asides[0].data_field == '{} aside data'.format(category) - assert asides[0].content == '{} Aside'.format(category.capitalize()) + assert asides[0].data_field == f'{category} aside data' + assert asides[0].content == f'{category.capitalize()} Aside' for child in block.get_children(): check_block(child) @@ -3368,7 +3366,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup): new_chapter = self.store.create_child(self.user_id, courses[0].location, 'chapter', 'new_chapter') asides = new_chapter.runtime.get_asides(new_chapter) - assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides) + assert len(asides) == 1, f'Found {asides} asides but expected only test_aside' chapter_aside = asides[0] assert isinstance(chapter_aside, AsideTestType) assert not chapter_aside.fields['data_field'].is_set_on(chapter_aside), \ @@ -3468,11 +3466,11 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup): """ asides = block.runtime.get_asides(block) - assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides) + assert len(asides) == 1, f'Found {asides} asides but expected only test_aside' assert isinstance(asides[0], AsideTestType) category = block.scope_ids.block_type - assert asides[0].data_field == 'Exported data_field {} aside data'.format(category) - assert asides[0].content == 'Exported content {} Aside'.format(category.capitalize()) + assert asides[0].data_field == f'Exported data_field {category} aside data' + assert asides[0].content == f'Exported content {category.capitalize()} Aside' for child in block.get_children(): check_block(child) @@ -3515,7 +3513,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup): new_chapter.display_name = new_chapter_display_name asides = new_chapter.runtime.get_asides(new_chapter) - assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides) + assert len(asides) == 1, f'Found {asides} asides but expected only test_aside' chapter_aside = asides[0] assert isinstance(chapter_aside, AsideTestType) chapter_aside.data_field = 'new value' @@ -3528,7 +3526,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup): new_problem.display_name = new_problem_display_name asides = new_problem.runtime.get_asides(new_problem) - assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides) + assert len(asides) == 1, f'Found {asides} asides but expected only test_aside' problem_aside = asides[0] assert isinstance(problem_aside, AsideTestType) problem_aside.data_field = 'new problem value' @@ -3607,7 +3605,7 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup): """ Setup environment for testing """ - super(TestAsidesWithMixedModuleStore, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() key_store = DictKeyValueStore() field_data = KvsFieldData(key_store) self.runtime = TestRuntime(services={'field-data': field_data}) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_modulestore_settings.py b/common/lib/xmodule/xmodule/modulestore/tests/test_modulestore_settings.py index 349c93b474c2105728a27cce26ad959d0b101c42..db267b942fb262402e26c23e04492be85c040198 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_modulestore_settings.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_modulestore_settings.py @@ -5,6 +5,7 @@ Tests for testing the modulestore settings migration code. import copy from unittest import TestCase + import pytest import ddt diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py index 7a9d88ba1bfc5eb960b70f5bcca3348f6c1b79de..4d81e6081e091aa5cddaea40c318a10d324f3acb 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py @@ -7,16 +7,15 @@ import logging import shutil from datetime import datetime from tempfile import mkdtemp +from unittest.mock import patch from uuid import uuid4 import pymongo import pytest -import six # pylint: disable=protected-access from django.test import TestCase # pylint: enable=E0611 -from mock import patch from opaque_keys.edx.keys import CourseKey, UsageKey from opaque_keys.edx.locator import AssetLocator, BlockUsageLocator, CourseLocator, LibraryLocator from path import Path as path @@ -172,7 +171,7 @@ class TestMongoModuleStoreBase(TestCase): connection.drop_database(DB) def setUp(self): - super(TestMongoModuleStoreBase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.dummy_user = ModuleStoreEnum.UserID.test @@ -188,11 +187,11 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): @classmethod def setUpClass(cls): - super(TestMongoModuleStore, cls).setUpClass() + super().setUpClass() @classmethod def tearDownClass(cls): - super(TestMongoModuleStore, cls).tearDownClass() + super().tearDownClass() def test_init(self): '''Make sure the db loads''' @@ -370,7 +369,7 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): courses = self.draft_store.get_courses() for course in courses: assert not ((course.location.org == 'edx') and (course.location.course == 'templates')),\ - '{0} is a template course'.format(course) + f'{course} is a template course' def test_contentstore_attrs(self): """ @@ -523,7 +522,7 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): for ref in refele.reference_list: assert isinstance(ref, UsageKey) assert len(refele.reference_dict) > 0 - for ref in six.itervalues(refele.reference_dict): + for ref in refele.reference_dict.values(): assert isinstance(ref, UsageKey) def check_mongo_fields(): @@ -532,17 +531,17 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): def check_children(payload): for child in payload['definition']['children']: - assert isinstance(child, six.string_types) + assert isinstance(child, str) refele = get_item(self.refloc) check_children(refele) - assert isinstance(refele['definition']['data']['reference_link'], six.string_types) + assert isinstance(refele['definition']['data']['reference_link'], str) assert len(refele['definition']['data']['reference_list']) > 0 for ref in refele['definition']['data']['reference_list']: - assert isinstance(ref, six.string_types) + assert isinstance(ref, str) assert len(refele['metadata']['reference_dict']) > 0 - for ref in six.itervalues(refele['metadata']['reference_dict']): - assert isinstance(ref, six.string_types) + for ref in refele['metadata']['reference_dict'].values(): + assert isinstance(ref, str) setup_test() check_xblock_fields() @@ -563,9 +562,9 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): root_dir = path(mkdtemp()) self.addCleanup(shutil.rmtree, root_dir) - export_course_to_xml(self.draft_store, self.content_store, course_key, root_dir, u'test_export') - assert path((root_dir / 'test_export/static/images/course_image.jpg')).isfile() - assert path((root_dir / 'test_export/static/images_course_image.jpg')).isfile() + export_course_to_xml(self.draft_store, self.content_store, course_key, root_dir, 'test_export') + assert path(root_dir / 'test_export/static/images/course_image.jpg').isfile() + assert path(root_dir / 'test_export/static/images_course_image.jpg').isfile() @patch('xmodule.video_module.video_module.edxval_api', None) @patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json) @@ -579,9 +578,9 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): root_dir = path(mkdtemp()) self.addCleanup(shutil.rmtree, root_dir) - export_course_to_xml(self.draft_store, self.content_store, course.id, root_dir, u'test_export') - assert path((root_dir / 'test_export/static/just_a_test.jpg')).isfile() - assert not path((root_dir / 'test_export/static/images/course_image.jpg')).isfile() + export_course_to_xml(self.draft_store, self.content_store, course.id, root_dir, 'test_export') + assert path(root_dir / 'test_export/static/just_a_test.jpg').isfile() + assert not path(root_dir / 'test_export/static/images/course_image.jpg').isfile() @patch('xmodule.video_module.video_module.edxval_api', None) def test_course_without_image(self): @@ -592,9 +591,9 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): course = self.draft_store.get_course(CourseKey.from_string('edX/simple_with_draft/2012_Fall')) root_dir = path(mkdtemp()) self.addCleanup(shutil.rmtree, root_dir) - export_course_to_xml(self.draft_store, self.content_store, course.id, root_dir, u'test_export') - assert not path((root_dir / 'test_export/static/images/course_image.jpg')).isfile() - assert not path((root_dir / 'test_export/static/images_course_image.jpg')).isfile() + export_course_to_xml(self.draft_store, self.content_store, course.id, root_dir, 'test_export') + assert not path(root_dir / 'test_export/static/images/course_image.jpg').isfile() + assert not path(root_dir / 'test_export/static/images_course_image.jpg').isfile() def _create_test_tree(self, name, user_id=None): """ @@ -610,7 +609,7 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): user_id = self.dummy_user org = 'edX' - course = 'tree{}'.format(name) + course = f'tree{name}' run = name if not self.draft_store.has_course(CourseKey.from_string('/'.join[org, course, run])): # lint-amnesty, pylint: disable=unsubscriptable-object @@ -701,8 +700,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): # First child should have been moved to second position, and better child takes the lead course = self.draft_store.get_course(course.id) - assert six.text_type(course.children[1]) == six.text_type(first_child.location) - assert six.text_type(course.children[0]) == six.text_type(second_child.location) + assert str(course.children[1]) == str(first_child.location) + assert str(course.children[0]) == str(second_child.location) # Clean up the data so we don't break other tests which apparently expect a particular state self.draft_store.delete_course(course.id, self.dummy_user) @@ -729,11 +728,11 @@ class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore): # lint-a @classmethod def setUpClass(cls): - super(TestMongoModuleStoreWithNoAssetCollection, cls).setUpClass() + super().setUpClass() @classmethod def tearDownClass(cls): - super(TestMongoModuleStoreWithNoAssetCollection, cls).tearDownClass() + super().tearDownClass() def test_no_asset_collection(self): courses = self.draft_store.get_courses() @@ -753,7 +752,7 @@ class TestMongoKeyValueStore(TestCase): """ def setUp(self): - super(TestMongoKeyValueStore, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.data = {'foo': 'foo_value'} self.course_id = CourseKey.from_string('org/course/run') self.parent = self.course_id.make_usage_key('parent', 'p') diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo_call_count.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo_call_count.py index c939147a7f7f5551535d92deb0f0c2344472b049..57eb4ba4857afe7a2ca2d3f0bf921c881943dc76 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo_call_count.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo_call_count.py @@ -9,7 +9,6 @@ from tempfile import mkdtemp from unittest import skip import ddt -import six from django.test import TestCase # lint-amnesty, pylint: disable=reimported from xmodule.modulestore.tests.factories import check_mongo_calls @@ -35,7 +34,7 @@ class CountMongoCallsXMLRoundtrip(TestCase): """ def setUp(self): - super(CountMongoCallsXMLRoundtrip, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.export_dir = mkdtemp() self.addCleanup(rmtree, self.export_dir, ignore_errors=True) @@ -112,7 +111,7 @@ class CountMongoCallsCourseTraversal(TestCase): if access_all_block_fields: # Read the fields on each block in order to ensure each block and its definition is loaded. for xblock in all_blocks: - for __, field in six.iteritems(xblock.fields): + for __, field in xblock.fields.items(): if field.is_set_on(xblock): __ = field.read_from(xblock) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_publish.py b/common/lib/xmodule/xmodule/modulestore/tests/test_publish.py index 5ab6ec70a6a0b6cfbe89940175155f032fbf731b..efcf5ef68ca6fcdd2bebf94cbf979e23d0c41d29 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_publish.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_publish.py @@ -15,8 +15,6 @@ from tempfile import mkdtemp import pytest import ddt -import six -from six.moves import range from openedx.core.lib.tests import attr from xmodule.exceptions import InvalidVersionError @@ -48,7 +46,7 @@ class TestPublish(SplitWMongoCourseBootstrapper): # create course: finds: 1 to verify uniqueness, 1 to find parents # sends: 1 to create course, 1 to create overview with check_mongo_calls(4, 2): - super(TestPublish, self)._create_course(split=False) # 2 inserts (course and overview) # lint-amnesty, pylint: disable=super-with-arguments + super()._create_course(split=False) # 2 inserts (course and overview) # with bulk will delay all inheritance computations which won't be added into the mongo_calls with self.draft_mongo.bulk_operations(self.old_course_key): @@ -183,7 +181,7 @@ class DraftPublishedOpTestCourseSetup(unittest.TestCase): """ Given a block_type/num, return a block id. """ - return '{}{:02d}'.format(block_type, num) + return f'{block_type}{num:02d}' def _make_course_db_entry(parent_type, parent_id, block_id, idx, child_block_type, child_block_id_base): """ @@ -276,7 +274,7 @@ class DraftPublishedOpTestCourseSetup(unittest.TestCase): # data needed to check the OLX. self.course_db = {} - super(DraftPublishedOpTestCourseSetup, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() class OLXFormatChecker(unittest.TestCase): @@ -306,7 +304,7 @@ class OLXFormatChecker(unittest.TestCase): self._ensure_exported() block_path = os.path.join(self.root_export_dir, self.export_dir) # pylint: disable=no-member - assert os.path.isdir(block_path), '{} is not a dir.'.format(block_path) + assert os.path.isdir(block_path), f'{block_path} is not a dir.' return block_path def _get_block_type_path(self, course_export_dir, block_type, draft): @@ -322,7 +320,7 @@ class OLXFormatChecker(unittest.TestCase): """ Return the course export filename for a block. """ - return '{}.xml'.format(block_id) + return f'{block_id}.xml' def _get_block_contents(self, block_subdir_path, block_id): """ @@ -333,8 +331,8 @@ class OLXFormatChecker(unittest.TestCase): block_file = self._get_block_filename(block_id) block_file_path = os.path.join(block_subdir_path, block_file) - assert os.path.isfile(block_file_path), '{} is not an existing file.'.format(block_file_path) - with open(block_file_path, "r") as file_handle: + assert os.path.isfile(block_file_path), f'{block_file_path} is not an existing file.' + with open(block_file_path) as file_handle: return file_handle.read() def assertElementTag(self, element, tag): @@ -390,7 +388,7 @@ class OLXFormatChecker(unittest.TestCase): is_draft = kwargs.pop('draft', False) block_path = self._get_block_type_path(course_export_dir, block_type, is_draft) block_file_path = os.path.join(block_path, self._get_block_filename(block_id)) - assert not os.path.exists(block_file_path), '{} exists but should not!'.format(block_file_path) + assert not os.path.exists(block_file_path), f'{block_file_path} exists but should not!' def assertParentReferences(self, element, course_key, parent_type, parent_id, index_in_children_list): """ @@ -406,7 +404,7 @@ class OLXFormatChecker(unittest.TestCase): parent_key = course_key.make_usage_key(parent_type, parent_id) self.assertElementAttrsSubset(element, { - 'parent_url': re.escape(six.text_type(parent_key)), + 'parent_url': re.escape(str(parent_key)), 'index_in_children_list': re.escape(str(index_in_children_list)), }) @@ -496,11 +494,11 @@ class DraftPublishedOpBaseTestSetup(OLXFormatChecker, DraftPublishedOpTestCourse Setup base class for draft/published/OLX tests. """ - EXPORTED_COURSE_BEFORE_DIR_NAME = u'exported_course_before' - EXPORTED_COURSE_AFTER_DIR_NAME = u'exported_course_after_{}' + EXPORTED_COURSE_BEFORE_DIR_NAME = 'exported_course_before' + EXPORTED_COURSE_AFTER_DIR_NAME = 'exported_course_after_{}' def setUp(self): - super(DraftPublishedOpBaseTestSetup, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.export_dir = self.EXPORTED_COURSE_BEFORE_DIR_NAME self.root_export_dir = None self.contentstore = None @@ -564,7 +562,7 @@ class DraftPublishedOpBaseTestSetup(OLXFormatChecker, DraftPublishedOpTestCourse """ Make a unique name for the new export dir. """ - return self.EXPORTED_COURSE_AFTER_DIR_NAME.format(six.text_type(uuid.uuid4())[:8]) + return self.EXPORTED_COURSE_AFTER_DIR_NAME.format(str(uuid.uuid4())[:8]) def publish(self, block_list): """ diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_semantics.py b/common/lib/xmodule/xmodule/modulestore/tests/test_semantics.py index ba667f8588b6a609f92abe3a30f2ad3826422e0e..e5fcfbc10f1668e686f3faff1287bcc8c941991d 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_semantics.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_semantics.py @@ -5,10 +5,10 @@ Tests of modulestore semantics: How do the interfaces methods of ModuleStore rel import itertools from collections import namedtuple +from unittest.mock import patch import pytest import ddt -from mock import patch from xblock.core import XBlock, XBlockAside from xblock.fields import Scope, String from xblock.runtime import DictKeyValueStore, KvsFieldData @@ -59,7 +59,7 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase): ASIDE_DATA_FIELD = TestField('content', '<div>aside test data</div>', '<div>aside different test data</div>') def setUp(self): - super(DirectOnlyCategorySemantics, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create( org='test_org', number='999', @@ -345,7 +345,7 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase): self.assertCourseSummaryFields(course_summaries) # Verify fetched accessible courses list is a list of CourseSummery instances - assert all((isinstance(course, CourseSummary) for course in course_summaries)) + assert all(isinstance(course, CourseSummary) for course in course_summaries) @ddt.data(*itertools.product(['chapter', 'sequential'], [True, False])) @ddt.unpack diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_copy_from_template.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_copy_from_template.py index 86eb5e0f312d37ad8490ac160a4c586ce841fa4b..2d0377ddfadd27112acbe3e743a3f5ca9dce1f91 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_copy_from_template.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_copy_from_template.py @@ -6,7 +6,6 @@ However for these tests, we make sure it also works when copying from course to import ddt -from six.moves import range import pytest from xmodule.modulestore import ModuleStoreEnum diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py index 60600ff79872507354a4302ea94c5a7773503dfb..a322e2b3962f1fb4025d0b0c9c1f17ed0a9d9462 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py @@ -6,10 +6,8 @@ Tests for split_migrator import random import uuid +from unittest import mock -import mock -import six -from six.moves import range, zip from xblock.fields import UNIQUE_ID, Reference, ReferenceList, ReferenceValueDict from openedx.core.lib.tests import attr @@ -24,7 +22,7 @@ class TestMigration(SplitWMongoCourseBootstrapper): """ def setUp(self): - super(TestMigration, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.migrator = SplitMigrator(self.split_mongo, self.draft_mongo) def _create_course(self): # lint-amnesty, pylint: disable=arguments-differ @@ -35,7 +33,7 @@ class TestMigration(SplitWMongoCourseBootstrapper): only the live ones get to published. Some are only draft, some are both, some are only live. * about, static_tab, and conditional documents """ - super(TestMigration, self)._create_course(split=False) # lint-amnesty, pylint: disable=super-with-arguments + super()._create_course(split=False) # chapters chapter1_name = uuid.uuid4().hex @@ -167,7 +165,7 @@ class TestMigration(SplitWMongoCourseBootstrapper): if split_dag_root.category != 'course': assert presplit_dag_root.location.block_id == split_dag_root.location.block_id # compare all fields but references - for name, field in six.iteritems(presplit_dag_root.fields): + for name, field in presplit_dag_root.fields.items(): # fields generated from UNIQUE_IDs are unique to an XBlock's scope, # so if such a field is unset on an XBlock, we don't expect it # to persist across courses diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py index 400c4df5be1c40b4bfde2b54af08496a75666dc1..977964067783c3111e3b94926d4f0d3a59ce93c9 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py @@ -9,17 +9,15 @@ import random import re import unittest from importlib import import_module +from unittest.mock import patch import pytest import ddt -import six from ccx_keys.locator import CCXBlockUsageLocator from contracts import contract from django.core.cache import InvalidCacheBackendError, caches -from mock import patch from opaque_keys.edx.locator import BlockUsageLocator, CourseKey, CourseLocator, LocalId, VersionTree from path import Path as path -from six.moves import range from xblock.fields import Reference, ReferenceList, ReferenceValueDict from openedx.core.lib import tempdir @@ -58,7 +56,7 @@ class SplitModuleTest(unittest.TestCase): # Snippets of what would be in the django settings envs file DOC_STORE_CONFIG = { 'host': MONGO_HOST, - 'db': 'test_xmodule_{0}'.format(os.getpid()), + 'db': f'test_xmodule_{os.getpid()}', 'port': MONGO_PORT_NUM, 'collection': 'modulestore', } @@ -503,7 +501,7 @@ class SplitModuleTest(unittest.TestCase): ''' Sets up the initial data into the db ''' - for _course_id, course_spec in six.iteritems(SplitModuleTest.COURSE_CONTENT): + for _course_id, course_spec in SplitModuleTest.COURSE_CONTENT.items(): course = split_store.create_course( course_spec['org'], course_spec['course'], @@ -514,7 +512,7 @@ class SplitModuleTest(unittest.TestCase): root_block_id=course_spec['root_block_id'] ) for revision in course_spec.get('revisions', []): - for (block_type, block_id), fields in six.iteritems(revision.get('update', {})): + for (block_type, block_id), fields in revision.get('update', {}).items(): # cheat since course is most frequent if course.location.block_id == block_id: block = course @@ -522,7 +520,7 @@ class SplitModuleTest(unittest.TestCase): # not easy to figure out the category but get_item won't care block_usage = BlockUsageLocator.make_relative(course.location, block_type, block_id) block = split_store.get_item(block_usage) - for key, value in six.iteritems(fields): + for key, value in fields.items(): setattr(block, key, value) # create new blocks into dag: parent must already exist; thus, order is important new_ele_dict = {} @@ -551,7 +549,7 @@ class SplitModuleTest(unittest.TestCase): split_store.copy("test@edx.org", source_course, destination, [to_publish], None) def setUp(self): - super(SplitModuleTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user_id = random.getrandbits(32) def tearDown(self): @@ -562,7 +560,7 @@ class SplitModuleTest(unittest.TestCase): modulestore()._drop_database(database=False, connections=False) # pylint: disable=protected-access # drop the modulestore to force re init SplitModuleTest.modulestore = None - super(SplitModuleTest, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() def findByIdInResult(self, collection, _id): # pylint: disable=invalid-name """ @@ -953,7 +951,7 @@ class TestCourseStructureCache(SplitModuleTest): 'org', 'course', 'test_run', self.user, BRANCH_NAME_DRAFT, ) - super(TestCourseStructureCache, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() @patch('xmodule.modulestore.split_mongo.mongo_connection.get_cache') def test_course_structure_cache(self, mock_get_cache): @@ -1741,8 +1739,8 @@ class TestItemCrud(SplitModuleTest): # First child should have been moved to second position, and better child takes the lead refetch_course = store.get_course(versionless_course_locator) children = refetch_course.get_children() - assert six.text_type(children[1].location) == six.text_type(first_child.location) - assert six.text_type(children[0].location) == six.text_type(second_child.location) + assert str(children[1].location) == str(first_child.location) + assert str(children[0].location) == str(second_child.location) # Clean up the data so we don't break other tests which apparently expect a particular state store.delete_course(refetch_course.id, user) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore_bulk_operations.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore_bulk_operations.py index d577876aa196159ac640c10547aee450a5987edc..e6070576f0322e6014b30c185a9a875ad2bb8506 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore_bulk_operations.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore_bulk_operations.py @@ -6,20 +6,18 @@ Tests for bulk operations in Split Modulestore. import copy import unittest +from unittest.mock import MagicMock, Mock, call -import six import ddt from bson.objectid import ObjectId -from mock import MagicMock, Mock, call from opaque_keys.edx.locator import CourseLocator -from six.moves import range from xmodule.modulestore.split_mongo.mongo_connection import MongoConnection from xmodule.modulestore.split_mongo.split import SplitBulkWriteMixin VERSION_GUID_DICT = { 'SAMPLE_VERSION_GUID': 'deadbeef1234' * 2, - 'SAMPLE_UNICODE_VERSION_GUID': u'deadbeef1234' * 2, + 'SAMPLE_UNICODE_VERSION_GUID': 'deadbeef1234' * 2, 'BSON_OBJECTID': ObjectId() } SAMPLE_GUIDS_LIST = ['SAMPLE_VERSION_GUID', 'SAMPLE_UNICODE_VERSION_GUID', 'BSON_OBJECTID'] @@ -28,7 +26,7 @@ SAMPLE_GUIDS_LIST = ['SAMPLE_VERSION_GUID', 'SAMPLE_UNICODE_VERSION_GUID', 'BSON class TestBulkWriteMixin(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring def setUp(self): - super(TestBulkWriteMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.bulk = SplitBulkWriteMixin() self.bulk.SCHEMA_VERSION = 1 self.clear_cache = self.bulk._clear_cache = Mock(name='_clear_cache') @@ -53,7 +51,7 @@ class TestBulkWriteMixinPreviousTransaction(TestBulkWriteMixin): Verify that opening and closing a transaction doesn't affect later behaviour. """ def setUp(self): - super(TestBulkWriteMixinPreviousTransaction, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.bulk._begin_bulk_operation(self.course_key) self.bulk.insert_course_index(self.course_key, MagicMock('prev-index-entry')) self.bulk.update_structure(self.course_key, {'this': 'is', 'the': 'previous structure', '_id': ObjectId()}) @@ -170,8 +168,7 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin): self.bulk.update_structure(self.course_key.replace(branch='b'), other_structure) self.assertConnCalls() self.bulk._end_bulk_operation(self.course_key) - six.assertCountEqual( - self, + self.assertCountEqual( [ call.insert_structure(self.structure, self.course_key), call.insert_structure(other_structure, self.course_key) @@ -207,8 +204,7 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin): self.bulk.update_definition(self.course_key.replace(branch='b'), other_definition) self.bulk.insert_course_index(self.course_key, {'versions': {'a': self.definition['_id'], 'b': other_definition['_id']}}) # lint-amnesty, pylint: disable=line-too-long self.bulk._end_bulk_operation(self.course_key) - six.assertCountEqual( - self, + self.assertCountEqual( [ call.insert_definition(self.definition, self.course_key), call.insert_definition(other_definition, self.course_key), @@ -239,8 +235,7 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin): self.bulk.update_definition(self.course_key.replace(branch='b'), other_definition) self.assertConnCalls() self.bulk._end_bulk_operation(self.course_key) - six.assertCountEqual( - self, + self.assertCountEqual( [ call.insert_definition(self.definition, self.course_key), call.insert_definition(other_definition, self.course_key) @@ -276,8 +271,7 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin): self.bulk.update_structure(self.course_key.replace(branch='b'), other_structure) self.bulk.insert_course_index(self.course_key, {'versions': {'a': self.structure['_id'], 'b': other_structure['_id']}}) # lint-amnesty, pylint: disable=line-too-long self.bulk._end_bulk_operation(self.course_key) - six.assertCountEqual( - self, + self.assertCountEqual( [ call.insert_structure(self.structure, self.course_key), call.insert_structure(other_structure, self.course_key), @@ -385,7 +379,7 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin): def test_find_matching_course_indexes(self, branch, search_targets, matching, unmatching): db_indexes = [{'org': 'what', 'course': 'this', 'run': 'needs'}] for n, index in enumerate(matching + unmatching): - course_key = CourseLocator('org', 'course', 'run{}'.format(n)) + course_key = CourseLocator('org', 'course', f'run{n}') self.bulk._begin_bulk_operation(course_key) for attr in ['org', 'course', 'run']: index[attr] = getattr(course_key, attr) @@ -394,7 +388,7 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin): expected = matching + db_indexes self.conn.find_matching_course_indexes.return_value = db_indexes result = self.bulk.find_matching_course_indexes(branch, search_targets) - six.assertCountEqual(self, result, expected) + self.assertCountEqual(result, expected) for item in unmatching: assert item not in result @@ -419,7 +413,7 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin): db_structures = [db_structure(_id) for _id in db_ids if _id not in active_ids] for n, _id in enumerate(active_ids): - course_key = CourseLocator('org', 'course', 'run{}'.format(n)) + course_key = CourseLocator('org', 'course', f'run{n}') self.bulk._begin_bulk_operation(course_key) self.bulk.update_structure(course_key, active_structure(_id)) @@ -515,7 +509,7 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin): db_structures = [db_structure(_id) for _id in db_ids] active_structures = [] for n, _id in enumerate(active_ids): - course_key = CourseLocator('org', 'course', 'run{}'.format(n)) + course_key = CourseLocator('org', 'course', f'run{n}') self.bulk._begin_bulk_operation(course_key) structure = active_structure(_id) self.bulk.update_structure(course_key, structure) @@ -575,14 +569,14 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin): structure.setdefault('_id', ObjectId()) for n, structure in enumerate(active_match + active_unmatch): - course_key = CourseLocator('org', 'course', 'run{}'.format(n)) + course_key = CourseLocator('org', 'course', f'run{n}') self.bulk._begin_bulk_operation(course_key) self.bulk.update_structure(course_key, structure) self.conn.find_ancestor_structures.return_value = db_match + db_unmatch results = self.bulk.find_ancestor_structures(original_version, block_id) self.conn.find_ancestor_structures.assert_called_once_with(original_version, block_id) - six.assertCountEqual(self, active_match + db_match, results) + self.assertCountEqual(active_match + db_match, results) @ddt.ddt @@ -592,7 +586,7 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin): """ def setUp(self): - super(TestBulkWriteMixinOpen, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.bulk._begin_bulk_operation(self.course_key) @ddt.data(*SAMPLE_GUIDS_LIST) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_mongo_mongo_connection.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_mongo_mongo_connection.py index 7512c3da004cbdaa354c140c35c2a0dc8a4c5638..3460470186b3fe93aec04b8f7768338756f1392a 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_mongo_mongo_connection.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_mongo_mongo_connection.py @@ -2,8 +2,9 @@ import unittest +from unittest.mock import patch + import pytest -from mock import patch from pymongo.errors import ConnectionFailure from xmodule.exceptions import HeartbeatFailure diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_w_old_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_w_old_mongo.py index e32a517e00682de52868cda80a72528a40984f59..7cd1537cfa52c151f98e13d4391858916625d025 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_w_old_mongo.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_w_old_mongo.py @@ -4,10 +4,9 @@ import datetime import os import random import unittest +from unittest import mock -import mock import pytest -import six from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from xmodule.modulestore import ModuleStoreEnum @@ -38,7 +37,7 @@ class SplitWMongoCourseBootstrapper(unittest.TestCase): db_config = { 'host': MONGO_HOST, 'port': MONGO_PORT_NUM, - 'db': 'test_xmodule_{}'.format(os.getpid()), + 'db': f'test_xmodule_{os.getpid()}', 'collection': 'modulestore' } @@ -53,7 +52,7 @@ class SplitWMongoCourseBootstrapper(unittest.TestCase): def setUp(self): self.user_id = random.getrandbits(32) - super(SplitWMongoCourseBootstrapper, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.split_mongo = SplitMongoModuleStore( None, self.db_config, @@ -90,7 +89,7 @@ class SplitWMongoCourseBootstrapper(unittest.TestCase): ) if not draft: self.draft_mongo.publish(location, self.user_id) - if isinstance(data, six.string_types): + if isinstance(data, str): fields = {'data': data} else: fields = data.copy() diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_store_utilities.py b/common/lib/xmodule/xmodule/modulestore/tests/test_store_utilities.py index 166c633e6223f2d1dba1abe204637a841e0eab2f..fdc76655f7705f2f216d205d8b93ca721a05cadb 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_store_utilities.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_store_utilities.py @@ -4,9 +4,9 @@ Tests for store_utilities.py import unittest +from unittest.mock import Mock import ddt -from mock import Mock from xmodule.modulestore.store_utilities import draft_node_constructor, get_draft_subtree_roots diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_xml.py b/common/lib/xmodule/xmodule/modulestore/tests/test_xml.py index bbd47227c565f89dc69a0f0d6171e98cfa39d5bd..9b59cabb46a6e07db29460109fa61c3bd41717e1 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_xml.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_xml.py @@ -6,9 +6,10 @@ well-formed and not-well-formed XML. import os.path from glob import glob +from unittest.mock import Mock, patch + import pytest from django.test import TestCase -from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import CourseLocator @@ -145,7 +146,7 @@ class TestModuleStoreIgnore(TestXMLModuleStore): # lint-amnesty, pylint: disabl course_dir = DATA_DIR / "course_ignore" def setUp(self): - super(TestModuleStoreIgnore, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.addCleanup(remove_temp_files_from_list, list(TILDA_FILES_DICT.keys()), self.course_dir / "static") add_temp_files_from_dict(TILDA_FILES_DICT, self.course_dir / "static") diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py b/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py index b702a574b1e7426f41c62f391d2a97058610f91d..6e0e69dc861bd3594173110675b79367c0a1960b 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py @@ -7,9 +7,9 @@ import importlib import os import unittest from uuid import uuid4 +from unittest import mock + import pytest -import mock -import six from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from path import Path as path @@ -23,10 +23,7 @@ from xmodule.modulestore.xml_importer import StaticContentImporter, _update_and_ from xmodule.tests import DATA_DIR from xmodule.x_module import XModuleMixin -if six.PY2: - OPEN_BUILTIN = '__builtin__.open' -else: - OPEN_BUILTIN = 'builtins.open' +OPEN_BUILTIN = 'builtins.open' class ModuleStoreNoSettings(unittest.TestCase): @@ -72,7 +69,7 @@ class ModuleStoreNoSettings(unittest.TestCase): Add cleanups """ self.addCleanup(self.cleanup_modulestore) - super(ModuleStoreNoSettings, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() #=========================================== @@ -141,7 +138,7 @@ class RemapNamespaceTest(ModuleStoreNoSettings): self.field_data = KvsFieldData(kvs=DictKeyValueStore()) self.scope_ids = ScopeIds('Bob', 'stubxblock', '123', 'import') self.xblock = StubXBlock(self.runtime, self.field_data, self.scope_ids) - super(RemapNamespaceTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() def test_remap_namespace_native_xblock(self): @@ -282,7 +279,7 @@ class UpdateLocationTest(ModuleStoreNoSettings): BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'mutablestubxblock', 'child2'), ] - super(UpdateLocationTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() def _check_explicitly_set(self, block, scope, expected_explicitly_set_fields, should_be_set=False): """ Gets fields that are explicitly set on block and checks if they are marked as explicitly set or not """ diff --git a/common/lib/xmodule/xmodule/modulestore/tests/utils.py b/common/lib/xmodule/xmodule/modulestore/tests/utils.py index deda16f3e214dab7b3a9e710c0b703db51740efa..5208ad183c542340a2826ea24e88159d21b972d2 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/utils.py @@ -12,10 +12,8 @@ from tempfile import mkdtemp from unittest import TestCase from uuid import uuid4 -import six from contextlib2 import ExitStack from path import Path as path -from six.moves import range, zip from xmodule.contentstore.mongo import MongoContentStore from xmodule.modulestore.draft_and_published import ModuleStoreDraftAndPublished @@ -84,10 +82,10 @@ def add_temp_files_from_dict(file_dict, dir): # lint-amnesty, pylint: disable=r Takes in a dict formatted as: { file_name: content }, and adds files to directory """ for file_name in file_dict: - with io.open("{}/{}".format(dir, file_name), "w") as opened_file: + with open(f"{dir}/{file_name}", "w") as opened_file: content = file_dict[file_name] if content: - opened_file.write(six.text_type(content)) + opened_file.write(str(content)) def remove_temp_files_from_list(file_list, dir): # lint-amnesty, pylint: disable=redefined-builtin @@ -95,7 +93,7 @@ def remove_temp_files_from_list(file_list, dir): # lint-amnesty, pylint: disabl Takes in a list of file names and removes them from dir if they exist """ for file_name in file_list: - file_path = "{}/{}".format(dir, file_name) + file_path = f"{dir}/{file_name}" if os.path.exists(file_path): os.remove(file_path) @@ -105,7 +103,7 @@ class MixedSplitTestCase(TestCase): Stripped-down version of ModuleStoreTestCase that can be used without Django (i.e. for testing in common/lib/ ). Sets up MixedModuleStore and Split. """ - RENDER_TEMPLATE = lambda t_n, d, ctx=None, nsp='main': u'{}: {}, {}'.format(t_n, repr(d), repr(ctx)) + RENDER_TEMPLATE = lambda t_n, d, ctx=None, nsp='main': '{}: {}, {}'.format(t_n, repr(d), repr(ctx)) modulestore_options = { 'default_class': 'xmodule.raw_module.RawDescriptor', 'fs_root': DATA_DIR, @@ -115,7 +113,7 @@ class MixedSplitTestCase(TestCase): DOC_STORE_CONFIG = { 'host': MONGO_HOST, 'port': MONGO_PORT_NUM, - 'db': 'test_mongo_libs_{0}'.format(os.getpid()), + 'db': f'test_mongo_libs_{os.getpid()}', 'collection': 'modulestore', 'asset_collection': 'assetstore', } @@ -134,7 +132,7 @@ class MixedSplitTestCase(TestCase): """ Set up requirements for testing: a user ID and a modulestore """ - super(MixedSplitTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user_id = ModuleStoreEnum.UserID.test self.store = MixedModuleStore( @@ -162,7 +160,7 @@ class MixedSplitTestCase(TestCase): ) -class ProceduralCourseTestMixin(object): +class ProceduralCourseTestMixin: """ Contains methods for testing courses generated procedurally """ @@ -193,7 +191,7 @@ class ProceduralCourseTestMixin(object): descend(self.course, ['chapter', 'sequential', 'vertical', 'problem']) -class MemoryCache(object): +class MemoryCache: """ This fits the metadata_inheritance_cache_subsystem interface used by the modulestore, and stores the data in a dictionary in memory. @@ -222,7 +220,7 @@ class MemoryCache(object): self.data[key] = value -class MongoContentstoreBuilder(object): +class MongoContentstoreBuilder: """ A builder class for a MongoContentStore. """ @@ -233,7 +231,7 @@ class MongoContentstoreBuilder(object): when the context closes. """ contentstore = MongoContentStore( - db='contentstore{}'.format(THIS_UUID), + db=f'contentstore{THIS_UUID}', collection='content', **COMMON_DOCSTORE_CONFIG ) @@ -249,7 +247,7 @@ class MongoContentstoreBuilder(object): return 'MongoContentstoreBuilder()' -class StoreBuilderBase(object): +class StoreBuilderBase: """ Base class for all modulestore builders. """ @@ -291,7 +289,7 @@ class MongoModulestoreBuilder(StoreBuilderBase): all of its assets. """ doc_store_config = dict( - db='modulestore{}'.format(THIS_UUID), + db=f'modulestore{THIS_UUID}', collection='xmodule', asset_collection='asset_metadata', **COMMON_DOCSTORE_CONFIG @@ -339,7 +337,7 @@ class VersioningModulestoreBuilder(StoreBuilderBase): all of its assets. """ doc_store_config = dict( - db='modulestore{}'.format(THIS_UUID), + db=f'modulestore{THIS_UUID}', collection='split_module', **COMMON_DOCSTORE_CONFIG ) @@ -440,7 +438,7 @@ class MixedModulestoreBuilder(StoreBuilderBase): yield self.mixed_modulestore def __repr__(self): - return 'MixedModulestoreBuilder({!r}, {!r})'.format(self.store_builders, self.mappings) + return f'MixedModulestoreBuilder({self.store_builders!r}, {self.mappings!r})' def asset_collection(self): """ @@ -519,7 +517,7 @@ class PureModulestoreTestCase(TestCase): MODULESTORE = None def setUp(self): - super(PureModulestoreTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() builder = self.MODULESTORE.build() self.assets, self.store = builder.__enter__() diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py index 3e5322375041ab163d1b1037af5c81e953d2bcfe..68635e72eb7cb8c615c525826e9c6478e01a5564 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml.py +++ b/common/lib/xmodule/xmodule/modulestore/xml.py @@ -13,7 +13,6 @@ from collections import defaultdict from contextlib import contextmanager from importlib import import_module -import six from django.utils.encoding import python_2_unicode_compatible from edx_django_utils.monitoring import set_custom_attribute from fs.osfs import OSFS @@ -128,9 +127,9 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # lint-amnesty, pyl # put it in the error tracker--content folks need to see it. if tag in need_uniq_names: - error_tracker(u"PROBLEM: no name of any kind specified for {tag}. Student " - u"state will not be properly tracked for this module. Problem xml:" - u" '{xml}...'".format(tag=tag, xml=xml[:100])) + error_tracker("PROBLEM: no name of any kind specified for {tag}. Student " + "state will not be properly tracked for this module. Problem xml:" + " '{xml}...'".format(tag=tag, xml=xml[:100])) else: # TODO (vshnayder): We may want to enable this once course repos are cleaned up. # (or we may want to give up on the requirement for non-state-relevant issues...) @@ -143,8 +142,8 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # lint-amnesty, pyl # doesn't store state, don't complain about things that are # hashed. if tag in need_uniq_names: - msg = (u"Non-unique url_name in xml. This may break state tracking for content." - u" url_name={0}. Content={1}".format(url_name, xml[:100])) + msg = ("Non-unique url_name in xml. This may break state tracking for content." + " url_name={}. Content={}".format(url_name, xml[:100])) error_tracker("PROBLEM: " + msg) log.warning(msg) # Just set name to fallback_name--if there are multiple things with the same fallback name, @@ -181,14 +180,14 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # lint-amnesty, pyl msg = "Error loading from xml. %s" log.warning( msg, - six.text_type(err)[:200], + str(err)[:200], # Normally, we don't want lots of exception traces in our logs from common # content problems. But if you're debugging the xml loading code itself, # uncomment the next line. # exc_info=True ) - msg = msg % (six.text_type(err)[:200]) + msg = msg % (str(err)[:200]) self.error_tracker(msg) err_msg = msg + "\n" + exc_info_to_str(sys.exc_info()) @@ -221,7 +220,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # lint-amnesty, pyl descriptor.save() return descriptor - render_template = lambda template, context: u'' + render_template = lambda template, context: '' # TODO (vshnayder): we are somewhat architecturally confused in the loading code: # load_item should actually be get_instance, because it expects the course-specific @@ -234,7 +233,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # lint-amnesty, pyl id_manager = CourseImportLocationManager(course_id, target_course_id) - super(ImportSystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( load_item=load_item, resources_fs=resources_fs, render_template=render_template, @@ -258,7 +257,7 @@ class CourseLocationManager(OpaqueKeyReader, AsideKeyGenerator): based within a course """ def __init__(self, course_id): - super(CourseLocationManager, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() self.course_id = course_id self.autogen_ids = itertools.count(0) @@ -298,7 +297,7 @@ class CourseImportLocationManager(CourseLocationManager): see https://openedx.atlassian.net/browse/MA-417 as a pending TODO. """ def __init__(self, course_id, target_course_id): - super(CourseImportLocationManager, self).__init__(course_id=course_id) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(course_id=course_id) self.target_course_id = target_course_id @@ -326,7 +325,7 @@ class XMLModuleStore(ModuleStoreReadBase): source_dirs or course_ids (list of str): If specified, the list of source_dirs or course_ids to load. Otherwise, load all courses. Note, providing both """ - super(XMLModuleStore, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) self.data_dir = path(data_dir) self.modules = defaultdict(dict) # course_id -> dict(location -> XBlock) @@ -378,10 +377,10 @@ class XMLModuleStore(ModuleStoreReadBase): try: course_descriptor = self.load_course(course_dir, course_ids, errorlog.tracker, target_course_id) except Exception as exc: # pylint: disable=broad-except - msg = "ERROR: Failed to load courselike '{0}': {1}".format( - course_dir.encode("utf-8"), six.text_type(exc) + msg = "ERROR: Failed to load courselike '{}': {}".format( + course_dir.encode("utf-8"), str(exc) ) - set_custom_attribute('course_import_failure', "Courselike load failure: {}".format(msg)) + set_custom_attribute('course_import_failure', f"Courselike load failure: {msg}") log.exception(msg) errorlog.tracker(msg) self.errored_courses[course_dir] = errorlog @@ -424,8 +423,8 @@ class XMLModuleStore(ModuleStoreReadBase): try: with open(policy_path) as f: return json.load(f) - except (IOError, ValueError) as err: - msg = "ERROR: loading courselike policy from {0}".format(policy_path) + except (OSError, ValueError) as err: + msg = f"ERROR: loading courselike policy from {policy_path}" tracker(msg) log.warning(msg + " " + str(err)) # lint-amnesty, pylint: disable=logging-not-lazy return {} @@ -478,7 +477,7 @@ class XMLModuleStore(ModuleStoreReadBase): # VS[compat]: remove once courses use the policy dirs. if policy == {}: - old_policy_path = self.data_dir / course_dir / 'policies' / '{0}.json'.format(url_name) + old_policy_path = self.data_dir / course_dir / 'policies' / f'{url_name}.json' policy = self.load_policy(old_policy_path, tracker) else: policy = {} @@ -608,7 +607,7 @@ class XMLModuleStore(ModuleStoreReadBase): with open(file_path) as field_content_file: field_data = json.load(field_content_file) data_content = {field: field_data} - except (IOError, ValueError): + except (OSError, ValueError): # ignore this exception # only new exported courses which use content fields other than 'metadata' and 'data' # will have this file '{dirname}.{field_name}.json' @@ -627,7 +626,7 @@ class XMLModuleStore(ModuleStoreReadBase): if filepath.endswith('~'): # skip *~ files continue - with io.open(filepath) as f: + with open(filepath) as f: try: if filepath.find('.json') != -1: # json file with json data content @@ -638,7 +637,7 @@ class XMLModuleStore(ModuleStoreReadBase): try: # get and update data field in xblock runtime module = system.load_item(loc) - for key, value in six.iteritems(data_content): + for key, value in data_content.items(): setattr(module, key, value) module.save() except ItemNotFoundError: @@ -681,8 +680,8 @@ class XMLModuleStore(ModuleStoreReadBase): self.modules[course_descriptor.id][module.scope_ids.usage_id] = module except Exception as exc: # pylint: disable=broad-except logging.exception("Failed to load %s. Skipping... \ - Exception: %s", filepath, six.text_type(exc)) - system.error_tracker("ERROR: " + six.text_type(exc)) + Exception: %s", filepath, str(exc)) + system.error_tracker("ERROR: " + str(exc)) def has_item(self, usage_key): """ @@ -756,7 +755,7 @@ class XMLModuleStore(ModuleStoreReadBase): for fields in [settings, content, qualifiers] ) - for mod_loc, module in six.iteritems(self.modules[course_id]): + for mod_loc, module in self.modules[course_id].items(): if _block_matches_all(mod_loc, module): items.append(module) @@ -796,7 +795,7 @@ class XMLModuleStore(ModuleStoreReadBase): Return a dictionary of course_dir -> [(msg, exception_str)], for each course_dir where course loading failed. """ - return dict((k, self.errored_courses[k].errors) for k in self.errored_courses) + return {k: self.errored_courses[k].errors for k in self.errored_courses} def get_orphans(self, course_key, **kwargs): """ @@ -847,7 +846,7 @@ class XMLModuleStore(ModuleStoreReadBase): A context manager for temporarily setting the branch value for the store to the given branch_setting. """ if branch_setting != ModuleStoreEnum.Branch.published_only: - raise ValueError(u"Cannot set branch setting to {} on a ReadOnly store".format(branch_setting)) + raise ValueError(f"Cannot set branch setting to {branch_setting} on a ReadOnly store") yield def _find_course_asset(self, asset_key): diff --git a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py index cfbfa810d69a015fa9a62dbb8e97bb073dae3fde..767be91cffd52a5a7fe2fdad4029bcbe5c3be454 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py @@ -9,10 +9,8 @@ from abc import abstractmethod from json import dumps import lxml.etree -import six from fs.osfs import OSFS from opaque_keys.edx.locator import CourseLocator, LibraryLocator -from six import text_type from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope from xmodule.assetstore import AssetMetadata @@ -60,12 +58,12 @@ def _export_drafts(modulestore, course_key, export_fs, xml_centric_course_key): # if module has no parent, set its parent_url to `None` parent_url = None if parent_loc is not None: - parent_url = text_type(parent_loc) + parent_url = str(parent_loc) draft_node = draft_node_constructor( draft_module, location=draft_module.location, - url=text_type(draft_module.location), + url=str(draft_module.location), parent_location=parent_loc, parent_url=parent_url, ) @@ -103,7 +101,7 @@ def _export_drafts(modulestore, course_key, export_fs, xml_centric_course_key): draft_node.module.add_xml_to_node(node) -class ExportManager(object): +class ExportManager: """ Manages XML exporting for courselike objects. """ @@ -121,7 +119,7 @@ class ExportManager(object): self.contentstore = contentstore self.courselike_key = courselike_key self.root_dir = root_dir - self.target_dir = text_type(target_dir) + self.target_dir = str(target_dir) @abstractmethod def get_key(self): @@ -200,7 +198,7 @@ class CourseExportManager(ExportManager): return self.modulestore.get_course(self.courselike_key, depth=None, lazy=False) def process_root(self, root, export_fs): - with export_fs.open(u'course.xml', 'wb') as course_xml: + with export_fs.open('course.xml', 'wb') as course_xml: lxml.etree.ElementTree(root).write(course_xml, encoding='utf-8') def process_extra(self, root, courselike, root_courselike_dir, xml_centric_courselike_key, export_fs): @@ -242,7 +240,7 @@ class CourseExportManager(ExportManager): output_dir = root_courselike_dir + '/static/images/' if not os.path.isdir(output_dir): os.makedirs(output_dir) - with OSFS(output_dir).open(u'course_image.jpg', 'wb') as course_image_file: + with OSFS(output_dir).open('course_image.jpg', 'wb') as course_image_file: course_image_file.write(course_image.data) # export the static tabs @@ -273,12 +271,12 @@ class CourseExportManager(ExportManager): course_run_policy_dir = policies_dir.makedir(course_policy_dir_name, recreate=True) # export the grading policy - with course_run_policy_dir.open(u'grading_policy.json', 'wb') as grading_policy: + with course_run_policy_dir.open('grading_policy.json', 'wb') as grading_policy: grading_policy.write(dumps(courselike.grading_policy, cls=EdxJSONEncoder, sort_keys=True, indent=4).encode('utf-8')) # export all of the course metadata in policy.json - with course_run_policy_dir.open(u'policy.json', 'wb') as course_policy: + with course_run_policy_dir.open('policy.json', 'wb') as course_policy: policy = {'course/' + courselike.location.run: own_metadata(courselike)} course_policy.write(dumps(policy, cls=EdxJSONEncoder, sort_keys=True, indent=4).encode('utf-8')) @@ -357,7 +355,7 @@ def adapt_references(subtree, destination_course_key, export_fs): Map every reference in the subtree into destination_course_key and set it back into the xblock fields """ subtree.runtime.export_fs = export_fs # ensure everything knows where it's going! - for field_name, field in six.iteritems(subtree.fields): + for field_name, field in subtree.fields.items(): if field.is_set_on(subtree): if isinstance(field, Reference): value = field.read_from(subtree) @@ -374,7 +372,7 @@ def adapt_references(subtree, destination_course_key, export_fs): elif isinstance(field, ReferenceValueDict): field.write_to( subtree, { - key: ele.map_into_course(destination_course_key) for key, ele in six.iteritems(field.read_from(subtree)) # lint-amnesty, pylint: disable=line-too-long + key: ele.map_into_course(destination_course_key) for key, ele in field.read_from(subtree).items() # lint-amnesty, pylint: disable=line-too-long } ) @@ -388,7 +386,7 @@ def _export_field_content(xblock_item, item_dir): for field_name in module_data: if field_name not in DEFAULT_CONTENT_FIELDS: # filename format: {dirname}.{field_name}.json - with item_dir.open(u'{0}.{1}.{2}'.format(xblock_item.location.block_id, field_name, 'json'), + with item_dir.open('{}.{}.{}'.format(xblock_item.location.block_id, field_name, 'json'), 'wb') as field_content_file: field_content_file.write(dumps(module_data.get(field_name, {}), cls=EdxJSONEncoder, sort_keys=True, indent=4).encode('utf-8')) diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py index 3e586728ecb80fc1569aaa29832a10f50a0bcf07..24194131af3d25d795609ac87c4ac5df2e0f4288 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_importer.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py @@ -30,7 +30,6 @@ import os import re from abc import abstractmethod -import six import xblock from edx_django_utils.monitoring import set_custom_attribute from lxml import etree @@ -92,7 +91,7 @@ class StaticContentImporter: # lint-amnesty, pylint: disable=missing-class-docs try: with open(course_data_path / 'policies/assets.json') as f: self.policy = json.load(f) - except (IOError, ValueError) as err: # lint-amnesty, pylint: disable=unused-variable + except (OSError, ValueError) as err: # lint-amnesty, pylint: disable=unused-variable # xml backed courses won't have this file, only exported courses; # so, its absence is not really an exception. self.policy = {} @@ -132,7 +131,7 @@ class StaticContentImporter: # lint-amnesty, pylint: disable=missing-class-docs try: with open(full_file_path, 'rb') as f: data = f.read() - except IOError: + except OSError: # OS X "companion files". See # http://www.diigo.com/annotated/0c936fda5da4aa1159c189cea227e174 if filename.startswith('._'): @@ -174,14 +173,14 @@ class StaticContentImporter: # lint-amnesty, pylint: disable=missing-class-docs try: self.static_content_store.save(content) except Exception as err: # lint-amnesty, pylint: disable=broad-except - msg = "Error importing {0}, error={1}".format(file_subpath, err) + msg = f"Error importing {file_subpath}, error={err}" log.exception(msg) - set_custom_attribute('course_import_failure', "Static Content Save Failure: {}".format(msg)) + set_custom_attribute('course_import_failure', f"Static Content Save Failure: {msg}") return file_subpath, asset_key -class ImportManager(object): +class ImportManager: """ Import xml-based courselikes from data_dir into modulestore. @@ -352,7 +351,7 @@ class ImportManager(object): asset_md = AssetMetadata(asset_key) asset_md.from_xml(asset) all_assets.append(asset_md) - except IOError: + except OSError: logging.info('No %s file is present with asset metadata.', assets_filename) return except Exception: # pylint: disable=W0703 @@ -378,7 +377,7 @@ class ImportManager(object): # first into the store course_data_path = path(self.data_dir) / source_courselike.data_dir - log.debug(u'======> IMPORTING courselike %s', courselike_key) + log.debug('======> IMPORTING courselike %s', courselike_key) if not self.do_import_static: # for old-style xblock where this was actually linked to kvs @@ -494,9 +493,9 @@ class ImportManager(object): runtime=courselike.runtime, ) except Exception: - msg = 'failed to import module location {}'.format(leftover) + msg = f'failed to import module location {leftover}' log.error(msg) - set_custom_attribute('course_import_failure', "Module Load failure: {}".format(msg)) + set_custom_attribute('course_import_failure', f"Module Load failure: {msg}") raise def run_imports(self): @@ -601,13 +600,13 @@ class CourseImportManager(ImportManager): # If we are importing into a course with a different course_id and wiki_slug is equal to either of these default # values then remap it so that the wiki does not point to the old wiki. if courselike_key != course.id: - original_unique_wiki_slug = u'{0}.{1}.{2}'.format( + original_unique_wiki_slug = '{}.{}.{}'.format( courselike_key.org, courselike_key.course, courselike_key.run ) if course.wiki_slug == original_unique_wiki_slug or course.wiki_slug == courselike_key.course: - course.wiki_slug = u'{0}.{1}.{2}'.format( + course.wiki_slug = '{}.{}.{}'.format( course.id.org, course.id.course, course.id.run, @@ -750,7 +749,7 @@ def _update_and_import_module( Update all the module reference fields to the destination course id, then import the module into the destination course. """ - logging.debug(u'processing import of module %s...', six.text_type(module.location)) + logging.debug('processing import of module %s...', str(module.location)) def _update_module_references(module, source_course_id, dest_course_id): """ @@ -770,7 +769,7 @@ def _update_and_import_module( return reference fields = {} - for field_name, field in six.iteritems(module.fields): + for field_name, field in module.fields.items(): if field.scope != Scope.parent and field.is_set_on(module): if isinstance(field, Reference): value = field.read_from(module) @@ -786,7 +785,7 @@ def _update_and_import_module( fields[field_name] = { key: _convert_ref_fields_to_new_namespace(reference) for key, reference - in six.iteritems(reference_dict) + in reference_dict.items() } elif field_name == 'xml_attributes': value = field.read_from(module) @@ -962,7 +961,7 @@ def _import_course_draft( # Skip any OSX quarantine files, prefixed with a '._'. continue module_path = os.path.join(rootdir, filename) - with io.open(module_path, 'r') as f: + with open(module_path, 'r') as f: try: xml = f.read() @@ -984,7 +983,7 @@ def _import_course_draft( index = index_in_children_list(descriptor) parent_url = get_parent_url(descriptor, xml) - draft_url = six.text_type(descriptor.location) + draft_url = str(descriptor.location) draft = draft_node_constructor( module=descriptor, url=draft_url, parent_url=parent_url, index=index @@ -1033,7 +1032,7 @@ def check_module_metadata_editability(module): print( ": found non-editable metadata on {url}. " "These metadata keys are not supported = {keys}".format( - url=six.text_type(module.location), keys=illegal_keys + url=str(module.location), keys=illegal_keys ) ) @@ -1079,7 +1078,7 @@ def create_xml_attributes(module, xml): Make up for modules which don't define xml_attributes by creating them here and populating """ xml_attrs = {} - for attr, val in six.iteritems(xml.attrib): + for attr, val in xml.attrib.items(): if attr not in module.fields: # translate obsolete attr if attr == 'parent_sequential_url': @@ -1106,7 +1105,7 @@ def validate_category_hierarchy( # lint-amnesty, pylint: disable=missing-functi parents = [] # get all modules of parent_category - for module in six.itervalues(module_store.modules[course_id]): + for module in module_store.modules[course_id].values(): if module.location.block_type == parent_category: parents.append(module) @@ -1162,7 +1161,7 @@ def validate_course_policy(module_store, course_id): """ # is there a reliable way to get the module location just given the course_id? warn_cnt = 0 - for module in six.itervalues(module_store.modules[course_id]): + for module in module_store.modules[course_id].values(): if module.location.block_type == 'course': if not module._field_data.has(module, 'rerandomize'): # lint-amnesty, pylint: disable=protected-access warn_cnt += 1 @@ -1204,7 +1203,7 @@ def perform_xlint( # lint-amnesty, pylint: disable=missing-function-docstring warn_cnt += _warn_cnt # first count all errors and warnings as part of the XMLModuleStore import - for err_log in six.itervalues(module_store._course_errors): # pylint: disable=protected-access + for err_log in module_store._course_errors.values(): # pylint: disable=protected-access for err_log_entry in err_log.errors: msg = err_log_entry[0] if msg.startswith('ERROR:'): @@ -1213,7 +1212,7 @@ def perform_xlint( # lint-amnesty, pylint: disable=missing-function-docstring warn_cnt += 1 # then count outright all courses that failed to load at all - for err_log in six.itervalues(module_store.errored_courses): + for err_log in module_store.errored_courses.values(): for err_log_entry in err_log.errors: msg = err_log_entry[0] print(msg) diff --git a/common/lib/xmodule/xmodule/partitions/enrollment_track_partition_generator.py b/common/lib/xmodule/xmodule/partitions/enrollment_track_partition_generator.py index d5c0b3011e30500a1b935241218b62ed91771792..f7ebb730a199ab12026a357d94e2bdf8b473c69a 100644 --- a/common/lib/xmodule/xmodule/partitions/enrollment_track_partition_generator.py +++ b/common/lib/xmodule/xmodule/partitions/enrollment_track_partition_generator.py @@ -4,7 +4,6 @@ openedx.dynamic_partition plugin. """ import logging -import six from django.conf import settings from django.utils.translation import ugettext_lazy as _ @@ -34,21 +33,21 @@ def create_enrollment_track_partition(course): log.warning("No 'enrollment_track' scheme registered, EnrollmentTrackUserPartition will not be created.") return None - used_ids = set(p.id for p in course.user_partitions) + used_ids = {p.id for p in course.user_partitions} if ENROLLMENT_TRACK_PARTITION_ID in used_ids: log.warning( "Can't add 'enrollment_track' partition, as ID {id} is assigned to {partition} in course {course}.".format( id=ENROLLMENT_TRACK_PARTITION_ID, partition=get_partition_from_id(course.user_partitions, ENROLLMENT_TRACK_PARTITION_ID).name, - course=six.text_type(course.id) + course=str(course.id) ) ) return None partition = enrollment_track_scheme.create_user_partition( id=ENROLLMENT_TRACK_PARTITION_ID, - name=_(u"Enrollment Track Groups"), - description=_(u"Partition for segmenting users by enrollment track"), - parameters={"course_id": six.text_type(course.id)} + name=_("Enrollment Track Groups"), + description=_("Partition for segmenting users by enrollment track"), + parameters={"course_id": str(course.id)} ) return partition diff --git a/common/lib/xmodule/xmodule/partitions/partitions.py b/common/lib/xmodule/xmodule/partitions/partitions.py index 0b40ef242143ae79e04cc5b03921752a590a9425..107a797054a66d9a8532b50da55dd1e0a282fe48 100644 --- a/common/lib/xmodule/xmodule/partitions/partitions.py +++ b/common/lib/xmodule/xmodule/partitions/partitions.py @@ -58,7 +58,7 @@ class Group(namedtuple("Group", "id name")): VERSION = 1 def __new__(cls, id, name): - return super(Group, cls).__new__(cls, int(id), name) + return super().__new__(cls, int(id), name) def to_json(self): """ @@ -88,11 +88,11 @@ class Group(namedtuple("Group", "id name")): for key in ("id", "name", "version"): if key not in value: - raise TypeError("Group dict {0} missing value key '{1}'".format( + raise TypeError("Group dict {} missing value key '{}'".format( value, key)) if value["version"] != Group.VERSION: - raise TypeError("Group dict {0} has unexpected version".format( + raise TypeError("Group dict {} has unexpected version".format( value)) return Group(value["id"], value["name"]) @@ -133,7 +133,7 @@ class UserPartition(namedtuple("UserPartition", "id name description groups sche if parameters is None: parameters = {} - return super(UserPartition, cls).__new__(cls, int(id), name, description, groups, scheme, parameters, active) + return super().__new__(cls, int(id), name, description, groups, scheme, parameters, active) @staticmethod def get_scheme(name): @@ -147,7 +147,7 @@ class UserPartition(namedtuple("UserPartition", "id name description groups sche try: scheme = UserPartition.scheme_extensions[name].plugin # lint-amnesty, pylint: disable=unsubscriptable-object except KeyError: - raise UserPartitionError("Unrecognized scheme '{0}'".format(name)) # lint-amnesty, pylint: disable=raise-missing-from + raise UserPartitionError(f"Unrecognized scheme '{name}'") # lint-amnesty, pylint: disable=raise-missing-from scheme.name = name return scheme @@ -184,7 +184,7 @@ class UserPartition(namedtuple("UserPartition", "id name description groups sche for key in ("id", "name", "description", "version", "groups"): if key not in value: - raise TypeError("UserPartition dict {0} missing value key '{1}'".format(value, key)) + raise TypeError(f"UserPartition dict {value} missing value key '{key}'") if value["version"] == 1: # If no scheme was provided, set it to the default ('random') @@ -195,21 +195,21 @@ class UserPartition(namedtuple("UserPartition", "id name description groups sche # version, we should try to read it rather than raising an exception. elif value["version"] >= 2: if "scheme" not in value: - raise TypeError("UserPartition dict {0} missing value key 'scheme'".format(value)) + raise TypeError(f"UserPartition dict {value} missing value key 'scheme'") scheme_id = value["scheme"] else: - raise TypeError("UserPartition dict {0} has unexpected version".format(value)) + raise TypeError(f"UserPartition dict {value} has unexpected version") parameters = value.get("parameters", {}) active = value.get("active", True) groups = [Group.from_json(g) for g in value["groups"]] scheme = UserPartition.get_scheme(scheme_id) if not scheme: - raise TypeError("UserPartition dict {0} has unrecognized scheme {1}".format(value, scheme_id)) + raise TypeError(f"UserPartition dict {value} has unrecognized scheme {scheme_id}") if getattr(scheme, 'read_only', False): - raise ReadOnlyUserPartitionError("UserPartition dict {0} uses scheme {1} which is read only".format(value, scheme_id)) # lint-amnesty, pylint: disable=line-too-long + raise ReadOnlyUserPartitionError(f"UserPartition dict {value} uses scheme {scheme_id} which is read only") # lint-amnesty, pylint: disable=line-too-long if hasattr(scheme, "create_user_partition"): return scheme.create_user_partition( diff --git a/common/lib/xmodule/xmodule/partitions/partitions_service.py b/common/lib/xmodule/xmodule/partitions/partitions_service.py index df03e21583ac6d6f379287d9eb0732cf6208342f..3dcf6bba21edf5d2f5c4ea66913e18a41da686c0 100644 --- a/common/lib/xmodule/xmodule/partitions/partitions_service.py +++ b/common/lib/xmodule/xmodule/partitions/partitions_service.py @@ -81,7 +81,7 @@ def _get_dynamic_partitions(course): return generated_partitions -class PartitionService(object): +class PartitionService: """ This is an XBlock service that returns information about the user partitions associated with a given course. @@ -136,8 +136,8 @@ class PartitionService(object): user_partition = self.get_user_partition(user_partition_id) if user_partition is None: raise ValueError( - "Configuration problem! No user_partition with id {0} " - "in course {1}".format(user_partition_id, self._course_id) + "Configuration problem! No user_partition with id {} " + "in course {}".format(user_partition_id, self._course_id) ) group = self.get_group(user, user_partition) diff --git a/common/lib/xmodule/xmodule/partitions/tests/test_partitions.py b/common/lib/xmodule/xmodule/partitions/tests/test_partitions.py index be5a1428e7f1c6464739953cdc1b0a87bfa03da0..fcbbb1a94c40350d4ee603d7bdce81a456315eaf 100644 --- a/common/lib/xmodule/xmodule/partitions/tests/test_partitions.py +++ b/common/lib/xmodule/xmodule/partitions/tests/test_partitions.py @@ -5,11 +5,10 @@ Test the partitions and partitions service from datetime import datetime +from unittest.mock import Mock import pytest -import six from django.test import TestCase -from mock import Mock # lint-amnesty, pylint: disable=unused-import from opaque_keys.edx.locator import CourseLocator from stevedore.extension import Extension, ExtensionManager @@ -96,12 +95,12 @@ class TestGroup(TestCase): assert 'programmer' not in group.to_json() -class MockUserPartitionScheme(object): +class MockUserPartitionScheme: """ Mock user partition scheme """ def __init__(self, name="mock", current_group=None, **kwargs): - super(MockUserPartitionScheme, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) self.name = name self.current_group = current_group @@ -137,7 +136,7 @@ class PartitionTestCase(TestCase): ENROLLMENT_TRACK_SCHEME_NAME = "enrollment_track" def setUp(self): - super(PartitionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Set up two user partition schemes: mock and random self.non_random_scheme = MockUserPartitionScheme(self.TEST_SCHEME_NAME) self.random_scheme = MockUserPartitionScheme("random") @@ -419,7 +418,7 @@ class MockPartitionService(PartitionService): Mock PartitionService for testing. """ def __init__(self, course, **kwargs): - super(MockPartitionService, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) self._course = course def get_course(self): @@ -432,7 +431,7 @@ class PartitionServiceBaseClass(PartitionTestCase): """ def setUp(self): - super(PartitionServiceBaseClass, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() ContentTypeGatingConfig.objects.create( enabled=True, @@ -448,7 +447,7 @@ class PartitionServiceBaseClass(PartitionTestCase): # extra param to this method. Just has to be unique per user. user_id = abs(hash(username)) self.user = Mock( - username=username, email='{}@edx.org'.format(username), is_staff=False, is_active=True, id=user_id + username=username, email=f'{username}@edx.org', is_staff=False, is_active=True, id=user_id ) self.course.user_partitions = [self.user_partition] @@ -543,7 +542,7 @@ class TestGetCourseUserPartitions(PartitionServiceBaseClass): """ def setUp(self): - super(TestGetCourseUserPartitions, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() TestGetCourseUserPartitions._enable_enrollment_track_partition(True) @staticmethod @@ -562,7 +561,7 @@ class TestGetCourseUserPartitions(PartitionServiceBaseClass): assert self.TEST_SCHEME_NAME == all_partitions[0].scheme.name enrollment_track_partition = all_partitions[1] assert self.ENROLLMENT_TRACK_SCHEME_NAME == enrollment_track_partition.scheme.name - assert six.text_type(self.course.id) == enrollment_track_partition.parameters['course_id'] + assert str(self.course.id) == enrollment_track_partition.parameters['course_id'] assert ENROLLMENT_TRACK_PARTITION_ID == enrollment_track_partition.id def test_enrollment_track_partition_not_added_if_conflict(self): diff --git a/common/lib/xmodule/xmodule/progress.py b/common/lib/xmodule/xmodule/progress.py index 60923d498c2eef38d66c73a071bfbf6281efdba7..064118f4e769a078c154530091408b6410949b74 100644 --- a/common/lib/xmodule/xmodule/progress.py +++ b/common/lib/xmodule/xmodule/progress.py @@ -9,7 +9,7 @@ frac() and __str__(). import numbers -class Progress(object): +class Progress: # pylint: disable=eq-without-hash '''Represents a progress of a/b (a out of b done) a and b must be numeric, but not necessarily integer, with @@ -29,7 +29,7 @@ class Progress(object): # Want to do all checking at construction time, so explicitly check types if not (isinstance(a, numbers.Number) and isinstance(b, numbers.Number)): - raise TypeError('a and b must be numbers. Passed {0}/{1}'.format(a, b)) + raise TypeError(f'a and b must be numbers. Passed {a}/{b}') if a > b: a = b @@ -38,7 +38,7 @@ class Progress(object): a = 0 if b <= 0: - raise ValueError('fraction a/b = {0}/{1} must have b > 0'.format(a, b)) + raise ValueError(f'fraction a/b = {a}/{b} must have b > 0') self._a = a self._b = b @@ -116,8 +116,8 @@ class Progress(object): ''' (a, b) = self.frac() - display = lambda n: '{:.2f}'.format(n).rstrip('0').rstrip('.') - return "{0}/{1}".format(display(a), display(b)) + display = lambda n: f'{n:.2f}'.rstrip('0').rstrip('.') + return "{}/{}".format(display(a), display(b)) @staticmethod def add_counts(a, b): diff --git a/common/lib/xmodule/xmodule/randomize_module.py b/common/lib/xmodule/xmodule/randomize_module.py index 7067b5c13c34fedd267293c597cadf8291d1cdb3..2079c7246fc098f35f65c7bce8d56ffb26c30192 100644 --- a/common/lib/xmodule/xmodule/randomize_module.py +++ b/common/lib/xmodule/xmodule/randomize_module.py @@ -102,7 +102,7 @@ class RandomizeBlock( """ if self.child is None: # raise error instead? In fact, could complain on descriptor load... - return Fragment(content=u"<div>Nothing to randomize between</div>") + return Fragment(content="<div>Nothing to randomize between</div>") return self.child.render(STUDENT_VIEW, context) diff --git a/common/lib/xmodule/xmodule/raw_module.py b/common/lib/xmodule/xmodule/raw_module.py index 86ec4a58d803b58a2cf2cee2d2cdc0622aa9a1f5..a07f51e658a3251c7800f1499b914ea7c2433512 100644 --- a/common/lib/xmodule/xmodule/raw_module.py +++ b/common/lib/xmodule/xmodule/raw_module.py @@ -14,7 +14,7 @@ log = logging.getLogger(__name__) PRE_TAG_REGEX = re.compile(r'<pre\b[^>]*>(?:(?=([^<]+))\1|<(?!pre\b[^>]*>))*?</pre>') -class RawMixin(object): +class RawMixin: """ Common code between RawDescriptor and XBlocks converted from XModules. """ @@ -68,8 +68,8 @@ class RawMixin(object): lines = self.data.split('\n') line, offset = err.position msg = ( - u"Unable to create xml for module {loc}. " - u"Context: '{context}'" + "Unable to create xml for module {loc}. " + "Context: '{context}'" ).format( context=lines[line - 1][offset - 40:offset + 40], loc=self.location, @@ -92,9 +92,9 @@ class RawMixin(object): node.remove(child) # Get attributes, if any, via normal parse_xml. try: - block = super(RawMixin, cls).parse_xml_new_runtime(node, runtime, keys) + block = super().parse_xml_new_runtime(node, runtime, keys) except AttributeError: - block = super(RawMixin, cls).parse_xml(node, runtime, keys, id_generator=None) + block = super().parse_xml(node, runtime, keys, id_generator=None) block.data = data_field_value return block @@ -107,7 +107,7 @@ class RawDescriptor(RawMixin, XmlDescriptor, XMLEditingDescriptor): pass # lint-amnesty, pylint: disable=unnecessary-pass -class EmptyDataRawMixin(object): +class EmptyDataRawMixin: """ Common code between EmptyDataRawDescriptor and XBlocks converted from XModules. """ diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index 69fa86b09b911bda4accc8338230b6885a5e6e78..96694aea9db23780b7e643d1f0ee2ad670a5f18c 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -11,12 +11,10 @@ import logging from datetime import datetime from functools import reduce -import six from lxml import etree from opaque_keys.edx.keys import UsageKey from pkg_resources import resource_string from pytz import UTC -from six import text_type from web_fragments.fragment import Fragment from xblock.completable import XBlockCompletionMode from xblock.core import XBlock @@ -61,12 +59,12 @@ _ = lambda text: text TIMED_EXAM_GATING_WAFFLE_FLAG = LegacyWaffleFlag( waffle_namespace="xmodule", - flag_name=u'rev_1377_rollout', + flag_name='rev_1377_rollout', module_name=__name__, ) -class SequenceFields(object): # lint-amnesty, pylint: disable=missing-class-docstring +class SequenceFields: # lint-amnesty, pylint: disable=missing-class-docstring has_children = True completion_mode = XBlockCompletionMode.AGGREGATOR @@ -138,7 +136,7 @@ class SequenceMixin(SequenceFields): return xblock_body -class ProctoringFields(object): +class ProctoringFields: """ Fields that are specific to Proctored or Timed Exams """ @@ -315,7 +313,7 @@ class SequenceBlock( if dispatch == 'goto_position': # set position to default value if either 'position' argument not # found in request or it is a non-positive integer - position = data.get('position', u'1') + position = data.get('position', '1') if position.isdigit() and int(position) > 0: self.position = int(position) else: @@ -516,7 +514,7 @@ class SequenceBlock( params = { 'items': items, 'element_id': self.location.html_id(), - 'item_id': text_type(self.location), + 'item_id': str(self.location), 'is_time_limited': self.is_time_limited, 'position': self.position, 'tag': self.location.block_type, @@ -742,7 +740,7 @@ class SequenceBlock( 'content': content, 'page_title': getattr(item, 'tooltip_title', ''), 'type': item_type, - 'id': text_type(usage_id), + 'id': str(usage_id), 'bookmarked': is_bookmarked, 'path': " > ".join(display_names + [item.display_name_with_default]), 'graded': item.graded, @@ -783,7 +781,7 @@ class SequenceBlock( """ if not newrelic: return - newrelic.agent.add_custom_parameter('seq.block_id', six.text_type(self.location)) + newrelic.agent.add_custom_parameter('seq.block_id', str(self.location)) newrelic.agent.add_custom_parameter('seq.display_name', self.display_name or '') newrelic.agent.add_custom_parameter('seq.position', self.position) newrelic.agent.add_custom_parameter('seq.is_time_limited', self.is_time_limited) @@ -808,7 +806,7 @@ class SequenceBlock( # Count of all modules by block_type (e.g. "video": 2, "discussion": 4) block_counts = collections.Counter(usage_key.block_type for usage_key in all_item_keys) for block_type, count in block_counts.items(): - newrelic.agent.add_custom_parameter('seq.block_counts.{}'.format(block_type), count) + newrelic.agent.add_custom_parameter(f'seq.block_counts.{block_type}', count) def _capture_current_unit_metrics(self, display_items): """ @@ -822,7 +820,7 @@ class SequenceBlock( if 1 <= self.position <= len(display_items): # Basic info about the Unit... current = display_items[self.position - 1] - newrelic.agent.add_custom_parameter('seq.current.block_id', six.text_type(current.location)) + newrelic.agent.add_custom_parameter('seq.current.block_id', str(current.location)) newrelic.agent.add_custom_parameter('seq.current.display_name', current.display_name or '') # Examining all items inside the Unit (or split_test, conditional, etc.) @@ -830,7 +828,7 @@ class SequenceBlock( newrelic.agent.add_custom_parameter('seq.current.num_items', len(child_locs)) curr_block_counts = collections.Counter(usage_key.block_type for usage_key in child_locs) for block_type, count in curr_block_counts.items(): - newrelic.agent.add_custom_parameter('seq.current.block_counts.{}'.format(block_type), count) + newrelic.agent.add_custom_parameter(f'seq.current.block_counts.{block_type}', count) def _time_limited_student_view(self): """ @@ -906,8 +904,8 @@ class SequenceBlock( return view_html def get_icon_class(self): - 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 c in class_priority: if c in child_classes: @@ -930,7 +928,7 @@ class SequenceBlock( return non_editable_fields -class HighlightsFields(object): +class HighlightsFields: """Only Sections have summaries now, but we may expand that later.""" highlights = List( help=_("A list summarizing what students should look forward to in this section."), diff --git a/common/lib/xmodule/xmodule/services.py b/common/lib/xmodule/xmodule/services.py index c8b194a951cae0f84934183cbec148d1be4e02b2..f829862f55d5dfb8b4e4e5347f8bab901e2c035f 100644 --- a/common/lib/xmodule/xmodule/services.py +++ b/common/lib/xmodule/xmodule/services.py @@ -10,7 +10,7 @@ from django.conf import settings from xmodule.modulestore.django import modulestore -class SettingsService(object): +class SettingsService: """ Allows server-wide configuration of XBlocks on a per-type basis @@ -61,7 +61,7 @@ class SettingsService(object): def get_settings_bucket(self, block, default=None): """ Gets xblock settings dictionary from settings. """ if not block: - raise ValueError("Expected XBlock instance, got {0} of type {1}".format(block, type(block))) + raise ValueError("Expected XBlock instance, got {} of type {}".format(block, type(block))) actual_default = default if default is not None else {} xblock_settings_bucket = getattr(block, self.xblock_settings_bucket_selector, block.unmixed_class.__name__) @@ -71,7 +71,7 @@ class SettingsService(object): # TODO: ConfigurationService and its usage will be removed as a part of EDUCATOR-121 # reference: https://openedx.atlassian.net/browse/EDUCATOR-121 -class ConfigurationService(object): +class ConfigurationService: """ An XBlock service to talk with the Configuration Models. This service should provide a pathway to Configuration Model which is designed to configure the corresponding XBlock. @@ -89,7 +89,7 @@ class ConfigurationService(object): """ if not (inspect.isclass(configuration_model) and issubclass(configuration_model, ConfigurationModel)): raise ValueError( - "Expected ConfigurationModel got {0} of type {1}".format( + "Expected ConfigurationModel got {} of type {}".format( configuration_model, type(configuration_model) ) @@ -98,7 +98,7 @@ class ConfigurationService(object): self.configuration = configuration_model -class TeamsConfigurationService(object): +class TeamsConfigurationService: """ An XBlock service that returns the teams_configuration object for a course. """ diff --git a/common/lib/xmodule/xmodule/split_test_module.py b/common/lib/xmodule/xmodule/split_test_module.py index d1857076eab622a75fb363b28871753f2f24a7bb..0f9f7ec33782a1f7dee251eac86da2accb6a8079 100644 --- a/common/lib/xmodule/xmodule/split_test_module.py +++ b/common/lib/xmodule/xmodule/split_test_module.py @@ -10,11 +10,9 @@ from functools import reduce from operator import itemgetter from uuid import uuid4 -import six from django.utils.functional import cached_property from lxml import etree from pkg_resources import resource_string -from six import text_type from web_fragments.fragment import Fragment from webob import Response from xblock.core import XBlock @@ -43,7 +41,7 @@ log = logging.getLogger('edx.' + __name__) # `django.utils.translation.ugettext_noop` because Django cannot be imported in this file _ = lambda text: text -DEFAULT_GROUP_NAME = _(u'Group ID {group_id}') +DEFAULT_GROUP_NAME = _('Group ID {group_id}') class UserPartitionValues(threading.local): @@ -75,7 +73,7 @@ class UserPartitionValues(threading.local): user_partition_values = UserPartitionValues() -class SplitTestFields(object): +class SplitTestFields: """Fields needed for split test module""" has_children = True @@ -284,8 +282,8 @@ class SplitTestBlock( group_name = child.display_name updated_group_id = [g_id for g_id, loc in self.group_id_to_child.items() if loc == child_location][0] inactive_contents.append({ - 'group_name': _(u'{group_name} (inactive)').format(group_name=group_name), - 'id': text_type(child.location), + 'group_name': _('{group_name} (inactive)').format(group_name=group_name), + 'id': str(child.location), 'content': rendered_child.content, 'group_id': updated_group_id, }) @@ -293,7 +291,7 @@ class SplitTestBlock( active_contents.append({ 'group_name': group_name, - 'id': text_type(child.location), + 'id': str(child.location), 'content': rendered_child.content, 'group_id': updated_group_id, }) @@ -382,7 +380,7 @@ class SplitTestBlock( """ if self.child is None: # raise error instead? In fact, could complain on descriptor load... - return Fragment(content=u"<div>Nothing here. Move along.</div>") + return Fragment(content="<div>Nothing here. Move along.</div>") if self.system.user_is_staff: return self._staff_view(context) @@ -404,11 +402,11 @@ class SplitTestBlock( """ # TODO: use publish instead, when publish is wired to the tracking logs try: - child_id = text_type(self.child.scope_ids.usage_id) + child_id = str(self.child.scope_ids.usage_id) except Exception: log.info( "Can't get usage_id of Nonetype object in course {course_key}".format( - course_key=six.text_type(self.location.course_key) + course_key=str(self.location.course_key) ) ) raise @@ -432,7 +430,7 @@ class SplitTestBlock( user_partition = self.get_selected_partition() if user_partition: for group in user_partition.groups: - group_id = six.text_type(group.id) + group_id = str(group.id) child_location = self.group_id_to_child.get(group_id, None) if child_location == vertical.location: return (group.name, group.id) @@ -447,7 +445,7 @@ class SplitTestBlock( renderable_groups = {} # json.dumps doesn't know how to handle Location objects for group in self.group_id_to_child: - renderable_groups[group] = text_type(self.group_id_to_child[group]) + renderable_groups[group] = str(self.group_id_to_child[group]) xml_object.set('group_id_to_child', json.dumps(renderable_groups)) xml_object.set('user_partition_id', str(self.user_partition_id)) for child in self.get_children(): @@ -577,7 +575,7 @@ class SplitTestBlock( # Compute the active children in the order specified by the user partition active_children = [] for group in user_partition.groups: - group_id = six.text_type(group.id) + group_id = str(group.id) child_location = self.group_id_to_child.get(group_id, None) child = get_child_descriptor(child_location) if child: @@ -626,9 +624,9 @@ class SplitTestBlock( split_validation.add( StudioValidationMessage( StudioValidationMessage.NOT_CONFIGURED, - _(u"The experiment is not associated with a group configuration."), + _("The experiment is not associated with a group configuration."), action_class='edit-button', - action_label=_(u"Select a Group Configuration") + action_label=_("Select a Group Configuration") ) ) else: @@ -637,7 +635,7 @@ class SplitTestBlock( split_validation.add( StudioValidationMessage( StudioValidationMessage.ERROR, - _(u"The experiment uses a deleted group configuration. Select a valid group configuration or delete this experiment.") # lint-amnesty, pylint: disable=line-too-long + _("The experiment uses a deleted group configuration. Select a valid group configuration or delete this experiment.") # lint-amnesty, pylint: disable=line-too-long ) ) else: @@ -647,8 +645,8 @@ class SplitTestBlock( split_validation.add( StudioValidationMessage( StudioValidationMessage.ERROR, - _(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.") ) ) else: @@ -657,17 +655,17 @@ class SplitTestBlock( split_validation.add( StudioValidationMessage( StudioValidationMessage.ERROR, - _(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."), action_runtime_event='add-missing-groups', - action_label=_(u"Add Missing Groups") + action_label=_("Add Missing Groups") ) ) if len(inactive_children) > 0: split_validation.add( StudioValidationMessage( StudioValidationMessage.WARNING, - _(u"The experiment has an inactive group. " - u"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.") ) ) return split_validation @@ -685,7 +683,7 @@ class SplitTestBlock( has_error = any(message.type == StudioValidationMessage.ERROR for message in validation.messages) return StudioValidationMessage( StudioValidationMessage.ERROR if has_error else StudioValidationMessage.WARNING, - _(u"This content experiment has issues that affect content visibility.") + _("This content experiment has issues that affect content visibility.") ) return None @@ -700,7 +698,7 @@ class SplitTestBlock( changed = False for group in user_partition.groups: - str_group_id = six.text_type(group.id) + str_group_id = str(group.id) if str_group_id not in self.group_id_to_child: user_id = self.runtime.service(self, 'user').get_current_user().opt_attrs['edx-platform.user_id'] self._create_vertical_for_group(group, user_id) @@ -722,7 +720,7 @@ class SplitTestBlock( user_partition = self.get_selected_partition() if user_partition: group_configuration_url = "{url}#{configuration_id}".format( - url='/group_configurations/' + six.text_type(self.location.course_key), + url='/group_configurations/' + str(self.location.course_key), configuration_id=str(user_partition.id) ) @@ -751,4 +749,4 @@ class SplitTestBlock( runtime=self.system, ) self.children.append(dest_usage_key) # pylint: disable=no-member - self.group_id_to_child[six.text_type(group.id)] = dest_usage_key + self.group_id_to_child[str(group.id)] = dest_usage_key diff --git a/common/lib/xmodule/xmodule/static_content.py b/common/lib/xmodule/xmodule/static_content.py index 58e03bd05ac5d0f3e87512430c6d34cdf53937e0..bf48f37883a9d03d8ed2140ea7ae1d602f2dfb3f 100755 --- a/common/lib/xmodule/xmodule/static_content.py +++ b/common/lib/xmodule/xmodule/static_content.py @@ -16,7 +16,6 @@ from collections import defaultdict from pkg_resources import resource_string import django -import six from docopt import docopt from path import Path as path @@ -179,7 +178,7 @@ def _write_styles(selector, output_root, classes, css_attribute): module_styles_lines.append("""{selector}.xmodule_{class_} {{""".format( class_=class_, selector=selector )) - module_styles_lines.extend(' @import "{0}";'.format(name) for name in fragment_names) + module_styles_lines.extend(f' @import "{name}";' for name in fragment_names) module_styles_lines.append('}') contents['_module-styles.scss'] = '\n'.join(module_styles_lines) @@ -236,7 +235,7 @@ def _write_files(output_root, contents, generated_suffix_map=None): will be ignored """ _ensure_dir(output_root) - to_delete = set(file.basename() for file in output_root.files()) - set(contents.keys()) + to_delete = {file.basename() for file in output_root.files()} - set(contents.keys()) if generated_suffix_map: for output_file in contents.keys(): @@ -247,7 +246,7 @@ def _write_files(output_root, contents, generated_suffix_map=None): for extra_file in to_delete: (output_root / extra_file).remove_p() - for filename, file_content in six.iteritems(contents): + for filename, file_content in contents.items(): output_file = output_root / filename not_file = not output_file.isfile() @@ -255,7 +254,7 @@ def _write_files(output_root, contents, generated_suffix_map=None): # Sometimes content is already unicode and sometimes it's not # so we add this conditional here to make sure that below we're # always working with streams of bytes. - if not isinstance(file_content, six.binary_type): + if not isinstance(file_content, bytes): file_content = file_content.encode('utf-8') # not_file is included to short-circuit this check, because @@ -280,7 +279,7 @@ def write_webpack(output_file, module_files, descriptor_files): 'entry': {} } for (owner, files) in list(module_files.items()) + list(descriptor_files.items()): - unique_files = sorted(set('./{}'.format(file) for file in files)) + unique_files = sorted({f'./{file}' for file in files}) if len(unique_files) == 1: unique_files = unique_files[0] config['entry'][owner] = unique_files @@ -289,7 +288,7 @@ def write_webpack(output_file, module_files, descriptor_files): with output_file.open('w') as outfile: outfile.write( - textwrap.dedent(u"""\ + textwrap.dedent("""\ module.exports = {config_json}; """).format( config_json=json.dumps( diff --git a/common/lib/xmodule/xmodule/stringify.py b/common/lib/xmodule/xmodule/stringify.py index 0ff52846d18e334071a5abc67c452ff370ec8860..c97af7232338cdb90d97ed41d29405599b079298 100644 --- a/common/lib/xmodule/xmodule/stringify.py +++ b/common/lib/xmodule/xmodule/stringify.py @@ -1,5 +1,4 @@ # lint-amnesty, pylint: disable=missing-module-docstring -# -*- coding: utf-8 -*- from lxml import etree @@ -28,4 +27,4 @@ def stringify_children(node): parts.append(etree.tostring(c, with_tail=True, encoding='unicode')) # filter removes possible Nones in texts and tails - return u''.join([part for part in parts if part]) + return ''.join([part for part in parts if part]) diff --git a/common/lib/xmodule/xmodule/studio_editable.py b/common/lib/xmodule/xmodule/studio_editable.py index 241953935cab7e9d6b3438110888d15992385322..8352c781d14e206155dba973e81a1db27d4ac8d3 100644 --- a/common/lib/xmodule/xmodule/studio_editable.py +++ b/common/lib/xmodule/xmodule/studio_editable.py @@ -1,13 +1,10 @@ """ Mixin to support editing in Studio. """ - - -import six from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW, module_attr -class StudioEditableBlock(object): +class StudioEditableBlock: """ Helper methods for supporting Studio editing of XBlocks. @@ -30,7 +27,7 @@ class StudioEditableBlock(object): fragment.add_fragment_resources(rendered_child) contents.append({ - 'id': six.text_type(child.location), + 'id': str(child.location), 'content': rendered_child.content }) @@ -52,7 +49,7 @@ class StudioEditableBlock(object): StudioEditableModule = StudioEditableBlock -class StudioEditableDescriptor(object): +class StudioEditableDescriptor: """ Helper mixin for supporting Studio editing of xmodules. diff --git a/common/lib/xmodule/xmodule/tabs.py b/common/lib/xmodule/xmodule/tabs.py index 5e1a7747846cbc33dfd150444f9775cba8c36089..40ed7863da8781af9a7c10e8040948326ea317c9 100644 --- a/common/lib/xmodule/xmodule/tabs.py +++ b/common/lib/xmodule/xmodule/tabs.py @@ -6,9 +6,7 @@ Implement CourseTab import logging from abc import ABCMeta -import six from django.core.files.storage import get_storage_class -from six import text_type from xblock.fields import List from edx_django_utils.plugins import PluginError @@ -23,7 +21,7 @@ _ = lambda text: text READ_ONLY_COURSE_TAB_ATTRIBUTES = ['type'] -class CourseTab(six.with_metaclass(ABCMeta, object)): +class CourseTab(metaclass=ABCMeta): """ The Course Tab class is a data abstraction for all tabs (i.e., course navigation links) within a course. It is an abstract class - to be inherited by various tab types. @@ -85,7 +83,7 @@ class CourseTab(six.with_metaclass(ABCMeta, object)): Args: tab_dict (dict) - a dictionary of parameters used to build the tab. """ - super(CourseTab, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() self.name = tab_dict.get('name', self.title) self.tab_id = tab_dict.get('tab_id', getattr(self, 'tab_id', self.type)) self.course_staff_only = tab_dict.get('course_staff_only', False) @@ -129,7 +127,7 @@ class CourseTab(six.with_metaclass(ABCMeta, object)): if hasattr(self, key): return getattr(self, key, None) else: - raise KeyError('Key {0} not present in tab {1}'.format(key, self.to_json())) + raise KeyError(f'Key {key} not present in tab {self.to_json()}') def __setitem__(self, key, value): """ @@ -141,7 +139,7 @@ class CourseTab(six.with_metaclass(ABCMeta, object)): if hasattr(self, key) and key not in READ_ONLY_COURSE_TAB_ATTRIBUTES: setattr(self, key, value) else: - raise KeyError('Key {0} cannot be set in tab {1}'.format(key, self.to_json())) + raise KeyError(f'Key {key} cannot be set in tab {self.to_json()}') def __eq__(self, other): """ @@ -245,14 +243,14 @@ class CourseTab(six.with_metaclass(ABCMeta, object)): return tab_type(tab_dict=tab_dict) -class TabFragmentViewMixin(object): +class TabFragmentViewMixin: """ A mixin for tabs that render themselves as web fragments. """ fragment_view_name = None def __init__(self, tab_dict): - super(TabFragmentViewMixin, self).__init__(tab_dict) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(tab_dict) self._fragment_view = None @property @@ -261,12 +259,12 @@ class TabFragmentViewMixin(object): # If a view_name is specified, then use the default link function if self.view_name: - return super(TabFragmentViewMixin, self).link_func # lint-amnesty, pylint: disable=super-with-arguments + return super().link_func # If not, then use the generic course tab URL def link_func(course, reverse_func): """ Returns a function that returns the course tab's URL. """ - return reverse_func("course_tab_view", args=[text_type(course.id), self.type]) + return reverse_func("course_tab_view", args=[str(course.id), self.type]) return link_func @@ -290,7 +288,7 @@ class TabFragmentViewMixin(object): """ Renders this tab to a web fragment. """ - return self.fragment_view.render_to_fragment(request, course_id=six.text_type(course.id), **kwargs) + return self.fragment_view.render_to_fragment(request, course_id=str(course.id), **kwargs) def __hash__(self): """ Return a hash representation of Tab Object. """ @@ -308,7 +306,7 @@ class StaticTab(CourseTab): def __init__(self, tab_dict=None, name=None, url_slug=None): def link_func(course, reverse_func): """ Returns a function that returns the static tab's URL. """ - return reverse_func(self.type, args=[text_type(course.id), self.url_slug]) + return reverse_func(self.type, args=[str(course.id), self.url_slug]) self.url_slug = tab_dict.get('url_slug') if tab_dict else url_slug @@ -319,9 +317,9 @@ class StaticTab(CourseTab): tab_dict['name'] = name tab_dict['link_func'] = link_func - tab_dict['tab_id'] = 'static_tab_{0}'.format(self.url_slug) + tab_dict['tab_id'] = f'static_tab_{self.url_slug}' - super(StaticTab, self).__init__(tab_dict) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(tab_dict) @classmethod def is_enabled(cls, course, user=None): @@ -335,29 +333,29 @@ class StaticTab(CourseTab): """ Ensures that the specified tab_dict is valid. """ - return (super(StaticTab, cls).validate(tab_dict, raise_error) + return (super().validate(tab_dict, raise_error) and key_checker(['name', 'url_slug'])(tab_dict, raise_error)) def __getitem__(self, key): if key == 'url_slug': return self.url_slug else: - return super(StaticTab, self).__getitem__(key) # lint-amnesty, pylint: disable=super-with-arguments + return super().__getitem__(key) def __setitem__(self, key, value): if key == 'url_slug': self.url_slug = value else: - super(StaticTab, self).__setitem__(key, value) # lint-amnesty, pylint: disable=super-with-arguments + super().__setitem__(key, value) def to_json(self): """ Return a dictionary representation of this tab. """ - to_json_val = super(StaticTab, self).to_json() # lint-amnesty, pylint: disable=super-with-arguments + to_json_val = super().to_json() to_json_val.update({'url_slug': self.url_slug}) return to_json_val def __eq__(self, other): - if not super(StaticTab, self).__eq__(other): # lint-amnesty, pylint: disable=super-with-arguments + if not super().__eq__(other): return False return self.url_slug == other.get('url_slug') @@ -461,8 +459,7 @@ class CourseTabList(List): # If rendering inline that add each item in the collection, # else just show the tab itself as long as it is not empty. if inline_collections: - for item in tab.items(course): - yield item + yield from tab.items(course) elif len(list(tab.items(course))) > 0: yield tab else: @@ -496,15 +493,15 @@ class CourseTabList(List): return if len(tabs) < 2: - raise InvalidTabsException("Expected at least two tabs. tabs: '{0}'".format(tabs)) + raise InvalidTabsException(f"Expected at least two tabs. tabs: '{tabs}'") if tabs[0].get('type') != 'course_info': raise InvalidTabsException( - "Expected first tab to have type 'course_info'. tabs: '{0}'".format(tabs)) + f"Expected first tab to have type 'course_info'. tabs: '{tabs}'") if tabs[1].get('type') != 'courseware': raise InvalidTabsException( - "Expected second tab to have type 'courseware'. tabs: '{0}'".format(tabs)) + f"Expected second tab to have type 'courseware'. tabs: '{tabs}'") # the following tabs should appear only once # TODO: don't import openedx capabilities from common @@ -574,7 +571,7 @@ def key_checker(expected_keys): return True if raise_error: # lint-amnesty, pylint: disable=no-else-raise raise InvalidTabsException( - "Expected keys '{0}' are not present in the given dict: {1}".format(expected_keys, actual_dict) + f"Expected keys '{expected_keys}' are not present in the given dict: {actual_dict}" ) else: return False @@ -620,7 +617,7 @@ def course_reverse_func_from_name_func(reverse_name_func): """ return lambda course, reverse_url_func: reverse_url_func( reverse_name_func(course), - args=[text_type(course.id)] + args=[str(course.id)] ) diff --git a/common/lib/xmodule/xmodule/template_module.py b/common/lib/xmodule/xmodule/template_module.py index a94cf457fa29e7262707e2da18a4d5b704e99508..8a5211353e207dba7e580b86b948387971fdd5be 100644 --- a/common/lib/xmodule/xmodule/template_module.py +++ b/common/lib/xmodule/xmodule/template_module.py @@ -93,7 +93,7 @@ class CustomTagBlock( template_name = child_impl.text else: # TODO (vshnayder): better exception type - raise Exception("Could not find impl attribute in customtag {0}" + raise Exception("Could not find impl attribute in customtag {}" .format(self.location)) params = dict(list(xmltree.items())) diff --git a/common/lib/xmodule/xmodule/tests/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py index f8b531aa52e8aaf76ac4d78320e69a25b1c6c483..5f3639a7bedaef9cba11d54ce918a1940e83b2af 100644 --- a/common/lib/xmodule/xmodule/tests/__init__.py +++ b/common/lib/xmodule/xmodule/tests/__init__.py @@ -17,14 +17,12 @@ import traceback import unittest from contextlib import contextmanager from functools import wraps +from unittest.mock import Mock -import six from django.test import TestCase from django.utils.encoding import python_2_unicode_compatible -from mock import Mock from opaque_keys.edx.keys import CourseKey from path import Path as path -from six import text_type from xblock.core import XBlock from xblock.field_data import DictFieldData from xblock.fields import Reference, ReferenceList, ReferenceValueDict, ScopeIds @@ -53,11 +51,11 @@ class TestModuleSystem(ModuleSystem): # pylint: disable=abstract-method kwargs.setdefault('id_reader', id_manager) kwargs.setdefault('id_generator', id_manager) kwargs.setdefault('services', {}).setdefault('field-data', DictFieldData({})) - super(TestModuleSystem, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) def handler_url(self, block, handler, suffix='', query='', thirdparty=False): # lint-amnesty, pylint: disable=arguments-differ return '{usage_id}/{handler}{suffix}?{query}'.format( - usage_id=six.text_type(block.scope_ids.usage_id), + usage_id=str(block.scope_ids.usage_id), handler=handler, suffix=suffix, query=query, @@ -65,7 +63,7 @@ class TestModuleSystem(ModuleSystem): # pylint: disable=abstract-method def local_resource_url(self, block, uri): return 'resource/{usage_id}/{uri}'.format( - usage_id=six.text_type(block.scope_ids.usage_id), + usage_id=str(block.scope_ids.usage_id), uri=uri, ) @@ -84,7 +82,7 @@ class TestModuleSystem(ModuleSystem): # pylint: disable=abstract-method if hasattr(self, '_view_name'): orig_view_name = self._view_name self._view_name = None - rt_repr = super(TestModuleSystem, self).__repr__() # lint-amnesty, pylint: disable=super-with-arguments + rt_repr = super().__repr__() self._view_name = orig_view_name return rt_repr @@ -202,12 +200,12 @@ def map_references(value, field, actual_course_key): if isinstance(field, ReferenceList): return [sub.map_into_course(actual_course_key) for sub in value] if isinstance(field, ReferenceValueDict): - return {key: ele.map_into_course(actual_course_key) for key, ele in six.iteritems(value)} + return {key: ele.map_into_course(actual_course_key) for key, ele in value.items()} return value @python_2_unicode_compatible -class LazyFormat(object): +class LazyFormat: """ An stringy object that delays formatting until it's put into a string context. """ @@ -225,13 +223,13 @@ class LazyFormat(object): return self._message def __repr__(self): - return six.text_type(self) + return str(self) def __len__(self): - return len(six.text_type(self)) + return len(str(self)) def __getitem__(self, index): - return six.text_type(self)[index] + return str(self)[index] class CourseComparisonTest(TestCase): @@ -240,7 +238,7 @@ class CourseComparisonTest(TestCase): """ def setUp(self): - super(CourseComparisonTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.field_exclusions = set() self.ignored_asset_keys = set() @@ -283,8 +281,8 @@ class CourseComparisonTest(TestCase): expected = [extract_key(key) for key in expected] actual = [extract_key(key) for key in actual] elif isinstance(reference_field, ReferenceValueDict): - expected = {key: extract_key(val) for (key, val) in six.iteritems(expected)} - actual = {key: extract_key(val) for (key, val) in six.iteritems(actual)} + expected = {key: extract_key(val) for (key, val) in expected.items()} + actual = {key: extract_key(val) for (key, val) in actual.items()} assert expected == actual,\ LazyFormat("Field {} doesn't match between usages {} and {}: {!r} != {!r}", reference_field.name, @@ -365,8 +363,7 @@ class CourseComparisonTest(TestCase): } # Split Mongo and Old-Mongo disagree about what the block_id of courses is, so skip those in # this comparison - six.assertCountEqual( - self, + self.assertCountEqual( [map_key(item.location) for item in expected_items if item.scope_ids.block_type != 'course'], [key for key in actual_item_map.keys() if key[0] != 'course'], ) @@ -387,7 +384,7 @@ class CourseComparisonTest(TestCase): continue # compare fields assert expected_item.fields == actual_item.fields - for field_name, field in six.iteritems(expected_item.fields): + for field_name, field in expected_item.fields.items(): if (expected_item.scope_ids.usage_id, field_name) in self.field_exclusions: continue if (None, field_name) in self.field_exclusions: @@ -428,8 +425,8 @@ class CourseComparisonTest(TestCase): expected_filename = expected_asset.pop('filename') actual_filename = actual_asset.pop('filename') - assert text_type(expected_key) == expected_filename - assert text_type(actual_key) == actual_filename + assert str(expected_key) == expected_filename + assert str(actual_key) == actual_filename assert expected_asset == actual_asset def _assertAssetsEqual(self, expected_course_key, expected_assets, actual_course_key, actual_assets): # pylint: disable=invalid-name diff --git a/common/lib/xmodule/xmodule/tests/helpers.py b/common/lib/xmodule/xmodule/tests/helpers.py index 63d8c0bdd4e1067a3e253396745b46c8cb31a685..42156049fdc5d331adacd07c2a9579ad10f3de97 100644 --- a/common/lib/xmodule/xmodule/tests/helpers.py +++ b/common/lib/xmodule/xmodule/tests/helpers.py @@ -36,7 +36,7 @@ class StubUserService(UserService): def __init__(self, is_anonymous=False, **kwargs): self.is_anonymous = is_anonymous - super(StubUserService, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) def get_current_user(self): """ diff --git a/common/lib/xmodule/xmodule/tests/test_annotatable_module.py b/common/lib/xmodule/xmodule/tests/test_annotatable_module.py index c7e909f111b27c63ffd291ee89935399269a835a..5cdbac7b62656b25d5008937e74da7eaf5780cc1 100644 --- a/common/lib/xmodule/xmodule/tests/test_annotatable_module.py +++ b/common/lib/xmodule/xmodule/tests/test_annotatable_module.py @@ -68,7 +68,7 @@ class AnnotatableBlockTestCase(unittest.TestCase): # lint-amnesty, pylint: disa for color in self.annotatable.HIGHLIGHT_COLORS: el = etree.fromstring(xml.format(highlight=color)) - value = 'annotatable-span highlight highlight-{highlight}'.format(highlight=color) + value = f'annotatable-span highlight highlight-{color}' expected_attr = { 'class': { @@ -126,7 +126,7 @@ class AnnotatableBlockTestCase(unittest.TestCase): # lint-amnesty, pylint: disa def test_extract_instructions(self): xmltree = etree.fromstring(self.sample_xml) - expected_xml = u"<div>Read the text.</div>" + expected_xml = "<div>Read the text.</div>" actual_xml = self.annotatable._extract_instructions(xmltree) # lint-amnesty, pylint: disable=protected-access assert actual_xml is not None assert expected_xml.strip() == actual_xml.strip() diff --git a/common/lib/xmodule/xmodule/tests/test_annotator_mixin.py b/common/lib/xmodule/xmodule/tests/test_annotator_mixin.py index 813e265d8e95551c450f0b0bc6216acb4214288e..baaa7ad5d905e4b30c68bed549ad4cbdca559790 100644 --- a/common/lib/xmodule/xmodule/tests/test_annotator_mixin.py +++ b/common/lib/xmodule/xmodule/tests/test_annotator_mixin.py @@ -30,7 +30,7 @@ class HelperFunctionTest(unittest.TestCase): """ xmltree = etree.fromstring(self.sample_xml) - expected_xml = u"<div><p>Helper Test Instructions.</p></div>" + expected_xml = "<div><p>Helper Test Instructions.</p></div>" actual_xml = get_instructions(xmltree) assert actual_xml is not None assert expected_xml.strip() == actual_xml.strip() diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index 30ee3e078263f3db6da77c888c8ce461ac45ddc8..a3351277b3a647fc5df7834f9dcb5ead8d43d2be 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Tests of the Capa XModule """ @@ -11,19 +10,17 @@ import os import random import textwrap import unittest +from unittest.mock import DEFAULT, Mock, patch import pytest import ddt import requests -import six import webob from django.utils.encoding import smart_text from edx_user_state_client.interface import XBlockUserState from lxml import etree -from mock import DEFAULT, Mock, patch from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator from pytz import UTC -from six.moves import range, zip from webob.multidict import MultiDict from xblock.field_data import DictFieldData from xblock.fields import ScopeIds @@ -41,7 +38,7 @@ from ..capa_base import RANDOMIZATION, SHOWANSWER from . import get_test_system -class CapaFactory(object): +class CapaFactory: """ A helper class to create problem modules with various parameters for testing. """ @@ -101,7 +98,7 @@ class CapaFactory(object): location = BlockUsageLocator( CourseLocator("edX", "capa_test", "2012_Fall", deprecated=True), "problem", - "SampleProblem{0}".format(cls.next_num()), + f"SampleProblem{cls.next_num()}", deprecated=True, ) if xml is None: @@ -182,7 +179,7 @@ if submission[0] == '': class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring def setUp(self): - super(ProblemBlockTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() now = datetime.datetime.now(UTC) day_delta = datetime.timedelta(days=1) @@ -861,8 +858,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss assert xqueue_interface._http_post.call_count == 1 _, kwargs = xqueue_interface._http_post.call_args - six.assertCountEqual(self, fpaths, list(kwargs['files'].keys())) - for fpath, fileobj in six.iteritems(kwargs['files']): + self.assertCountEqual(fpaths, list(kwargs['files'].keys())) + for fpath, fileobj in kwargs['files'].items(): assert fpath == fileobj.name def test_submit_problem_with_files_as_xblock(self): @@ -894,8 +891,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss assert xqueue_interface._http_post.call_count == 1 _, kwargs = xqueue_interface._http_post.call_args - six.assertCountEqual(self, fnames, list(kwargs['files'].keys())) - for fpath, fileobj in six.iteritems(kwargs['files']): + self.assertCountEqual(fnames, list(kwargs['files'].keys())) + for fpath, fileobj in kwargs['files'].items(): assert fpath == fileobj.name def test_submit_problem_error(self): @@ -947,7 +944,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss ' File "<string>", line 65, in check_func\\n' 'Exception: Couldn\'t execute jailed code\\n\' with status code: 1', ) except ResponseError as err: - mock_grade.side_effect = exception_class(six.text_type(err)) + mock_grade.side_effect = exception_class(str(err)) get_request_dict = {CapaFactory.input_key(): '3.14'} result = module.submit_problem(get_request_dict) @@ -974,7 +971,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # Simulate answering a problem that raises the exception with patch('capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade: - error_msg = u"Superterrible error happened: ☠" + error_msg = "Superterrible error happened: ☠" mock_grade.side_effect = Exception(error_msg) get_request_dict = {CapaFactory.input_key(): '3.14'} @@ -1009,13 +1006,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # Simulate answering a problem that raises the exception with patch('capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade: - mock_grade.side_effect = exception_class(u"ȧƈƈḗƞŧḗḓ ŧḗẋŧ Æ’Ç¿Å™ Å§á¸—ÅŸÅ§Ä«ÆžÉ ") + mock_grade.side_effect = exception_class("ȧƈƈḗƞŧḗḓ ŧḗẋŧ Æ’Ç¿Å™ Å§á¸—ÅŸÅ§Ä«ÆžÉ ") get_request_dict = {CapaFactory.input_key(): '3.14'} result = module.submit_problem(get_request_dict) # Expect an AJAX alert message in 'success' - expected_msg = u'ȧƈƈḗƞŧḗḓ ŧḗẋŧ Æ’Ç¿Å™ Å§á¸—ÅŸÅ§Ä«ÆžÉ ' + expected_msg = 'ȧƈƈḗƞŧḗḓ ŧḗẋŧ Æ’Ç¿Å™ Å§á¸—ÅŸÅ§Ä«ÆžÉ ' assert expected_msg == result['success'] @@ -1241,7 +1238,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # Simulate answering a problem that raises the exception with patch('capa.capa_problem.LoncapaProblem.get_grade_from_current_answers') as mock_rescore: - mock_rescore.side_effect = exception_class(u'test error \u03a9') + mock_rescore.side_effect = exception_class('test error \u03a9') with pytest.raises(exception_class): module.rescore(only_if_higher=False) @@ -1710,7 +1707,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss # Simulate throwing an exception when the capa problem # is asked to render itself as HTML - error_msg = u"Superterrible error happened: ☠" + error_msg = "Superterrible error happened: ☠" module.lcp.get_html = Mock(side_effect=Exception(error_msg)) # Stub out the get_test_system rendering function @@ -2527,7 +2524,7 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m self.assertDictEqual( indexing_result, { 'content_type': ProblemBlock.INDEX_CONTENT_TYPE, - 'problem_types': set(["optionresponse", "multiplechoiceresponse"]), + 'problem_types': {"optionresponse", "multiplechoiceresponse"}, 'content': { 'display_name': name, 'capa_content': " Label Some comment Donut Buggy '1','2' " @@ -2569,7 +2566,7 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m def test_indexing_checkboxes(self): name = "Checkboxes" descriptor = self._create_descriptor(self.sample_checkbox_problem_xml, name=name) - capa_content = textwrap.dedent(u""" + capa_content = textwrap.dedent(""" Title Description Example @@ -2856,7 +2853,7 @@ class ProblemCheckTrackingTest(unittest.TestCase): """ def setUp(self): - super(ProblemCheckTrackingTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.maxDiff = None def test_choice_answer_text(self): @@ -2909,14 +2906,14 @@ class ProblemCheckTrackingTest(unittest.TestCase): 'group_label': '', 'variant': ''}, factory.answer_key(3): {'question': 'Which piece of furniture is built for sitting?', - 'answer': u'<text>a table</text>', + 'answer': '<text>a table</text>', 'response_type': 'multiplechoiceresponse', 'input_type': 'choicegroup', 'correct': False, 'group_label': '', 'variant': ''}, factory.answer_key(4): {'question': 'Which of the following are musical instruments?', - 'answer': [u'a piano', u'a tree'], + 'answer': ['a piano', 'a tree'], 'response_type': 'choiceresponse', 'input_type': 'checkboxgroup', 'correct': False, @@ -3160,14 +3157,14 @@ class ProblemBlockReportGenerationTest(unittest.TestCase): def _mock_user_state_generator(self, user_count=1, response_count=10): for uid in range(user_count): - yield self._user_state(username='user{}'.format(uid), response_count=response_count) + yield self._user_state(username=f'user{uid}', response_count=response_count) def _user_state(self, username='testuser', response_count=10, suffix=''): return XBlockUserState( username=username, state={ 'student_answers': { - '{}_answerid_{}{}'.format(username, aid, suffix): '{}_answer_{}'.format(username, aid) + f'{username}_answerid_{aid}{suffix}': f'{username}_answer_{aid}' for aid in range(response_count) }, 'seed': 1, diff --git a/common/lib/xmodule/xmodule/tests/test_conditional.py b/common/lib/xmodule/xmodule/tests/test_conditional.py index 02d2a746f89d355b2eb5d02205da95cfebd03758..201c5fd6c5bc8e3aba73d913b636c970f6cbb823 100644 --- a/common/lib/xmodule/xmodule/tests/test_conditional.py +++ b/common/lib/xmodule/xmodule/tests/test_conditional.py @@ -2,13 +2,12 @@ import json import unittest +from unittest.mock import Mock, patch from fs.memoryfs import MemoryFS 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 six import text_type from web_fragments.fragment import Fragment from xblock.field_data import DictFieldData from xblock.fields import ScopeIds @@ -33,7 +32,7 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho xmlstore = XMLModuleStore("data_dir", source_dirs=[], load_error_modules=load_error_modules) - super(DummySystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( xmlstore=xmlstore, course_id=CourseKey.from_string('/'.join([ORG, COURSE, 'test_run'])), course_dir='test_dir', @@ -52,7 +51,7 @@ class ConditionalBlockFactory(xml.XmlImportFactory): tag = 'conditional' -class ConditionalFactory(object): +class ConditionalFactory: """ A helper class to create a conditional module and associated source and child modules to allow for testing. @@ -89,7 +88,7 @@ class ConditionalFactory(object): # construct other descriptors: child_descriptor = Mock(name='child_descriptor') child_descriptor.visible_to_staff_only = False - child_descriptor._xmodule.student_view.return_value = Fragment(content=u'<p>This is a secret</p>') # lint-amnesty, pylint: disable=protected-access + child_descriptor._xmodule.student_view.return_value = Fragment(content='<p>This is a secret</p>') # lint-amnesty, pylint: disable=protected-access child_descriptor.student_view = child_descriptor._xmodule.student_view # lint-amnesty, pylint: disable=protected-access child_descriptor.displayable_items.return_value = [child_descriptor] child_descriptor.runtime = descriptor_system @@ -149,7 +148,7 @@ class ConditionalBlockBasicTest(unittest.TestCase): """ def setUp(self): - super(ConditionalBlockBasicTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.test_system = get_test_system() def test_icon_class(self): @@ -168,8 +167,8 @@ class ConditionalBlockBasicTest(unittest.TestCase): html = modules['cond_module'].render(STUDENT_VIEW).content expected = modules['cond_module'].xmodule_runtime.render_template('conditional_ajax.html', { 'ajax_url': modules['cond_module'].ajax_url, - 'element_id': u'i4x-edX-conditional_test-conditional-SampleConditional', - 'depends': u'i4x-edX-conditional_test-problem-SampleProblem', + 'element_id': 'i4x-edX-conditional_test-conditional-SampleConditional', + 'depends': 'i4x-edX-conditional_test-problem-SampleProblem', }) assert expected == html @@ -226,12 +225,12 @@ class ConditionalBlockXmlTest(unittest.TestCase): return DummySystem(load_error_modules) def setUp(self): - super(ConditionalBlockXmlTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.test_system = get_test_system() 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, source_dirs=[name]) courses = modulestore.get_courses() @@ -280,9 +279,9 @@ class ConditionalBlockXmlTest(unittest.TestCase): 'conditional_ajax.html', { # Test ajax url is just usage-id / handler_name - 'ajax_url': '{}/xmodule_handler'.format(text_type(location)), - 'element_id': u'i4x-HarvardX-ER22x-conditional-condone', - 'depends': u'i4x-HarvardX-ER22x-problem-choiceprob' + 'ajax_url': '{}/xmodule_handler'.format(str(location)), + 'element_id': 'i4x-HarvardX-ER22x-conditional-condone', + 'depends': 'i4x-HarvardX-ER22x-problem-choiceprob' } ) assert html == html_expect @@ -443,7 +442,7 @@ class ConditionalBlockStudioTest(XModuleXmlImportTest): """ self.conditional.sources_list = None validation = self.conditional.validate() - assert validation.summary.text == u'This component has no source components configured yet.' + assert validation.summary.text == 'This component has no source components configured yet.' assert validation.summary.type == StudioValidationMessage.NOT_CONFIGURED assert validation.summary.action_class == 'edit-button' - assert validation.summary.action_label == u'Configure list of sources' + assert validation.summary.action_label == 'Configure list of sources'