refactor: pyupgrade in common/lib/xmodule (#26781)

This commit is contained in:
M. Zulqarnain
2021-03-10 17:55:49 +05:00
committed by GitHub
parent ba4708edd0
commit 8aec103447
50 changed files with 543 additions and 599 deletions

View File

@@ -3,9 +3,9 @@
import os
import unittest
from unittest.mock import Mock, patch
import ddt
from mock import Mock, patch
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import AssetLocator, CourseLocator
from path import Path as path
@@ -54,7 +54,7 @@ injected humour and the like).
"""
class Content(object):
class Content:
"""
A class with location and content_type members
"""
@@ -64,7 +64,7 @@ class Content(object):
self.data = None
class FakeGridFsItem(object):
class FakeGridFsItem:
"""
This class provides the basic methods to get data from a GridFS item
"""
@@ -112,19 +112,19 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
assert content.thumbnail_location is None
@ddt.data(
(u"monsters__.jpg", u"monsters__.jpg"),
(u"monsters__.png", u"monsters__-png.jpg"),
(u"dots.in.name.jpg", u"dots.in.name.jpg"),
(u"dots.in.name.png", u"dots.in.name-png.jpg"),
("monsters__.jpg", "monsters__.jpg"),
("monsters__.png", "monsters__-png.jpg"),
("dots.in.name.jpg", "dots.in.name.jpg"),
("dots.in.name.png", "dots.in.name-png.jpg"),
)
@ddt.unpack
def test_generate_thumbnail_image(self, original_filename, thumbnail_filename):
content_store = ContentStore()
content = Content(AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'asset', original_filename),
content = Content(AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'asset', original_filename),
None)
(thumbnail_content, thumbnail_file_location) = content_store.generate_thumbnail(content)
assert thumbnail_content is None
assert AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename) ==\
assert AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'thumbnail', thumbnail_filename) ==\
thumbnail_file_location
@patch('xmodule.contentstore.content.Image')
@@ -135,7 +135,7 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
image_class_mock.open.return_value = mock_image
content_store = ContentStore()
content = Content(AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'asset', "monsters.jpg"),
content = Content(AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'asset', "monsters.jpg"),
"image/jpeg")
content.data = b'mock data'
content_store.generate_thumbnail(content)
@@ -147,13 +147,13 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
# SVG files should be stored in original form for thumbnail purposes.
content_store = ContentStore()
content_store.save = Mock()
thumbnail_filename = u'test.svg'
content = Content(AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'asset', u'test.svg'),
thumbnail_filename = 'test.svg'
content = Content(AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'asset', 'test.svg'),
'image/svg+xml')
content.data = b'mock svg file'
(thumbnail_content, thumbnail_file_location) = content_store.generate_thumbnail(content)
assert thumbnail_content.data.read() == b'mock svg file'
assert AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename) ==\
assert AssetLocator(CourseLocator('mitX', '800', 'ignore_run'), 'thumbnail', thumbnail_filename) ==\
thumbnail_file_location
def test_compute_location(self):
@@ -162,13 +162,13 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
asset_location = StaticContent.compute_location(
CourseKey.from_string('mitX/400/ignore'), 'subs__1eo_jXvZnE .srt.sjson'
)
assert AssetLocator(CourseLocator(u'mitX', u'400', u'ignore', deprecated=True),
u'asset', u'subs__1eo_jXvZnE_.srt.sjson') == asset_location
assert AssetLocator(CourseLocator('mitX', '400', 'ignore', deprecated=True),
'asset', 'subs__1eo_jXvZnE_.srt.sjson') == asset_location
def test_get_location_from_path(self):
asset_location = StaticContent.get_location_from_path(u'/c4x/a/b/asset/images_course_image.jpg')
assert AssetLocator(CourseLocator(u'a', u'b', None, deprecated=True),
u'asset', u'images_course_image.jpg', deprecated=True) == asset_location
asset_location = StaticContent.get_location_from_path('/c4x/a/b/asset/images_course_image.jpg')
assert AssetLocator(CourseLocator('a', 'b', None, deprecated=True),
'asset', 'images_course_image.jpg', deprecated=True) == asset_location
def test_static_content_stream_stream_data(self):
"""
@@ -210,8 +210,8 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
"""
Test that only one filename starts with 000.
"""
output_root = path(u'common/static/xmodule/descriptors/js')
output_root = path('common/static/xmodule/descriptors/js')
file_owners = _write_js(output_root, _list_descriptors(), 'get_studio_view_js')
js_file_paths = set(file_path for file_path in sum(list(file_owners.values()), []) if os.path.basename(file_path).startswith('000-')) # lint-amnesty, pylint: disable=line-too-long
js_file_paths = {file_path for file_path in sum(list(file_owners.values()), []) if os.path.basename(file_path).startswith('000-')} # lint-amnesty, pylint: disable=line-too-long
assert len(js_file_paths) == 1
assert 'XModule.Descriptor = (function() {' in open(js_file_paths.pop()).read()

View File

@@ -44,7 +44,7 @@ class CourseMetadataUtilsTestCase(TestCase):
"""
Set up module store testing capabilities and initialize test courses.
"""
super(CourseMetadataUtilsTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
mongo_builder = MongoModulestoreBuilder()
split_builder = VersioningModulestoreBuilder()

View File

@@ -4,13 +4,14 @@
import itertools
import unittest
from datetime import datetime, timedelta
from unittest.mock import Mock, patch
import pytest
import ddt
from dateutil import parser
from django.conf import settings
from django.test import override_settings
from fs.memoryfs import MemoryFS
from mock import Mock, patch
from opaque_keys.edx.keys import CourseKey
from pytz import utc
from xblock.runtime import DictKeyValueStore, KvsFieldData
@@ -46,7 +47,7 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho
course_dir = "test_dir"
error_tracker = Mock()
super(DummySystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(
xmlstore=xmlstore,
course_id=course_id,
course_dir=course_dir,
@@ -62,7 +63,7 @@ def get_dummy_course(start, announcement=None, is_new=None, advertised_start=Non
system = DummySystem(load_error_modules=True)
def to_attrb(n, v):
return '' if v is None else '{0}="{1}"'.format(n, v).lower()
return '' if v is None else f'{n}="{v}"'.lower()
is_new = to_attrb('is_new', is_new)
announcement = to_attrb('announcement', announcement)
@@ -100,7 +101,7 @@ class HasEndedMayCertifyTestCase(unittest.TestCase):
"""Double check the semantics around when to finalize courses."""
def setUp(self):
super(HasEndedMayCertifyTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
system = DummySystem(load_error_modules=True) # lint-amnesty, pylint: disable=unused-variable
#sample_xml = """
@@ -161,7 +162,7 @@ class IsNewCourseTestCase(unittest.TestCase):
"""Make sure the property is_new works on courses"""
def setUp(self):
super(IsNewCourseTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
# Needed for test_is_newish
datetime_patcher = patch.object(
@@ -210,13 +211,13 @@ class IsNewCourseTestCase(unittest.TestCase):
for a, b, assertion in dates:
a_score = get_dummy_course(start=a[0], announcement=a[1], advertised_start=a[2]).sorting_score
b_score = get_dummy_course(start=b[0], announcement=b[1], advertised_start=b[2]).sorting_score
print("Comparing %s to %s" % (a, b))
print(f"Comparing {a} to {b}")
assertion(a_score, b_score)
start_advertised_settings = [
# start, advertised, result, is_still_default, date_time_result
('2012-12-02T12:00', None, 'Dec 02, 2012', False, u'Dec 02, 2012 at 12:00 UTC'),
('2012-12-02T12:00', '2011-11-01T12:00', 'Nov 01, 2011', False, u'Nov 01, 2011 at 12:00 UTC'),
('2012-12-02T12:00', None, 'Dec 02, 2012', False, 'Dec 02, 2012 at 12:00 UTC'),
('2012-12-02T12:00', '2011-11-01T12:00', 'Nov 01, 2011', False, 'Nov 01, 2011 at 12:00 UTC'),
('2012-12-02T12:00', 'Spring 2012', 'Spring 2012', False, 'Spring 2012'),
('2012-12-02T12:00', 'November, 2011', 'November, 2011', False, 'November, 2011'),
(xmodule.course_module.CourseFields.start.default, None, 'TBD', True, 'TBD'),
@@ -231,12 +232,12 @@ class IsNewCourseTestCase(unittest.TestCase):
def test_display_organization(self):
descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True)
assert descriptor.location.org != descriptor.display_org_with_default
assert descriptor.display_org_with_default == '{0}_display'.format(ORG)
assert descriptor.display_org_with_default == f'{ORG}_display'
def test_display_coursenumber(self):
descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True)
assert descriptor.location.course != descriptor.display_number_with_default
assert descriptor.display_number_with_default == '{0}_display'.format(COURSE)
assert descriptor.display_number_with_default == f'{COURSE}_display'
def test_is_newish(self):
descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True)
@@ -274,7 +275,7 @@ class TeamsConfigurationTestCase(unittest.TestCase):
"""
def setUp(self):
super(TeamsConfigurationTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course = get_dummy_course('2012-12-02T12:00')
self.course.teams_configuration = TeamsConfig(None)
self.count = itertools.count()
@@ -290,9 +291,9 @@ class TeamsConfigurationTestCase(unittest.TestCase):
def make_topic(self):
""" Make a sample topic dictionary. """
next_num = next(self.count)
topic_id = "topic_id_{}".format(next_num)
name = "Name {}".format(next_num)
description = "Description {}".format(next_num)
topic_id = f"topic_id_{next_num}"
name = f"Name {next_num}"
description = f"Description {next_num}"
return {
"name": name,
"description": description,
@@ -363,7 +364,7 @@ class SelfPacedTestCase(unittest.TestCase):
"""Tests for self-paced courses."""
def setUp(self):
super(SelfPacedTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course = get_dummy_course('2012-12-02T12:00')
def test_default(self):
@@ -427,7 +428,7 @@ class ProctoringProviderTestCase(unittest.TestCase):
"""
Initialize dummy testing course.
"""
super(ProctoringProviderTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.proctoring_provider = xmodule.course_module.ProctoringProvider()
def test_from_json_with_platform_default(self):
@@ -447,7 +448,7 @@ class ProctoringProviderTestCase(unittest.TestCase):
throws a ValueError with the correct error message.
"""
provider = 'invalid-provider'
allowed_proctoring_providers = [u'mock', u'mock_proctoring_without_rules']
allowed_proctoring_providers = ['mock', 'mock_proctoring_without_rules']
with pytest.raises(ValueError) as context_manager:
self.proctoring_provider.from_json(provider)

View File

@@ -11,9 +11,9 @@ submissions" setting is set to different values
import datetime
import textwrap
import unittest
from unittest.mock import Mock
import pytest
from mock import Mock
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from pytz import UTC
from xblock.field_data import DictFieldData
@@ -26,7 +26,7 @@ from xmodule.capa_module import ProblemBlock
from . import get_test_system
class CapaFactoryWithDelay(object):
class CapaFactoryWithDelay:
"""
Create problem modules class, specialized for delay_between_attempts
test cases. This factory seems different enough from the one in
@@ -88,7 +88,7 @@ class CapaFactoryWithDelay(object):
Optional parameters here are cut down to what we actually use vs. the regular CapaFactory.
"""
location = BlockUsageLocator(CourseLocator('edX', 'capa_test', 'run', deprecated=True),
'problem', 'SampleProblem{0}'.format(cls.next_num()), deprecated=True)
'problem', f'SampleProblem{cls.next_num()}', deprecated=True)
field_data = {'data': cls.sample_problem_xml}
if max_attempts is not None:

View File

@@ -4,8 +4,8 @@
import logging
import os
import unittest
from unittest.mock import Mock
from mock import Mock
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from pkg_resources import resource_string
from xblock.field_data import DictFieldData
@@ -21,7 +21,7 @@ class TabsEditingDescriptorTestCase(unittest.TestCase):
""" Testing TabsEditingDescriptor"""
def setUp(self):
super(TabsEditingDescriptorTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
system = get_test_descriptor_system()
system.render_template = Mock(return_value="<div>Test Template HTML</div>")
self.tabs = [

View File

@@ -4,9 +4,9 @@ Tests for ErrorBlock and NonStaffErrorBlock
import unittest
from unittest.mock import MagicMock, Mock, patch
import pytest
from mock import MagicMock, Mock, patch
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
@@ -27,7 +27,7 @@ class SetupTestErrorBlock(unittest.TestCase):
self.system = get_test_system()
self.course_id = CourseLocator('org', 'course', 'run')
self.location = self.course_id.make_usage_key('foo', 'bar')
self.valid_xml = u"<problem>ABC \N{SNOWMAN}</problem>"
self.valid_xml = "<problem>ABC \N{SNOWMAN}</problem>"
self.error_msg = "Error"
@@ -107,7 +107,7 @@ class TestNonStaffErrorBlock(SetupTestErrorBlock):
class BrokenModule(XModule): # lint-amnesty, pylint: disable=abstract-method
def __init__(self, *args, **kwargs):
super(BrokenModule, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(*args, **kwargs)
raise Exception("This is a broken xmodule")

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Tests of XML export
"""
@@ -9,17 +8,16 @@ import unittest
from datetime import datetime, timedelta, tzinfo
from tempfile import mkdtemp
from textwrap import dedent
from unittest import mock
import pytest
import ddt
import lxml.etree
import mock
import pytz
import six
from django.utils.translation import ugettext_lazy
from fs.osfs import OSFS
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from path import Path as path
from six import text_type
from xblock.core import XBlock
from xblock.fields import Integer, Scope, String
from xblock.test.tools import blocks_are_equivalent
@@ -34,7 +32,7 @@ def strip_filenames(descriptor):
"""
Recursively strips 'filename' from all children's definitions.
"""
print("strip filename from {desc}".format(desc=text_type(descriptor.location)))
print("strip filename from {desc}".format(desc=str(descriptor.location)))
if descriptor._field_data.has(descriptor, 'filename'): # lint-amnesty, pylint: disable=protected-access
descriptor._field_data.delete(descriptor, 'filename') # lint-amnesty, pylint: disable=protected-access
@@ -67,7 +65,7 @@ class RoundTripTestCase(unittest.TestCase):
"""
def setUp(self):
super(RoundTripTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.maxDiff = None
self.temp_dir = mkdtemp()
self.addCleanup(shutil.rmtree, self.temp_dir)
@@ -75,14 +73,14 @@ class RoundTripTestCase(unittest.TestCase):
@mock.patch('xmodule.video_module.video_module.edxval_api', None)
@mock.patch('xmodule.course_module.requests.get')
@ddt.data(
u"toy",
u"simple",
u"conditional_and_poll",
u"conditional",
u"self_assessment",
u"test_exam_registration",
u"word_cloud",
u"pure_xblock",
"toy",
"simple",
"conditional_and_poll",
"conditional",
"self_assessment",
"test_exam_registration",
"word_cloud",
"pure_xblock",
)
@XBlock.register_temp_plugin(PureXBlock, 'pure')
def test_export_roundtrip(self, course_dir, mock_get):
@@ -95,7 +93,7 @@ class RoundTripTestCase(unittest.TestCase):
""").strip()
root_dir = path(self.temp_dir)
print("Copying test course to temp dir {0}".format(root_dir))
print(f"Copying test course to temp dir {root_dir}")
data_dir = path(DATA_DIR)
shutil.copytree(data_dir / course_dir, root_dir / course_dir)
@@ -137,8 +135,7 @@ class RoundTripTestCase(unittest.TestCase):
course_id = initial_course.id
print("Checking key equality")
six.assertCountEqual(
self,
self.assertCountEqual(
list(initial_import.modules[course_id].keys()),
list(second_import.modules[course_id].keys())
)
@@ -156,7 +153,7 @@ class TestEdxJsonEncoder(unittest.TestCase):
"""
def setUp(self):
super(TestEdxJsonEncoder, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.encoder = EdxJSONEncoder()
@@ -175,10 +172,10 @@ class TestEdxJsonEncoder(unittest.TestCase):
def test_encode_location(self):
loc = BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'category', 'name')
assert text_type(loc) == self.encoder.default(loc)
assert str(loc) == self.encoder.default(loc)
loc = BlockUsageLocator(CourseLocator('org', 'course', 'run', branch='version'), 'category', 'name')
assert text_type(loc) == self.encoder.default(loc)
assert str(loc) == self.encoder.default(loc)
def test_encode_naive_datetime(self):
assert '2013-05-03T10:20:30.000100' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 100))
@@ -204,7 +201,7 @@ class TestEdxJsonEncoder(unittest.TestCase):
"""
# Initializing a lazy text object with Unicode
unicode_text = u"Your 𝓟𝓵𝓪𝓽𝓯𝓸𝓻𝓶 Name Here"
unicode_text = "Your 𝓟𝓵𝓪𝓽𝓯𝓸𝓻𝓶 Name Here"
lazy_text = ugettext_lazy(unicode_text) # lint-amnesty, pylint: disable=translation-of-non-string
assert unicode_text == self.encoder.default(lazy_text)

View File

@@ -78,7 +78,7 @@ class DateTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-clas
"""
now = datetime.datetime.now(UTC)
delta = now - datetime.datetime.fromtimestamp(0, UTC)
assert DateTest.date.from_json((delta.total_seconds() * 1000)) == now
assert DateTest.date.from_json(delta.total_seconds() * 1000) == now
yesterday = datetime.datetime.now(UTC) - datetime.timedelta(days=-1)
assert DateTest.date.from_json(yesterday) == yesterday

View File

@@ -8,8 +8,6 @@ from datetime import datetime, timedelta
import pytest
import ddt
from pytz import UTC
import six
from six import text_type
from lms.djangoapps.grades.scores import compute_percent
from xmodule import graders
@@ -68,7 +66,7 @@ class GraderTest(unittest.TestCase):
'Midterm': {},
}
class MockGrade(object):
class MockGrade:
"""
Mock class for SubsectionGrade object.
"""
@@ -319,25 +317,25 @@ class GraderTest(unittest.TestCase):
(
# empty
{},
u"Configuration has no appropriate grader class."
"Configuration has no appropriate grader class."
),
(
# no min_count
{'type': "Homework", 'drop_count': 0},
u"Configuration has no appropriate grader class."
"Configuration has no appropriate grader class."
),
(
# no drop_count
{'type': "Homework", 'min_count': 0},
# pylint: disable=line-too-long
u"__init__() takes at least 4 arguments (3 given)" if six.PY2 else u"__init__() missing 1 required positional argument: 'drop_count'"
"__init__() missing 1 required positional argument: 'drop_count'"
),
)
@ddt.unpack
def test_grader_with_invalid_conf(self, invalid_conf, expected_error_message):
with pytest.raises(ValueError) as error:
graders.grader_from_conf([invalid_conf])
assert expected_error_message in text_type(error.value)
assert expected_error_message in str(error.value)
@ddt.ddt
@@ -347,7 +345,7 @@ class ShowCorrectnessTest(unittest.TestCase):
"""
def setUp(self):
super(ShowCorrectnessTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
now = datetime.now(UTC)
day_delta = timedelta(days=1)

View File

@@ -1,10 +1,10 @@
# lint-amnesty, pylint: disable=missing-module-docstring
import unittest
from unittest.mock import Mock
import ddt
from django.test.utils import override_settings
from mock import Mock
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
@@ -312,7 +312,7 @@ class CourseInfoBlockTestCase(unittest.TestCase):
],
'hidden_updates': [],
}
template_name = "{0}/course_updates.html".format(info_module.TEMPLATE_DIR)
template_name = f"{info_module.TEMPLATE_DIR}/course_updates.html"
info_module.get_html()
# Assertion to validate that render function is called with the expected context
info_module.system.render_template.assert_called_once_with(

View File

@@ -1,19 +1,17 @@
# lint-amnesty, pylint: disable=missing-module-docstring
# -*- coding: utf-8 -*-
import datetime
from tempfile import mkdtemp
from unittest.mock import Mock, patch
import ddt
from django.test import TestCase
from fs.osfs import OSFS
from lxml import etree
from mock import Mock, patch
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from pytz import UTC
from six import text_type
from xblock.core import XBlock
from xblock.fields import Integer, Scope, String
from xblock.runtime import DictKeyValueStore, KvsFieldData
@@ -44,7 +42,7 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho
course_dir = "test_dir"
error_tracker = Mock()
super(DummySystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(
xmlstore=xmlstore,
course_id=course_id,
course_dir=course_dir,
@@ -68,7 +66,7 @@ class BaseCourseTestCase(TestCase):
def get_course(self, name):
"""Get a test course by directory name. If there's more than one, error."""
print("Importing {0}".format(name))
print(f"Importing {name}")
modulestore = XMLModuleStore(
DATA_DIR,
@@ -126,7 +124,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
'''Check that malformed xml loads as an ErrorBlock.'''
# Use an exotic character to also flush out Unicode issues.
bad_xml = u'''<sequential display_name="oops\N{SNOWMAN}"><video url="hi"></sequential>'''
bad_xml = '''<sequential display_name="oops\N{SNOWMAN}"><video url="hi"></sequential>'''
system = self.get_system()
descriptor = system.process_xml(bad_xml)
@@ -208,7 +206,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
# Now export and check things
file_system = OSFS(mkdtemp())
descriptor.runtime.export_fs = file_system.makedir(u'course', recreate=True)
descriptor.runtime.export_fs = file_system.makedir('course', recreate=True)
node = etree.Element('unknown')
descriptor.add_xml_to_node(node)
@@ -220,7 +218,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
assert node.attrib['org'] == ORG
# Does the course still have unicorns?
with descriptor.runtime.export_fs.open(u'course/{course_run}.xml'.format(course_run=course_run)) as f:
with descriptor.runtime.export_fs.open(f'course/{course_run}.xml') as f:
course_xml = etree.fromstring(f.read())
assert course_xml.attrib['unicorn'] == unicorn_color
@@ -234,7 +232,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
# Does the chapter tag now have a due attribute?
# hardcoded path to child
with descriptor.runtime.export_fs.open(u'chapter/ch.xml') as f:
with descriptor.runtime.export_fs.open('chapter/ch.xml') as f:
chapter_xml = etree.fromstring(f.read())
assert chapter_xml.tag == 'chapter'
assert 'due' not in chapter_xml.attrib
@@ -426,11 +424,11 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
"""]
for xml_str in yes:
print("should be True for {0}".format(xml_str))
print(f"should be True for {xml_str}")
assert is_pointer_tag(etree.fromstring(xml_str))
for xml_str in no:
print("should be False for {0}".format(xml_str))
print(f"should be False for {xml_str}")
assert not is_pointer_tag(etree.fromstring(xml_str))
def test_metadata_inherit(self):
@@ -441,7 +439,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
def check_for_key(key, node, value):
"recursive check for presence of key"
print("Checking {0}".format(text_type(node.location)))
print("Checking {}".format(str(node.location)))
assert getattr(node, key) == value
for c in node.get_children():
check_for_key(key, c, value)
@@ -561,7 +559,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
in modulestore.get_course_errors(course.id)
]
assert any((((expect in msg) or (expect in err)) for (msg, err) in errors))
assert any(((expect in msg) or (expect in err)) for (msg, err) in errors)
chapters = course.get_children()
assert len(chapters) == 4
@@ -584,7 +582,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
for i in (2, 3):
video = sections[i]
# Name should be 'video_{hash}'
print("video {0} url_name: {1}".format(i, video.url_name))
print(f"video {i} url_name: {video.url_name}")
assert len(video.url_name) == (len('video_') + 12)
def test_poll_and_conditional_import(self):
@@ -608,7 +606,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
assert module.poll_answer == ''
assert module.poll_answers == {}
assert module.answers ==\
[{'text': u'Yes', 'id': 'Yes'}, {'text': u'No', 'id': 'No'}, {'text': u"Don't know", 'id': 'Dont_know'}]
[{'text': 'Yes', 'id': 'Yes'}, {'text': 'No', 'id': 'No'}, {'text': "Don't know", 'id': 'Dont_know'}]
def test_error_on_import(self):
'''Check that when load_error_module is false, an exception is raised, rather than returning an ErrorBlock'''

View File

@@ -4,8 +4,8 @@ Tests that check that we ignore the appropriate files when importing courses.
import unittest
from unittest.mock import Mock
from mock import Mock
from opaque_keys.edx.locator import CourseLocator
from xmodule.modulestore.tests.utils import (
@@ -26,7 +26,7 @@ class IgnoredFilesTestCase(unittest.TestCase):
dict_list = [DOT_FILES_DICT, TILDA_FILES_DICT]
def setUp(self):
super(IgnoredFilesTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
for dictionary in self.dict_list:
self.addCleanup(remove_temp_files_from_list, list(dictionary.keys()), self.course_dir / "static")
add_temp_files_from_dict(dictionary, self.course_dir / "static")

View File

@@ -1,18 +1,14 @@
# -*- coding: utf-8 -*-
"""
Basic unit tests for LibraryContentBlock
Higher-level tests are in `cms/djangoapps/contentstore/tests/test_libraries.py`.
"""
from unittest.mock import Mock, patch
import six
from bson.objectid import ObjectId
from fs.memoryfs import MemoryFS
from lxml import etree
from mock import Mock, patch
from search.search_engine_base import SearchEngine
from six.moves import range
from web_fragments.fragment import Fragment
from xblock.runtime import Runtime as VanillaRuntime
@@ -35,12 +31,12 @@ class LibraryContentTest(MixedSplitTestCase):
Base class for tests of LibraryContentBlock (library_content_block.py)
"""
def setUp(self):
super(LibraryContentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.tools = LibraryToolsService(self.store, self.user_id)
self.library = LibraryFactory.create(modulestore=self.store)
self.lib_blocks = [
self.make_block("html", self.library, data="Hello world from block {}".format(i))
self.make_block("html", self.library, data=f"Hello world from block {i}")
for i in range(1, 5)
]
self.course = CourseFactory.create(modulestore=self.store)
@@ -51,7 +47,7 @@ class LibraryContentTest(MixedSplitTestCase):
"library_content",
self.vertical,
max_count=1,
source_library_id=six.text_type(self.library.location.library_key)
source_library_id=str(self.library.location.library_key)
)
def _bind_course_module(self, module):
@@ -138,7 +134,7 @@ class TestLibraryContentExportImport(LibraryContentTest):
assert imported_lc_block.children == lc_block.children
class LibraryContentBlockTestMixin(object):
class LibraryContentBlockTestMixin:
"""
Basic unit tests for LibraryContentBlock
"""
@@ -222,7 +218,7 @@ class LibraryContentBlockTestMixin(object):
assert 'invalid' in result.summary.text
# When source_library_id is set but the block needs to be updated, the summary should say so:
self.lc_block.source_library_id = six.text_type(self.library.location.library_key)
self.lc_block.source_library_id = str(self.library.location.library_key)
result = self.lc_block.validate()
assert not result
# Validation fails due to at least one warning/message
@@ -385,7 +381,7 @@ class TestLibraryContentBlockWithSearchIndex(LibraryContentBlockTestMixin, Libra
def setUp(self):
""" Sets up search engine mock """
super(TestLibraryContentBlockWithSearchIndex, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
search_index_mock.search = Mock(side_effect=self._get_search_response)
@@ -427,7 +423,7 @@ class TestLibraryContentAnalytics(LibraryContentTest):
"""
def setUp(self):
super(TestLibraryContentAnalytics, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.publisher = Mock()
self.lc_block.refresh_children()
self.lc_block = self.store.get_item(self.lc_block.location)
@@ -441,8 +437,8 @@ class TestLibraryContentAnalytics(LibraryContentTest):
assert self.publisher.called
assert len(self.publisher.call_args[0]) == 3 # pylint:disable=unsubscriptable-object
_, event_name, event_data = self.publisher.call_args[0] # pylint:disable=unsubscriptable-object
assert event_name == 'edx.librarycontentblock.content.{}'.format(event_type)
assert event_data['location'] == six.text_type(self.lc_block.location)
assert event_name == f'edx.librarycontentblock.content.{event_type}'
assert event_data['location'] == str(self.lc_block.location)
return event_data
def test_assigned_event(self):
@@ -455,13 +451,13 @@ class TestLibraryContentAnalytics(LibraryContentTest):
assert isinstance(child_lib_version, ObjectId)
event_data = self._assert_event_was_published("assigned")
block_info = {
"usage_key": six.text_type(child.location),
"original_usage_key": six.text_type(child_lib_location),
"original_usage_version": six.text_type(child_lib_version),
"usage_key": str(child.location),
"original_usage_key": str(child_lib_location),
"original_usage_version": str(child_lib_version),
"descendants": [],
}
assert event_data ==\
{'location': six.text_type(self.lc_block.location),
{'location': str(self.lc_block.location),
'added': [block_info],
'result': [block_info],
'previous_count': 0, 'max_count': 1}
@@ -473,7 +469,7 @@ class TestLibraryContentAnalytics(LibraryContentTest):
assert len(children) == 2
child, new_child = children if children[0].location == child.location else reversed(children)
event_data = self._assert_event_was_published("assigned")
assert event_data['added'][0]['usage_key'] == six.text_type(new_child.location)
assert event_data['added'][0]['usage_key'] == str(new_child.location)
assert len(event_data['result']) == 2
assert event_data['previous_count'] == 1
assert event_data['max_count'] == 2
@@ -521,7 +517,7 @@ class TestLibraryContentAnalytics(LibraryContentTest):
for block_list in (event_data["added"], event_data["result"]):
assert len(block_list) == 1
# main_vertical is the only root block added, and is the only result.
assert block_list[0]['usage_key'] == six.text_type(course_usage_main_vertical)
assert block_list[0]['usage_key'] == str(course_usage_main_vertical)
# Check that "descendants" is a flat, unordered list of all of main_vertical's descendants:
descendants_expected = (
@@ -531,10 +527,10 @@ class TestLibraryContentAnalytics(LibraryContentTest):
)
descendant_data_expected = {}
for lib_key, course_usage_key in descendants_expected:
descendant_data_expected[six.text_type(course_usage_key)] = {
"usage_key": six.text_type(course_usage_key),
"original_usage_key": six.text_type(lib_key),
"original_usage_version": six.text_type(self.store.get_block_original_usage(course_usage_key)[1]),
descendant_data_expected[str(course_usage_key)] = {
"usage_key": str(course_usage_key),
"original_usage_key": str(lib_key),
"original_usage_version": str(self.store.get_block_original_usage(course_usage_key)[1]),
}
assert len(block_list[0]['descendants']) == len(descendant_data_expected)
for descendant in block_list[0]["descendants"]:
@@ -585,12 +581,12 @@ class TestLibraryContentAnalytics(LibraryContentTest):
assert len(children) == 1
event_data = self._assert_event_was_published("removed")
assert event_data['removed'] ==\
[{'usage_key': six.text_type(deleted_block_key),
[{'usage_key': str(deleted_block_key),
'original_usage_key': None,
'original_usage_version': None,
'descendants': []}]
assert event_data['result'] ==\
[{'usage_key': six.text_type(keep_block_key),
'original_usage_key': six.text_type(keep_block_lib_usage_key),
'original_usage_version': six.text_type(keep_block_lib_version), 'descendants': []}]
[{'usage_key': str(keep_block_key),
'original_usage_key': str(keep_block_lib_usage_key),
'original_usage_version': str(keep_block_lib_version), 'descendants': []}]
assert event_data['reason'] == 'invalid'

View File

@@ -1,11 +1,9 @@
# -*- coding: utf-8 -*-
"""
Basic unit tests for LibraryRoot
"""
from mock import patch
from six.moves import range
from unittest.mock import patch
from web_fragments.fragment import Fragment
from xblock.runtime import Runtime as VanillaRuntime
@@ -34,7 +32,7 @@ class TestLibraryRoot(MixedSplitTestCase):
We have to patch the runtime (module system) in order to be able to
render blocks in our test environment.
"""
message = u"Hello world"
message = "Hello world"
library = LibraryFactory.create(modulestore=self.store)
# Add one HTML block to the library:
ItemFactory.create(

View File

@@ -28,7 +28,7 @@ class LibrarySourcedBlockTestCase(ContentLibrariesRestApiTest):
user_id=self.user.id,
modulestore=self.store
)
self.submit_url = '/xblock/{0}/handler/submit_studio_edits'.format(self.source_block.scope_ids.usage_id)
self.submit_url = f'/xblock/{self.source_block.scope_ids.usage_id}/handler/submit_studio_edits'
def test_block_views(self):
# Create a blockstore content library
@@ -52,7 +52,7 @@ class LibrarySourcedBlockTestCase(ContentLibrariesRestApiTest):
# Create a blockstore content library
library = self._create_library(slug="testlib2_preview", title="Test Library 2", description="Testing XBlocks")
# Add content to the library
blocks = [self._add_block_to_library(library["id"], "html", "block_{0}".format(i))["id"] for i in range(11)]
blocks = [self._add_block_to_library(library["id"], "html", f"block_{i}")["id"] for i in range(11)]
# Import the html blocks from the library to the course
post_data = {"values": {"source_block_ids": blocks}, "defaults": ["display_name"]}

View File

@@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
"""Tests for LTI Xmodule LTIv2.0 functional logic."""
import datetime
import textwrap
import unittest
from unittest.mock import Mock
from mock import Mock
from pytz import UTC
from xblock.field_data import DictFieldData
@@ -20,7 +19,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
"""Logic tests for LTI module. LTI2.0 REST ResultService"""
def setUp(self):
super(LTI20RESTResultServiceTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.system = get_test_system()
self.environ = {'wsgi.url_scheme': 'http', 'REQUEST_METHOD': 'POST'}
self.system.get_real_user = Mock()
@@ -43,9 +42,9 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.xmodule.lti_id = "lti_id"
test_cases = ( # (before sanitize, after sanitize)
(u"plaintext", u"plaintext"),
(u"a <script>alert(3)</script>", u"a &lt;script&gt;alert(3)&lt;/script&gt;"), # encodes scripts
(u"<b>bold 包</b>", u"<b>bold 包</b>"), # unicode, and <b> tags pass through
("plaintext", "plaintext"),
("a <script>alert(3)</script>", "a &lt;script&gt;alert(3)&lt;/script&gt;"), # encodes scripts
("<b>bold 包</b>", "<b>bold 包</b>"), # unicode, and <b> tags pass through
)
for case in test_cases:
self.xmodule.score_comment = case[0]
@@ -56,7 +55,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
Input with bad content type
"""
with self.assertRaisesRegex(LTIError, "Content-Type must be"):
request = Mock(headers={u'Content-Type': u'Non-existent'})
request = Mock(headers={'Content-Type': 'Non-existent'})
self.xmodule.verify_lti_2_0_result_rest_headers(request)
def test_lti20_rest_failed_oauth_body_verify(self):
@@ -66,7 +65,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
err_msg = "OAuth body verification failed"
self.xmodule.verify_oauth_body_sign = Mock(side_effect=LTIError(err_msg))
with self.assertRaisesRegex(LTIError, err_msg):
request = Mock(headers={u'Content-Type': u'application/vnd.ims.lis.v2.result+json'})
request = Mock(headers={'Content-Type': 'application/vnd.ims.lis.v2.result+json'})
self.xmodule.verify_lti_2_0_result_rest_headers(request)
def test_lti20_rest_good_headers(self):
@@ -75,21 +74,21 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
"""
self.xmodule.verify_oauth_body_sign = Mock(return_value=True)
request = Mock(headers={u'Content-Type': u'application/vnd.ims.lis.v2.result+json'})
request = Mock(headers={'Content-Type': 'application/vnd.ims.lis.v2.result+json'})
self.xmodule.verify_lti_2_0_result_rest_headers(request)
# We just want the above call to complete without exceptions, and to have called verify_oauth_body_sign
assert self.xmodule.verify_oauth_body_sign.called
BAD_DISPATCH_INPUTS = [
None,
u"",
u"abcd"
u"notuser/abcd"
u"user/"
u"user//"
u"user/gbere/"
u"user/gbere/xsdf"
u"user/ಠ益ಠ" # not alphanumeric
"",
"abcd"
"notuser/abcd"
"user/"
"user//"
"user/gbere/"
"user/gbere/xsdf"
"user/ಠ益ಠ" # not alphanumeric
]
def test_lti20_rest_bad_dispatch(self):
@@ -102,8 +101,8 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.xmodule.parse_lti_2_0_handler_suffix(einput)
GOOD_DISPATCH_INPUTS = [
(u"user/abcd3", u"abcd3"),
(u"user/Äbcdè2", u"Äbcdè2"), # unicode, just to make sure
("user/abcd3", "abcd3"),
("user/Äbcdè2", "Äbcdè2"), # unicode, just to make sure
]
def test_lti20_rest_good_dispatch(self):
@@ -117,40 +116,40 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
BAD_JSON_INPUTS = [
# (bad inputs, error message expected)
([
u"kk", # ValueError
u"{{}", # ValueError
u"{}}", # ValueError
"kk", # ValueError
"{{}", # ValueError
"{}}", # ValueError
3, # TypeError
{}, # TypeError
], u"Supplied JSON string in request body could not be decoded"),
], "Supplied JSON string in request body could not be decoded"),
([
u"3", # valid json, not array or object
u"[]", # valid json, array too small
u"[3, {}]", # valid json, 1st element not an object
], u"Supplied JSON string is a list that does not contain an object as the first element"),
"3", # valid json, not array or object
"[]", # valid json, array too small
"[3, {}]", # valid json, 1st element not an object
], "Supplied JSON string is a list that does not contain an object as the first element"),
([
u'{"@type": "NOTResult"}', # @type key must have value 'Result'
], u"JSON object does not contain correct @type attribute"),
'{"@type": "NOTResult"}', # @type key must have value 'Result'
], "JSON object does not contain correct @type attribute"),
([
# @context missing
u'{"@type": "Result", "resultScore": 0.1}',
], u"JSON object does not contain required key"),
'{"@type": "Result", "resultScore": 0.1}',
], "JSON object does not contain required key"),
([
u'''
'''
{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"resultScore": 100}''' # score out of range
], u"score value outside the permitted range of 0-1."),
], "score value outside the permitted range of 0-1."),
([
u'''
'''
{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"resultScore": "1b"}''', # score ValueError
u'''
'''
{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"resultScore": {}}''', # score TypeError
], u"Could not convert resultScore to float"),
], "Could not convert resultScore to float"),
]
def test_lti20_bad_json(self):
@@ -163,20 +162,20 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.xmodule.parse_lti_2_0_result_json(einput)
GOOD_JSON_INPUTS = [
(u'''
('''
{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"resultScore": 0.1}''', u""), # no comment means we expect ""
(u'''
"resultScore": 0.1}''', ""), # no comment means we expect ""
('''
[{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"@id": "anon_id:abcdef0123456789",
"resultScore": 0.1}]''', u""), # OK to have array of objects -- just take the first. @id is okay too
(u'''
"resultScore": 0.1}]''', ""), # OK to have array of objects -- just take the first. @id is okay too
('''
{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"resultScore": 0.1,
"comment": "ಠ益ಠ"}''', u"ಠ益ಠ"), # unicode comment
"comment": "ಠ益ಠ"}''', "ಠ益ಠ"), # unicode comment
]
def test_lti20_good_json(self):
@@ -188,7 +187,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
assert score == 0.1
assert comment == expected_comment
GOOD_JSON_PUT = textwrap.dedent(u"""
GOOD_JSON_PUT = textwrap.dedent("""
{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"@id": "anon_id:abcdef0123456789",
@@ -196,14 +195,14 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
"comment": "ಠ益ಠ"}
""").encode('utf-8')
GOOD_JSON_PUT_LIKE_DELETE = textwrap.dedent(u"""
GOOD_JSON_PUT_LIKE_DELETE = textwrap.dedent("""
{"@type": "Result",
"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
"@id": "anon_id:abcdef0123456789",
"comment": "ಠ益ಠ"}
""").encode('utf-8')
def get_signed_lti20_mock_request(self, body, method=u'PUT'):
def get_signed_lti20_mock_request(self, body, method='PUT'):
"""
Example of signed from LTI 2.0 Provider. Signatures and hashes are example only and won't verify
"""
@@ -211,15 +210,15 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
mock_request.headers = {
'Content-Type': 'application/vnd.ims.lis.v2.result+json',
'Authorization': (
u'OAuth oauth_nonce="135685044251684026041377608307", '
u'oauth_timestamp="1234567890", oauth_version="1.0", '
u'oauth_signature_method="HMAC-SHA1", '
u'oauth_consumer_key="test_client_key", '
u'oauth_signature="my_signature%3D", '
u'oauth_body_hash="gz+PeJZuF2//n9hNUnDj2v5kN70="'
'OAuth oauth_nonce="135685044251684026041377608307", '
'oauth_timestamp="1234567890", oauth_version="1.0", '
'oauth_signature_method="HMAC-SHA1", '
'oauth_consumer_key="test_client_key", '
'oauth_signature="my_signature%3D", '
'oauth_body_hash="gz+PeJZuF2//n9hNUnDj2v5kN70="'
)
}
mock_request.url = u'http://testurl'
mock_request.url = 'http://testurl'
mock_request.http_method = method
mock_request.method = method
mock_request.body = body
@@ -234,7 +233,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
"""
self.system.get_real_user = Mock(return_value=self.USER_STANDIN)
self.xmodule.max_score = Mock(return_value=1.0)
self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', u'test_client_secret'))
self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
self.xmodule.verify_oauth_body_sign = Mock()
def test_lti20_put_like_delete_success(self):
@@ -243,16 +242,16 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
"""
self.setup_system_xmodule_mocks_for_lti20_request_test()
SCORE = 0.55 # pylint: disable=invalid-name
COMMENT = u"ಠ益ಠ" # pylint: disable=invalid-name
COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name
self.xmodule.module_score = SCORE
self.xmodule.score_comment = COMMENT
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT_LIKE_DELETE)
# Now call the handler
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
# Now assert there's no score
assert response.status_code == 200
assert self.xmodule.module_score is None
assert self.xmodule.score_comment == u''
assert self.xmodule.score_comment == ''
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence
assert called_grade_obj ==\
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True}
@@ -264,16 +263,16 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
"""
self.setup_system_xmodule_mocks_for_lti20_request_test()
SCORE = 0.55 # pylint: disable=invalid-name
COMMENT = u"ಠ益ಠ" # pylint: disable=invalid-name
COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name
self.xmodule.module_score = SCORE
self.xmodule.score_comment = COMMENT
mock_request = self.get_signed_lti20_mock_request(b"", method=u'DELETE')
mock_request = self.get_signed_lti20_mock_request(b"", method='DELETE')
# Now call the handler
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
# Now assert there's no score
assert response.status_code == 200
assert self.xmodule.module_score is None
assert self.xmodule.score_comment == u''
assert self.xmodule.score_comment == ''
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence
assert called_grade_obj ==\
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True}
@@ -286,11 +285,11 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.setup_system_xmodule_mocks_for_lti20_request_test()
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
# Now call the handler
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
# Now assert
assert response.status_code == 200
assert self.xmodule.module_score == 0.1
assert self.xmodule.score_comment == u'ಠ益ಠ'
assert self.xmodule.score_comment == 'ಠ益ಠ'
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence
assert evt_type == 'grade'
assert called_grade_obj ==\
@@ -301,9 +300,9 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
The happy path for LTI 2.0 GET when there's no score
"""
self.setup_system_xmodule_mocks_for_lti20_request_test()
mock_request = self.get_signed_lti20_mock_request(b"", method=u'GET')
mock_request = self.get_signed_lti20_mock_request(b"", method='GET')
# Now call the handler
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
# Now assert
assert response.status_code == 200
assert response.json == {'@context': 'http://purl.imsglobal.org/ctx/lis/v2/Result', '@type': 'Result'}
@@ -314,12 +313,12 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
"""
self.setup_system_xmodule_mocks_for_lti20_request_test()
SCORE = 0.55 # pylint: disable=invalid-name
COMMENT = u"ಠ益ಠ" # pylint: disable=invalid-name
COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name
self.xmodule.module_score = SCORE
self.xmodule.score_comment = COMMENT
mock_request = self.get_signed_lti20_mock_request(b"", method=u'GET')
mock_request = self.get_signed_lti20_mock_request(b"", method='GET')
# Now call the handler
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
# Now assert
assert response.status_code == 200
assert response.json ==\
@@ -336,7 +335,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
for bad_method in self.UNSUPPORTED_HTTP_METHODS:
mock_request.method = bad_method
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
assert response.status_code == 404
def test_lti20_request_handler_bad_headers(self):
@@ -346,7 +345,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.setup_system_xmodule_mocks_for_lti20_request_test()
self.xmodule.verify_lti_2_0_result_rest_headers = Mock(side_effect=LTIError())
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
assert response.status_code == 401
def test_lti20_request_handler_bad_dispatch_user(self):
@@ -365,7 +364,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.setup_system_xmodule_mocks_for_lti20_request_test()
self.xmodule.parse_lti_2_0_result_json = Mock(side_effect=LTIError())
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
assert response.status_code == 404
def test_lti20_request_handler_bad_user(self):
@@ -375,7 +374,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.setup_system_xmodule_mocks_for_lti20_request_test()
self.system.get_real_user = Mock(return_value=None)
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
assert response.status_code == 404
def test_lti20_request_handler_grade_past_due(self):
@@ -386,5 +385,5 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
self.xmodule.due = datetime.datetime.now(UTC)
self.xmodule.accept_grades_past_due = False
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
assert response.status_code == 404

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Test for LTI Xmodule functional logic."""
@@ -6,14 +5,13 @@ import datetime
import textwrap
import unittest
from copy import copy
from unittest.mock import Mock, PropertyMock, patch
from urllib import parse
import pytest
import six
from lxml import etree
from mock import Mock, PropertyMock, patch
from opaque_keys.edx.locator import BlockUsageLocator
from pytz import UTC
from six import text_type
from webob.request import Request
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
@@ -31,7 +29,7 @@ class LTIBlockTest(unittest.TestCase):
def setUp(self):
super().setUp()
self.environ = {'wsgi.url_scheme': 'http', 'REQUEST_METHOD': 'POST'}
self.request_body_xml_template = textwrap.dedent(u"""
self.request_body_xml_template = textwrap.dedent("""
<?xml version = "1.0" encoding = "UTF-8"?>
<imsx_POXEnvelopeRequest xmlns = "{namespace}">
<imsx_POXHeader>
@@ -69,11 +67,11 @@ class LTIBlockTest(unittest.TestCase):
ScopeIds(None, None, None, BlockUsageLocator(self.system.course_id, 'lti', 'name'))
)
self.lti_id = self.xmodule.lti_id
self.unquoted_resource_link_id = u'{}-i4x-2-3-lti-31de800015cf4afb973356dbe81496df'.format(
self.unquoted_resource_link_id = '{}-i4x-2-3-lti-31de800015cf4afb973356dbe81496df'.format(
self.xmodule.runtime.hostname
)
sourced_id = u':'.join(six.moves.urllib.parse.quote(i) for i in (self.lti_id, self.unquoted_resource_link_id, self.user_id)) # lint-amnesty, pylint: disable=line-too-long
sourced_id = ':'.join(parse.quote(i) for i in (self.lti_id, self.unquoted_resource_link_id, self.user_id)) # lint-amnesty, pylint: disable=line-too-long
self.defaults = {
'namespace': "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0",
@@ -121,7 +119,7 @@ class LTIBlockTest(unittest.TestCase):
@patch(
'xmodule.lti_module.LTIBlock.get_client_key_secret',
return_value=('test_client_key', u'test_client_secret')
return_value=('test_client_key', 'test_client_secret')
)
def test_authorization_header_not_present(self, _get_key_secret):
"""
@@ -145,7 +143,7 @@ class LTIBlockTest(unittest.TestCase):
@patch(
'xmodule.lti_module.LTIBlock.get_client_key_secret',
return_value=('test_client_key', u'test_client_secret')
return_value=('test_client_key', 'test_client_secret')
)
def test_authorization_header_empty(self, _get_key_secret):
"""
@@ -234,14 +232,11 @@ class LTIBlockTest(unittest.TestCase):
request.body = self.get_request_body(params={'grade': '0,5'})
response = self.xmodule.grade_handler(request, '')
real_response = self.get_response_values(response)
if six.PY2:
msg = u'invalid literal for float(): 0,5'
else:
msg = u"could not convert string to float: '0,5'"
msg = "could not convert string to float: '0,5'"
expected_response = {
'action': None,
'code_major': 'failure',
'description': u'Request body XML parsing error: {}'.format(msg),
'description': f'Request body XML parsing error: {msg}',
'messageIdentifier': 'unknown',
}
assert response.status_code == 200
@@ -292,7 +287,7 @@ class LTIBlockTest(unittest.TestCase):
assert self.xmodule.module_score == float(self.defaults['grade'])
def test_user_id(self):
expected_user_id = text_type(six.moves.urllib.parse.quote(self.xmodule.runtime.anonymous_student_id))
expected_user_id = str(parse.quote(self.xmodule.runtime.anonymous_student_id))
real_user_id = self.xmodule.get_user_id()
assert real_user_id == expected_user_id
@@ -311,13 +306,13 @@ class LTIBlockTest(unittest.TestCase):
def test_resource_link_id(self):
with patch('xmodule.lti_module.LTIBlock.location', new_callable=PropertyMock):
self.xmodule.location.html_id = lambda: 'i4x-2-3-lti-31de800015cf4afb973356dbe81496df'
expected_resource_link_id = text_type(six.moves.urllib.parse.quote(self.unquoted_resource_link_id))
expected_resource_link_id = str(parse.quote(self.unquoted_resource_link_id))
real_resource_link_id = self.xmodule.get_resource_link_id()
assert real_resource_link_id == expected_resource_link_id
def test_lis_result_sourcedid(self):
expected_sourced_id = u':'.join(six.moves.urllib.parse.quote(i) for i in (
text_type(self.system.course_id),
expected_sourced_id = ':'.join(parse.quote(i) for i in (
str(self.system.course_id),
self.xmodule.get_resource_link_id(),
self.user_id
))
@@ -377,7 +372,7 @@ class LTIBlockTest(unittest.TestCase):
@patch('xmodule.lti_module.signature.verify_hmac_sha1', Mock(return_value=True))
@patch(
'xmodule.lti_module.LTIBlock.get_client_key_secret',
Mock(return_value=('test_client_key', u'test_client_secret'))
Mock(return_value=('test_client_key', 'test_client_secret'))
)
def test_successful_verify_oauth_body_sign(self):
"""
@@ -385,9 +380,9 @@ class LTIBlockTest(unittest.TestCase):
"""
self.xmodule.verify_oauth_body_sign(self.get_signed_grade_mock_request())
@patch('xmodule.lti_module.LTIBlock.get_outcome_service_url', Mock(return_value=u'https://testurl/'))
@patch('xmodule.lti_module.LTIBlock.get_outcome_service_url', Mock(return_value='https://testurl/'))
@patch('xmodule.lti_module.LTIBlock.get_client_key_secret',
Mock(return_value=(u'__consumer_key__', u'__lti_secret__')))
Mock(return_value=('__consumer_key__', '__lti_secret__')))
def test_failed_verify_oauth_body_sign_proxy_mangle_url(self):
"""
Oauth signing verify fail.
@@ -406,30 +401,30 @@ class LTIBlockTest(unittest.TestCase):
"""
mock_request = Mock()
mock_request.headers = {
u'X-Requested-With': u'XMLHttpRequest',
u'Content-Type': u'application/x-www-form-urlencoded',
u'Authorization': (
u'OAuth realm="https://testurl/", oauth_body_hash="wwzA3s8gScKD1VpJ7jMt9b%2BMj9Q%3D",'
u'oauth_nonce="18821463", oauth_timestamp="1409321145", '
u'oauth_consumer_key="__consumer_key__", oauth_signature_method="HMAC-SHA1", '
u'oauth_version="1.0", oauth_signature="fHsE1hhIz76/msUoMR3Lyb7Aou4%3D"'
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': (
'OAuth realm="https://testurl/", oauth_body_hash="wwzA3s8gScKD1VpJ7jMt9b%2BMj9Q%3D",'
'oauth_nonce="18821463", oauth_timestamp="1409321145", '
'oauth_consumer_key="__consumer_key__", oauth_signature_method="HMAC-SHA1", '
'oauth_version="1.0", oauth_signature="fHsE1hhIz76/msUoMR3Lyb7Aou4%3D"'
)
}
mock_request.url = u'https://testurl'
mock_request.http_method = u'POST'
mock_request.url = 'https://testurl'
mock_request.http_method = 'POST'
mock_request.method = mock_request.http_method
mock_request.body = (
u'<?xml version=\'1.0\' encoding=\'utf-8\'?>\n'
u'<imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">'
u'<imsx_POXHeader><imsx_POXRequestHeaderInfo><imsx_version>V1.0</imsx_version>'
u'<imsx_messageIdentifier>edX_fix</imsx_messageIdentifier></imsx_POXRequestHeaderInfo>'
u'</imsx_POXHeader><imsx_POXBody><replaceResultRequest><resultRecord><sourcedGUID>'
u'<sourcedId>MITxLTI/MITxLTI/201x:localhost%3A8000-i4x-MITxLTI-MITxLTI-lti-3751833a214a4f66a0d18f63234207f2'
u':363979ef768ca171b50f9d1bfb322131</sourcedId>'
u'</sourcedGUID><result><resultScore><language>en</language><textString>0.32</textString></resultScore>'
u'</result></resultRecord></replaceResultRequest></imsx_POXBody></imsx_POXEnvelopeRequest>'
).encode('utf-8')
b'<?xml version=\'1.0\' encoding=\'utf-8\'?>\n'
b'<imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">'
b'<imsx_POXHeader><imsx_POXRequestHeaderInfo><imsx_version>V1.0</imsx_version>'
b'<imsx_messageIdentifier>edX_fix</imsx_messageIdentifier></imsx_POXRequestHeaderInfo>'
b'</imsx_POXHeader><imsx_POXBody><replaceResultRequest><resultRecord><sourcedGUID>'
b'<sourcedId>MITxLTI/MITxLTI/201x:localhost%3A8000-i4x-MITxLTI-MITxLTI-lti-3751833a214a4f66a0d18f63234207f2'
b':363979ef768ca171b50f9d1bfb322131</sourcedId>'
b'</sourcedGUID><result><resultScore><language>en</language><textString>0.32</textString></resultScore>'
b'</result></resultRecord></replaceResultRequest></imsx_POXBody></imsx_POXEnvelopeRequest>'
)
return mock_request
@@ -459,7 +454,7 @@ class LTIBlockTest(unittest.TestCase):
@patch('xmodule.lti_module.signature.verify_hmac_sha1', Mock(return_value=False))
@patch(
'xmodule.lti_module.LTIBlock.get_client_key_secret',
Mock(return_value=('test_client_key', u'test_client_secret'))
Mock(return_value=('test_client_key', 'test_client_secret'))
)
def test_failed_verify_oauth_body_sign(self):
"""
@@ -480,15 +475,15 @@ class LTIBlockTest(unittest.TestCase):
mock_request.headers = {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': u'OAuth oauth_nonce="135685044251684026041377608307", \
'Authorization': 'OAuth oauth_nonce="135685044251684026041377608307", \
oauth_timestamp="1234567890", oauth_version="1.0", \
oauth_signature_method="HMAC-SHA1", \
oauth_consumer_key="test_client_key", \
oauth_signature="my_signature%3D", \
oauth_body_hash="JEpIArlNCeV4ceXxric8gJQCnBw="'
}
mock_request.url = u'http://testurl'
mock_request.http_method = u'POST'
mock_request.url = 'http://testurl'
mock_request.http_method = 'POST'
params = {}
if not namespace_lti_v1p1:
@@ -508,7 +503,7 @@ class LTIBlockTest(unittest.TestCase):
self.xmodule.oauth_params = Mock()
self.xmodule.get_input_fields()
self.xmodule.oauth_params.assert_called_with(
{u'custom_test_custom_params': u'test_custom_param_value'},
{'custom_test_custom_params': 'test_custom_param_value'},
'test_client_key', 'test_client_secret'
)
@@ -537,4 +532,4 @@ class LTIBlockTest(unittest.TestCase):
"""
Tests that LTI parameter context_id is equal to course_id.
"""
assert text_type(self.system.course_id) == self.xmodule.context_id
assert str(self.system.course_id) == self.xmodule.context_id

View File

@@ -2,8 +2,9 @@
from unittest import TestCase
from unittest.mock import Mock
import pytest
from mock import Mock
from xmodule.mako_module import MakoModuleDescriptor

View File

@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
"""Test for Poll Xmodule functional logic."""
import json
import unittest
from mock import Mock
from unittest.mock import Mock
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds

View File

@@ -2,8 +2,8 @@
import unittest
from unittest.mock import Mock
from mock import Mock
from xblock.field_data import DictFieldData
from xmodule import x_module

View File

@@ -1,10 +1,10 @@
"""
Test cases covering workflows and behaviors for the Randomize XModule
"""
from unittest.mock import Mock
from fs.memoryfs import MemoryFS
from lxml import etree
from mock import Mock
from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.utils import MixedSplitTestCase
@@ -33,7 +33,7 @@ class RandomizeBlockTest(MixedSplitTestCase):
display_name="Hello Randomize",
)
self.child_blocks = [
self.make_block("html", self.randomize_block, display_name="Hello HTML {}".format(i))
self.make_block("html", self.randomize_block, display_name=f"Hello HTML {i}")
for i in range(1, 4)
]

View File

@@ -14,12 +14,12 @@ class ResourceTemplatesTests(unittest.TestCase):
"""
def test_templates(self):
expected = set([
expected = {
'latex_html.yaml',
'zooming_image.yaml',
'announcement.yaml',
'anon_user_id.yaml'])
got = set((t['template_id'] for t in TestClass.templates()))
'anon_user_id.yaml'}
got = {t['template_id'] for t in TestClass.templates()}
assert expected == got
def test_templates_no_suchdir(self):

View File

@@ -7,14 +7,12 @@ Tests for sequence module.
import ast
import json
from datetime import datetime, timedelta
from unittest.mock import Mock, patch
import ddt
import six
from django.test.utils import override_settings
from django.utils.timezone import now
from freezegun import freeze_time
from mock import Mock, patch
from six.moves import range
from web_fragments.fragment import Fragment
from edx_toggles.toggles.testutils import override_waffle_flag
@@ -136,7 +134,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
"""
Verifies that the rendered view contains the expected position.
"""
assert "'position': {}".format(expected_position) in rendered_html
assert f"'position': {expected_position}" in rendered_html
def test_student_view_init(self):
module_system = get_test_system()
@@ -158,7 +156,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
view=view
)
self._assert_view_at_position(html, expected_position=1)
assert six.text_type(self.sequence_3_1.location) in html
assert str(self.sequence_3_1.location) in html
assert "'gated': False" in html
assert "'next_url': 'NextSequential'" in html
assert "'prev_url': 'PrevSequential'" in html
@@ -236,7 +234,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
def test_tooltip(self):
html = self._get_rendered_view(self.sequence_3_1, requested_child=None)
for child in self.sequence_3_1.children:
assert "'page_title': '{}'".format(child.block_id) in html
assert f"'page_title': '{child.block_id}'" in html
def test_hidden_content_before_due(self):
html = self._get_rendered_view(self.sequence_4_1)
@@ -291,7 +289,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
assert html['gated_content']['gated']
assert 'PrereqUrl' == html['gated_content']['prereq_url']
assert 'PrereqSectionName' == html['gated_content']['prereq_section_name']
assert six.text_type(sequence.display_name) in html['gated_content']['gated_section_name']
assert str(sequence.display_name) in html['gated_content']['gated_section_name']
assert 'NextSequential' == html['next_url']
assert 'PrevSequential' == html['prev_url']
@@ -303,7 +301,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
html = self.get_context_dict_from_string(html)
assert 'This section is a prerequisite. You must complete this section in order to unlock additional content.' == html['banner_text']
assert not html['gated_content']['gated']
assert six.text_type(sequence.location) == html['item_id']
assert str(sequence.location) == html['item_id']
assert html['gated_content']['prereq_url'] is None
assert html['gated_content']['prereq_section_name'] is None
assert 'NextSequential' == html['next_url']
@@ -316,7 +314,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
assert 'seq_module.html' in html
assert "'banner_text': None" in html
assert "'gated': False" in html
assert six.text_type(sequence.location) in html
assert str(sequence.location) in html
assert "'prereq_url': None" in html
assert "'prereq_section_name': None" in html
assert "'next_url': 'NextSequential'" in html
@@ -377,7 +375,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
targeted vertical through ajax call
"""
for child in self.sequence_3_1.get_children():
usage_key = six.text_type(child.location)
usage_key = str(child.location)
completion_return = json.loads(self.sequence_3_1.handle_ajax(
'get_completion',
{'usage_key': usage_key}

View File

@@ -1,14 +1,12 @@
"""
Tests for SettingsService
"""
import unittest
from unittest import mock
import pytest
from django.test import TestCase
import ddt
import mock
from config_models.models import ConfigurationModel
from django.conf import settings
@@ -20,7 +18,7 @@ from xmodule.services import ConfigurationService, SettingsService, TeamsConfigu
from openedx.core.lib.teams_config import TeamsConfig
class _DummyBlock(object):
class _DummyBlock:
""" Dummy Xblock class """
pass # lint-amnesty, pylint: disable=unnecessary-pass
@@ -33,7 +31,7 @@ class DummyConfig(ConfigurationModel):
app_label = 'xmoduletestservices'
class DummyUnexpected(object):
class DummyUnexpected:
"""
Dummy Unexpected Class
"""
@@ -49,7 +47,7 @@ class TestSettingsService(unittest.TestCase):
def setUp(self):
""" Setting up tests """
super(TestSettingsService, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.settings_service = SettingsService()
self.xblock_mock = mock.Mock()
self.xblock_mock.block_settings_key = self.xblock_setting_key1
@@ -128,7 +126,7 @@ class MockConfigurationService(TeamsConfigurationService):
Mock ConfigurationService for testing.
"""
def __init__(self, course, **kwargs): # lint-amnesty, pylint: disable=unused-argument
super(MockConfigurationService, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments
super().__init__()
self._course = course
def get_course(self, course_id):
@@ -141,7 +139,7 @@ class ConfigurationServiceBaseClass(TestCase):
"""
def setUp(self):
super(ConfigurationServiceBaseClass, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.teams_config = TeamsConfig(
{'max_size': 2, 'topics': [{'id': 'topic', 'name': 'Topic', 'description': 'A Topic'}]}

View File

@@ -2,12 +2,11 @@
Tests for the Split Testing Module
"""
import json
from unittest.mock import Mock, patch
import ddt
import lxml
import six
from fs.memoryfs import MemoryFS
from mock import Mock, patch
from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.utils import MixedSplitTestCase
@@ -97,8 +96,8 @@ class SplitTestBlockTest(XModuleXmlImportTest, PartitionTestCase):
UserPartition(
MINIMUM_STATIC_PARTITION_ID, 'second_partition', 'Second Partition',
[
Group(six.text_type(MINIMUM_STATIC_PARTITION_ID + 1), 'abel'),
Group(six.text_type(MINIMUM_STATIC_PARTITION_ID + 2), 'baker'), Group("103", 'charlie')
Group(str(MINIMUM_STATIC_PARTITION_ID + 1), 'abel'),
Group(str(MINIMUM_STATIC_PARTITION_ID + 2), 'baker'), Group("103", 'charlie')
],
MockUserPartitionScheme()
)
@@ -403,10 +402,10 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
assert len(validation.messages) == 0
verify_validation_message(
validation.summary,
u"The experiment is not associated with a group configuration.",
"The experiment is not associated with a group configuration.",
StudioValidationMessage.NOT_CONFIGURED,
'edit-button',
u"Select a Group Configuration",
"Select a Group Configuration",
)
# Verify the messages for a correctly configured split_test
@@ -427,14 +426,14 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
assert len(validation.messages) == 1
verify_validation_message(
validation.messages[0],
u"The experiment does not contain all of the groups in the configuration.",
"The experiment does not contain all of the groups in the configuration.",
StudioValidationMessage.ERROR,
expected_action_runtime_event='add-missing-groups',
expected_action_label=u"Add Missing Groups"
expected_action_label="Add Missing Groups"
)
verify_summary_message(
validation.summary,
u"This content experiment has issues that affect content visibility.",
"This content experiment has issues that affect content visibility.",
StudioValidationMessage.ERROR
)
# Verify the messages for a split test with children that are not associated with any group
@@ -446,12 +445,12 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
assert len(validation.messages) == 1
verify_validation_message(
validation.messages[0],
u"The experiment has an inactive group. Move content into active groups, then delete the inactive group.",
"The experiment has an inactive group. Move content into active groups, then delete the inactive group.",
StudioValidationMessage.WARNING
)
verify_summary_message(
validation.summary,
u"This content experiment has issues that affect content visibility.",
"This content experiment has issues that affect content visibility.",
StudioValidationMessage.WARNING
)
# Verify the messages for a split test with both missing and inactive children
@@ -463,20 +462,20 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
assert len(validation.messages) == 2
verify_validation_message(
validation.messages[0],
u"The experiment does not contain all of the groups in the configuration.",
"The experiment does not contain all of the groups in the configuration.",
StudioValidationMessage.ERROR,
expected_action_runtime_event='add-missing-groups',
expected_action_label=u"Add Missing Groups"
expected_action_label="Add Missing Groups"
)
verify_validation_message(
validation.messages[1],
u"The experiment has an inactive group. Move content into active groups, then delete the inactive group.",
"The experiment has an inactive group. Move content into active groups, then delete the inactive group.",
StudioValidationMessage.WARNING
)
# With two messages of type error and warning priority given to error.
verify_summary_message(
validation.summary,
u"This content experiment has issues that affect content visibility.",
"This content experiment has issues that affect content visibility.",
StudioValidationMessage.ERROR
)
@@ -486,13 +485,13 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
assert len(validation.messages) == 1
verify_validation_message(
validation.messages[0],
u"The experiment uses a deleted group configuration. "
u"Select a valid group configuration or delete this experiment.",
"The experiment uses a deleted group configuration. "
"Select a valid group configuration or delete this experiment.",
StudioValidationMessage.ERROR
)
verify_summary_message(
validation.summary,
u"This content experiment has issues that affect content visibility.",
"This content experiment has issues that affect content visibility.",
StudioValidationMessage.ERROR
)
@@ -508,13 +507,13 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
assert len(validation.messages) == 1
verify_validation_message(
validation.messages[0],
u"The experiment uses a group configuration that is not supported for experiments. "
u"Select a valid group configuration or delete this experiment.",
"The experiment uses a group configuration that is not supported for experiments. "
"Select a valid group configuration or delete this experiment.",
StudioValidationMessage.ERROR
)
verify_summary_message(
validation.summary,
u"This content experiment has issues that affect content visibility.",
"This content experiment has issues that affect content visibility.",
StudioValidationMessage.ERROR
)
@@ -539,7 +538,7 @@ class SplitTestBlockExportImportTest(MixedSplitTestCase):
user_partition_id=2,
)
self.child_blocks = [
self.make_block("html", self.split_test_block, display_name="Hello HTML {}".format(i))
self.make_block("html", self.split_test_block, display_name=f"Hello HTML {i}")
for i in range(1, 3)
]
self.split_test_block.group_id_to_child = {

View File

@@ -10,7 +10,7 @@ from xmodule.stringify import stringify_children
def test_stringify():
text = 'Hi <div x="foo">there <span>Bruce</span><b>!</b></div>'
html = '''<html a="b" foo="bar">{0}</html>'''.format(text)
html = f'''<html a="b" foo="bar">{text}</html>'''
xml = etree.fromstring(html)
out = stringify_children(xml)
assert out == text

View File

@@ -5,8 +5,8 @@ Tests for the Unit XBlock
import re
import unittest
from xml.dom import minidom
from unittest.mock import patch
from mock import patch
from web_fragments.fragment import Fragment
from xblock.core import XBlock
from xblock.completable import XBlockCompletionMode

View File

@@ -4,8 +4,7 @@ Tests for extended due date utilities.
import unittest
import mock
from unittest import mock
from ..util import duedate

View File

@@ -21,16 +21,16 @@ class StudioValidationMessageTest(unittest.TestCase):
Test that `TypeError`s are thrown for bad input parameters.
"""
with pytest.raises(TypeError):
StudioValidationMessage("unknown type", u"Unknown type info")
StudioValidationMessage("unknown type", "Unknown type info")
with pytest.raises(TypeError):
StudioValidationMessage(StudioValidationMessage.WARNING, u"bad warning", action_class=0)
StudioValidationMessage(StudioValidationMessage.WARNING, "bad warning", action_class=0)
with pytest.raises(TypeError):
StudioValidationMessage(StudioValidationMessage.WARNING, u"bad warning", action_runtime_event=0)
StudioValidationMessage(StudioValidationMessage.WARNING, "bad warning", action_runtime_event=0)
with pytest.raises(TypeError):
StudioValidationMessage(StudioValidationMessage.WARNING, u"bad warning", action_label=b"Non-unicode string")
StudioValidationMessage(StudioValidationMessage.WARNING, "bad warning", action_label=b"Non-unicode string")
def test_to_json(self):
"""
@@ -38,22 +38,22 @@ class StudioValidationMessageTest(unittest.TestCase):
"""
assert \
{'type': StudioValidationMessage.NOT_CONFIGURED,
'text': u'Not Configured message', 'action_label': u'Action label'} == \
'text': 'Not Configured message', 'action_label': 'Action label'} == \
StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED,
u'Not Configured message', action_label=u'Action label').to_json()
'Not Configured message', action_label='Action label').to_json()
assert \
{'type': StudioValidationMessage.WARNING,
'text': u'Warning message',
'text': 'Warning message',
'action_class': 'class-for-action'} ==\
StudioValidationMessage(StudioValidationMessage.WARNING, u'Warning message',
StudioValidationMessage(StudioValidationMessage.WARNING, 'Warning message',
action_class='class-for-action').to_json()
assert \
{'type': StudioValidationMessage.ERROR,
'text': u'Error message', 'action_runtime_event': 'do-fix-up'} ==\
'text': 'Error message', 'action_runtime_event': 'do-fix-up'} ==\
StudioValidationMessage(StudioValidationMessage.ERROR,
u'Error message', action_runtime_event='do-fix-up').to_json()
'Error message', action_runtime_event='do-fix-up').to_json()
class StudioValidationTest(unittest.TestCase):
@@ -63,7 +63,7 @@ class StudioValidationTest(unittest.TestCase):
def test_copy(self):
validation = Validation("id")
validation.add(ValidationMessage(ValidationMessage.ERROR, u"Error message"))
validation.add(ValidationMessage(ValidationMessage.ERROR, "Error message"))
studio_validation = StudioValidation.copy(validation)
assert isinstance(studio_validation, StudioValidation)
@@ -71,7 +71,7 @@ class StudioValidationTest(unittest.TestCase):
assert 1 == len(studio_validation.messages)
expected = {
"type": StudioValidationMessage.ERROR,
"text": u"Error message"
"text": "Error message"
}
assert expected == studio_validation.messages[0].to_json()
assert studio_validation.summary is None
@@ -79,7 +79,7 @@ class StudioValidationTest(unittest.TestCase):
def test_copy_studio_validation(self):
validation = StudioValidation("id")
validation.add(
StudioValidationMessage(StudioValidationMessage.WARNING, u"Warning message", action_label=u"Action Label")
StudioValidationMessage(StudioValidationMessage.WARNING, "Warning message", action_label="Action Label")
)
validation_copy = StudioValidation.copy(validation)
@@ -87,8 +87,8 @@ class StudioValidationTest(unittest.TestCase):
assert 1 == len(validation_copy.messages)
expected = {
"type": StudioValidationMessage.WARNING,
"text": u"Warning message",
"action_label": u"Action Label"
"text": "Warning message",
"action_label": "Action Label"
}
assert expected == validation_copy.messages[0].to_json()
@@ -105,13 +105,13 @@ class StudioValidationTest(unittest.TestCase):
assert validation.empty
assert validation
validation.add(StudioValidationMessage(StudioValidationMessage.ERROR, u"Error message"))
validation.add(StudioValidationMessage(StudioValidationMessage.ERROR, "Error message"))
assert not validation.empty
assert not validation
validation_with_summary = StudioValidation("id")
validation_with_summary.set_summary(
StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, u"Summary message")
StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, "Summary message")
)
assert not validation.empty
assert not validation
@@ -121,33 +121,33 @@ class StudioValidationTest(unittest.TestCase):
Test the behavior of calling `add_messages` with combination of `StudioValidation` instances.
"""
validation_1 = StudioValidation("id")
validation_1.set_summary(StudioValidationMessage(StudioValidationMessage.WARNING, u"Summary message"))
validation_1.add(StudioValidationMessage(StudioValidationMessage.ERROR, u"Error message"))
validation_1.set_summary(StudioValidationMessage(StudioValidationMessage.WARNING, "Summary message"))
validation_1.add(StudioValidationMessage(StudioValidationMessage.ERROR, "Error message"))
validation_2 = StudioValidation("id")
validation_2.set_summary(StudioValidationMessage(StudioValidationMessage.ERROR, u"Summary 2 message"))
validation_2.add(StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, u"Not configured"))
validation_2.set_summary(StudioValidationMessage(StudioValidationMessage.ERROR, "Summary 2 message"))
validation_2.add(StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, "Not configured"))
validation_1.add_messages(validation_2)
assert 2 == len(validation_1.messages)
assert StudioValidationMessage.ERROR == validation_1.messages[0].type
assert u'Error message' == validation_1.messages[0].text
assert 'Error message' == validation_1.messages[0].text
assert StudioValidationMessage.NOT_CONFIGURED == validation_1.messages[1].type
assert u'Not configured' == validation_1.messages[1].text
assert 'Not configured' == validation_1.messages[1].text
assert StudioValidationMessage.WARNING == validation_1.summary.type
assert u'Summary message' == validation_1.summary.text
assert 'Summary message' == validation_1.summary.text
def test_set_summary_accepts_validation_message(self):
"""
Test that `set_summary` accepts a ValidationMessage.
"""
validation = StudioValidation("id")
validation.set_summary(ValidationMessage(ValidationMessage.WARNING, u"Summary message"))
validation.set_summary(ValidationMessage(ValidationMessage.WARNING, "Summary message"))
assert ValidationMessage.WARNING == validation.summary.type
assert u'Summary message' == validation.summary.text
assert 'Summary message' == validation.summary.text
def test_set_summary_errors(self):
"""
@@ -171,24 +171,24 @@ class StudioValidationTest(unittest.TestCase):
validation.add(
StudioValidationMessage(
StudioValidationMessage.ERROR,
u"Error message",
action_label=u"Action label",
"Error message",
action_label="Action label",
action_class="edit-button"
)
)
validation.add(
StudioValidationMessage(
StudioValidationMessage.NOT_CONFIGURED,
u"Not configured message",
action_label=u"Action label",
"Not configured message",
action_label="Action label",
action_runtime_event="make groups"
)
)
validation.set_summary(
StudioValidationMessage(
StudioValidationMessage.WARNING,
u"Summary message",
action_label=u"Summary label",
"Summary message",
action_label="Summary label",
action_runtime_event="fix everything"
)
)
@@ -200,21 +200,21 @@ class StudioValidationTest(unittest.TestCase):
"messages": [
{
"type": "error",
"text": u"Error message",
"action_label": u"Action label",
"text": "Error message",
"action_label": "Action label",
"action_class": "edit-button"
},
{
"type": "not-configured",
"text": u"Not configured message",
"action_label": u"Action label",
"text": "Not configured message",
"action_label": "Action label",
"action_runtime_event": "make groups"
}
],
"summary": {
"type": "warning",
"text": u"Summary message",
"action_label": u"Summary label",
"text": "Summary message",
"action_label": "Summary label",
"action_runtime_event": "fix everything"
},
"empty": False

View File

@@ -8,12 +8,11 @@ Tests for vertical module.
from collections import namedtuple
from datetime import datetime, timedelta
import json
import pytz
import six
from unittest.mock import Mock, patch
import pytz
import ddt
from fs.memoryfs import MemoryFS
from mock import Mock, patch
from . import get_test_system
from .helpers import StubUserService
@@ -36,7 +35,7 @@ def get_json_request(data):
)
class StubCompletionService(object):
class StubCompletionService:
"""
A stub implementation of the CompletionService for testing without access to django
"""
@@ -86,7 +85,7 @@ class BaseVerticalBlockTest(XModuleXmlImportTest):
test_problem = 'Test Problem'
def setUp(self):
super(BaseVerticalBlockTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
# construct module
course = xml.CourseFactory.build()
sequence = xml.SequenceFactory.build(parent=course)
@@ -126,7 +125,7 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
Assert content has/hasn't all the bookmark info.
"""
assertion('bookmark_id', content)
assertion('{},{}'.format(self.username, six.text_type(self.vertical.location)), content)
assertion('{},{}'.format(self.username, str(self.vertical.location)), content)
assertion('bookmarked', content)
assertion('show_bookmark_button', content)
@@ -170,8 +169,8 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
if context:
assert "'has_assignments': True" in html
assert "'subsection_format': '{}'".format(context['format']) in html
assert "'completed': {}".format((completion_value == 1)) in html
assert "'past_due': {}".format((self.vertical.due < now)) in html
assert "'completed': {}".format(completion_value == 1) in html
assert "'past_due': {}".format(self.vertical.due < now) in html
@ddt.data(True, False)
def test_render_problem_without_score(self, has_score):

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# pylint: disable=protected-access
"""Test for Video Xmodule functional logic.
These test data read from xml, not from mongo.
@@ -21,19 +20,18 @@ import shutil
import unittest
from tempfile import mkdtemp
from uuid import uuid4
from unittest.mock import ANY, MagicMock, Mock, patch
import pytest
import ddt
import httpretty
import six
from django.conf import settings
from django.test import TestCase
from django.test.utils import override_settings
from fs.osfs import OSFS
from lxml import etree
from mock import ANY, MagicMock, Mock, patch
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import CourseLocator
from six.moves import zip
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
@@ -79,9 +77,9 @@ MOCKED_YOUTUBE_TRANSCRIPT_API_RESPONSE = '''
'''
ALL_LANGUAGES = (
[u"en", u"English"],
[u"eo", u"Esperanto"],
[u"ur", u"Urdu"]
["en", "English"],
["eo", "Esperanto"],
["ur", "Urdu"]
)
@@ -174,7 +172,7 @@ class VideoBlockTestBase(unittest.TestCase):
"""
def setUp(self):
super(VideoBlockTestBase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.descriptor = instantiate_descriptor()
def assertXmlEqual(self, expected, xml):
@@ -233,7 +231,7 @@ class TestCreateYouTubeUrl(VideoBlockTestBase):
Test that passing unicode to `create_youtube_url` doesn't throw
an error.
"""
self.descriptor.create_youtube_url(u"üñîçø∂é")
self.descriptor.create_youtube_url("üñîçø∂é")
@ddt.ddt
@@ -617,7 +615,7 @@ class VideoBlockImportTestCase(TestCase):
assert edx_video_id == 'test_edx_video_id'
assert static_dir == EXPORT_IMPORT_STATIC_DIR
assert resource_fs is not None
assert external_transcripts == {u'en': [u'subs_3_yD_cEKoCk.srt.sjson']}
assert external_transcripts == {'en': ['subs_3_yD_cEKoCk.srt.sjson']}
assert course_id == 'test_course_id'
return edx_video_id
@@ -646,7 +644,7 @@ class VideoBlockImportTestCase(TestCase):
edx_video_id,
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR,
{u'en': [u'subs_3_yD_cEKoCk.srt.sjson']},
{'en': ['subs_3_yD_cEKoCk.srt.sjson']},
course_id='test_course_id'
)
@@ -672,7 +670,7 @@ class VideoExportTestCase(VideoBlockTestBase):
"""
def setUp(self):
super(VideoExportTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.temp_dir = mkdtemp()
self.file_system = OSFS(self.temp_dir)
self.addCleanup(shutil.rmtree, self.temp_dir)
@@ -682,7 +680,7 @@ class VideoExportTestCase(VideoBlockTestBase):
"""
Test that we write the correct XML on export.
"""
edx_video_id = u'test_edx_video_id'
edx_video_id = 'test_edx_video_id'
mock_val_api.export_to_xml = Mock(
return_value=dict(
xml=etree.Element('video_asset'),
@@ -733,7 +731,7 @@ class VideoExportTestCase(VideoBlockTestBase):
video_id=edx_video_id,
static_dir=EXPORT_IMPORT_STATIC_DIR,
resource_fs=self.file_system,
course_id=six.text_type(self.descriptor.runtime.course_id.for_branch(None)),
course_id=str(self.descriptor.runtime.course_id.for_branch(None)),
)
@patch('xmodule.video_module.video_module.edxval_api')
@@ -814,9 +812,9 @@ class VideoExportTestCase(VideoBlockTestBase):
"""
Test XML export handles the unicode characters.
"""
self.descriptor.display_name = u'这是文'
self.descriptor.display_name = '这是文'
xml = self.descriptor.definition_to_xml(self.file_system)
assert xml.get('display_name') == u'这是文'
assert xml.get('display_name') == '这是文'
@ddt.ddt
@@ -875,15 +873,15 @@ class VideoBlockStudentViewDataTestCase(unittest.TestCase):
def test_student_view_data_with_hls_flag(self, mock_get_video_info, mock_get_video_transcript_content):
mock_get_video_info.return_value = {
'url': '/edxval/video/example',
'edx_video_id': u'example_id',
'edx_video_id': 'example_id',
'duration': 111.0,
'client_video_id': u'The example video',
'client_video_id': 'The example video',
'encoded_videos': [
{
'url': u'http://www.meowmix.com',
'url': 'http://www.meowmix.com',
'file_size': 25556,
'bitrate': 9600,
'profile': u'hls'
'profile': 'hls'
}
]
}
@@ -901,7 +899,7 @@ class VideoBlockStudentViewDataTestCase(unittest.TestCase):
descriptor.runtime.course_id = MagicMock()
descriptor.runtime.handler_url = MagicMock()
student_view_data = descriptor.student_view_data()
expected_video_data = {u'hls': {'url': u'http://www.meowmix.com', 'file_size': 25556}}
expected_video_data = {'hls': {'url': 'http://www.meowmix.com', 'file_size': 25556}}
self.assertDictEqual(student_view_data.get('encoded_videos'), expected_video_data)
@@ -985,7 +983,7 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
</video>
'''
yt_subs_id = 'OEoXaMPEzfM'
url = 'http://video.google.com/timedtext?lang=en&v={}'.format(yt_subs_id)
url = f'http://video.google.com/timedtext?lang=en&v={yt_subs_id}'
httpretty.register_uri(
method=httpretty.GET,
uri=url,
@@ -1020,7 +1018,7 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
</video>
'''
yt_subs_id = 'OEoXaMPEzfM'
url = 'http://video.google.com/timedtext?lang=en&v={}'.format(yt_subs_id)
url = f'http://video.google.com/timedtext?lang=en&v={yt_subs_id}'
httpretty.register_uri(
method=httpretty.GET,
uri=url,

View File

@@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
"""Test for Word cloud Xmodule functional logic."""
import json
from unittest.mock import Mock
from django.test import TestCase
from fs.memoryfs import MemoryFS
from lxml import etree
from mock import Mock
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from webob.multidict import MultiDict
from xblock.field_data import DictFieldData
@@ -57,7 +56,7 @@ class WordCloudBlockTest(TestCase):
node = etree.Element("unknown_root")
# This will export the olx to a separate file.
block.add_xml_to_node(node)
with runtime.export_fs.open(u'word_cloud/block_id.xml') as f:
with runtime.export_fs.open('word_cloud/block_id.xml') as f:
exported_xml = f.read()
assert exported_xml == original_xml
@@ -103,7 +102,7 @@ class WordCloudBlockTest(TestCase):
{'text': 'sun', 'size': 1, 'percent': 4.0}]
)
assert 100.0 == sum((i['percent'] for i in response['top_words']))
assert 100.0 == sum(i['percent'] for i in response['top_words'])
def test_indexibility(self):
"""

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Tests for the wrapping layer that provides the XBlock API using XModule/Descriptor
functionality
@@ -8,6 +7,7 @@ functionality
from unittest.case import SkipTest, TestCase
from unittest.mock import Mock
import ddt
import webob
@@ -23,9 +23,7 @@ from factory import (
)
from fs.memoryfs import MemoryFS
from lxml import etree
from mock import Mock
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from six.moves import range
from xblock.core import XBlock
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
@@ -69,7 +67,7 @@ CONTAINER_XMODULES = {
ConditionalBlock: [{}],
CourseBlock: [{}],
RandomizeBlock: [{'display_name': 'Test String Display'}],
SequenceBlock: [{'display_name': u'Test Unicode हिंदी Display'}],
SequenceBlock: [{'display_name': 'Test Unicode हिंदी Display'}],
VerticalBlock: [{}],
WrapperBlock: [{}],
}
@@ -98,7 +96,7 @@ class ModuleSystemFactory(Factory):
performed by :func:`xmodule.tests.get_test_system`, so
arguments for that function are valid factory attributes.
"""
class Meta(object):
class Meta:
model = ModuleSystem
@classmethod
@@ -114,7 +112,7 @@ class DescriptorSystemFactory(Factory):
performed by :func:`xmodule.tests.get_test_descriptor_system`, so
arguments for that function are valid factory attributes.
"""
class Meta(object):
class Meta:
model = DescriptorSystem
@classmethod
@@ -185,7 +183,7 @@ class LeafDescriptorFactory(Factory):
Factory to generate leaf XModuleDescriptors.
"""
class Meta(object):
class Meta:
model = XModuleDescriptor
runtime = SubFactory(DescriptorSystemFactory)
@@ -260,7 +258,7 @@ class ContainerModuleFactory(LeafModuleFactory):
@ddt.ddt
class XBlockWrapperTestMixin(object):
class XBlockWrapperTestMixin:
"""
This is a mixin for building tests of the implementation of the XBlock
api by wrapping XModule native functions.
@@ -374,7 +372,7 @@ class TestXModuleHandler(TestCase):
"""
def setUp(self):
super(TestXModuleHandler, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.module = XModule(descriptor=Mock(), field_data=Mock(), runtime=Mock(), scope_ids=Mock())
self.module.handle_ajax = Mock(return_value='{}')
self.request = webob.Request({})
@@ -393,7 +391,7 @@ class TestXModuleHandler(TestCase):
assert response.body.decode('utf-8') == '{}'
@ddt.data(
u'{"test_key": "test_value"}',
'{"test_key": "test_value"}',
'{"test_key": "test_value"}',
)
def test_xmodule_handler_with_data(self, response_data):

View File

@@ -3,10 +3,9 @@
import unittest
from unittest.mock import Mock
from mock import Mock
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from six.moves import range
from xblock.field_data import DictFieldData
from xblock.fields import Any, Boolean, Dict, Float, Integer, List, Scope, String
from xblock.runtime import DictKeyValueStore, KvsFieldData
@@ -28,7 +27,7 @@ class CrazyJsonString(String):
return value + " JSON"
class TestFields(object):
class TestFields:
# Will be returned by editable_metadata_fields.
max_attempts = Integer(scope=Scope.settings, default=1000, values={'min': 1, 'max': 10})
# Will not be returned by editable_metadata_fields because filtered out by non_editable_metadata_fields.
@@ -73,7 +72,7 @@ class InheritingFieldDataTest(unittest.TestCase):
not_inherited = String(scope=Scope.settings, default="nothing")
def setUp(self):
super(InheritingFieldDataTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.dummy_course_key = CourseLocator('test_org', 'test_123', 'test_run')
self.system = get_test_descriptor_system()
self.all_blocks = {}
@@ -164,7 +163,7 @@ class InheritingFieldDataTest(unittest.TestCase):
parent.inherited = "Changed!"
assert parent.inherited == 'Changed!'
for child_num in range(10):
usage_id = self.get_usage_id("vertical", "child_{}".format(child_num))
usage_id = self.get_usage_id("vertical", f"child_{child_num}")
child = self.get_a_block(usage_id=usage_id)
child.parent = parent.location
assert child.inherited == 'Changed!'
@@ -343,7 +342,7 @@ class EditableMetadataFieldsTest(unittest.TestCase):
class TestModuleDescriptor(TestFields, XmlDescriptor): # lint-amnesty, pylint: disable=abstract-method
@property
def non_editable_metadata_fields(self):
non_editable_fields = super(TestModuleDescriptor, self).non_editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments
non_editable_fields = super().non_editable_metadata_fields
non_editable_fields.append(TestModuleDescriptor.due)
return non_editable_fields

View File

@@ -4,12 +4,11 @@ Xml parsing tests for XModules
import pprint
from unittest.mock import Mock
from django.test import TestCase
from lxml import etree
from mock import Mock
from opaque_keys.edx.keys import CourseKey
from six import text_type
from xblock.runtime import DictKeyValueStore, KvsFieldData
from xmodule.mako_module import MakoDescriptorSystem
@@ -30,7 +29,7 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable
"""Return the policy data for the specified usage"""
return xml_import_data.policy.get(policy_key(usage_id), {})
super(InMemorySystem, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(
get_policy=get_policy,
process_xml=self.process_xml,
load_item=self.load_item,
@@ -50,12 +49,12 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable
None,
CourseLocationManager(self.course_id),
)
self._descriptors[text_type(descriptor.location)] = descriptor
self._descriptors[str(descriptor.location)] = descriptor
return descriptor
def load_item(self, location, for_parent=None): # pylint: disable=method-hidden, unused-argument
"""Return the descriptor loaded for `location`"""
return self._descriptors[text_type(location)]
return self._descriptors[str(location)]
class XModuleXmlImportTest(TestCase):

View File

@@ -16,7 +16,7 @@ from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.x_module import XModuleMixin
class XmlImportData(object):
class XmlImportData:
"""
Class to capture all of the data needed to actually run an XML import,
so that the Factories have something to generate
@@ -49,7 +49,7 @@ class XmlImportData(object):
return etree.tostring(self._xml_node)
def __repr__(self):
return u"XmlImportData{!r}".format((
return "XmlImportData{!r}".format((
self._xml_node, self._xml_string, self.course_id,
self.default_class, self.policy,
self.filesystem, self.parent, self.xblock_mixins,
@@ -67,7 +67,7 @@ class XmlImportFactory(Factory):
Factory for generating XmlImportData's, which can hold all the data needed
to run an XModule XML import
"""
class Meta(object):
class Meta:
model = XmlImportData
filesystem = OSFS(mkdtemp())

View File

@@ -2,13 +2,12 @@
import logging
import six
from xmodule.fields import Timedelta
log = logging.getLogger(__name__)
class TimeInfo(object):
class TimeInfo:
"""
This is a simple object that calculates and stores datetime information for an XModule
based on the due date and the grace period string
@@ -29,11 +28,11 @@ class TimeInfo(object):
self.display_due_date = None
if grace_period_string_or_timedelta is not None and self.display_due_date:
if isinstance(grace_period_string_or_timedelta, six.string_types):
if isinstance(grace_period_string_or_timedelta, str):
try:
self.grace_period = TimeInfo._delta_standin.from_json(grace_period_string_or_timedelta)
except:
log.error("Error parsing the grace period {0}".format(grace_period_string_or_timedelta))
log.error(f"Error parsing the grace period {grace_period_string_or_timedelta}")
raise
else:
self.grace_period = grace_period_string_or_timedelta

View File

@@ -61,7 +61,7 @@ class UnitBlock(XBlock):
"""
# return key/value fields in a Python dict object
# values may be numeric / string or dict
xblock_body = super(UnitBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments
xblock_body = super().index_dictionary()
index_body = {
"display_name": self.display_name,
}

View File

@@ -68,7 +68,7 @@ def get_short_labeler(prefix):
`prefix` to an assignment index.
"""
def labeler(index):
return u"{prefix} {index:02d}".format(prefix=prefix, index=index)
return f"{prefix} {index:02d}"
return labeler

View File

@@ -2,7 +2,6 @@
import re
import six
from django.conf import settings
DEFAULT_PYTHON_LIB_FILENAME = 'python_lib.zip'
@@ -28,7 +27,7 @@ def can_execute_unsafe_code(course_id):
# To others using this: the code as-is is brittle and likely to be changed in the future,
# as per the TODO, so please consider carefully before adding more values to COURSES_WITH_UNSAFE_CODE
for regex in getattr(settings, 'COURSES_WITH_UNSAFE_CODE', []):
if re.match(regex, six.text_type(course_id)):
if re.match(regex, str(course_id)):
return True
return False

View File

@@ -1,9 +1,6 @@
"""
Extension of XBlock Validation class to include information for presentation in Studio.
"""
import six
from xblock.validation import Validation, ValidationMessage
@@ -33,17 +30,17 @@ class StudioValidationMessage(ValidationMessage):
action_runtime_event (str): An event name to be triggered on the xblock client-side runtime when
the "fix-up" action is clicked (optional).
"""
super(StudioValidationMessage, self).__init__(message_type, message_text) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(message_type, message_text)
if action_label is not None:
if not isinstance(action_label, six.text_type):
if not isinstance(action_label, str):
raise TypeError("Action label must be unicode.")
self.action_label = action_label
if action_class is not None:
if not isinstance(action_class, six.string_types):
if not isinstance(action_class, str):
raise TypeError("Action class must be a string.")
self.action_class = action_class
if action_runtime_event is not None:
if not isinstance(action_runtime_event, six.string_types):
if not isinstance(action_runtime_event, str):
raise TypeError("Action runtime event must be a string.")
self.action_runtime_event = action_runtime_event
@@ -54,7 +51,7 @@ class StudioValidationMessage(ValidationMessage):
Returns:
dict: A dict representation that is json-serializable.
"""
serialized = super(StudioValidationMessage, self).to_json() # lint-amnesty, pylint: disable=super-with-arguments
serialized = super().to_json()
if hasattr(self, "action_label"):
serialized["action_label"] = self.action_label
if hasattr(self, "action_class"):
@@ -94,7 +91,7 @@ class StudioValidation(Validation):
Args:
xblock_id (object): An identification object that must support conversion to unicode.
"""
super(StudioValidation, self).__init__(xblock_id) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(xblock_id)
self.summary = None
def set_summary(self, message):
@@ -116,7 +113,7 @@ class StudioValidation(Validation):
Returns:
bool: True iff this instance has no validation issues and therefore has no messages or summary.
"""
return super(StudioValidation, self).empty and not self.summary # lint-amnesty, pylint: disable=super-with-arguments
return super().empty and not self.summary
def to_json(self):
"""
@@ -125,7 +122,7 @@ class StudioValidation(Validation):
Returns:
dict: A dict representation that is json-serializable.
"""
serialized = super(StudioValidation, self).to_json() # lint-amnesty, pylint: disable=super-with-arguments
serialized = super().to_json()
if self.summary:
serialized["summary"] = self.summary.to_json()
return serialized

View File

@@ -9,7 +9,6 @@ from datetime import datetime
from functools import reduce
import pytz
import six
from lxml import etree
from web_fragments.fragment import Fragment
@@ -94,7 +93,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
fragment.add_fragment_resources(rendered_child)
contents.append({
'id': six.text_type(child.location),
'id': str(child.location),
'content': rendered_child.content
})
@@ -120,8 +119,8 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
'show_bookmark_button': child_context.get('show_bookmark_button', not is_child_of_vertical),
'show_title': child_context.get('show_title', True),
'bookmarked': child_context['bookmarked'],
'bookmark_id': u"{},{}".format(
child_context['username'], six.text_type(self.location)), # pylint: disable=no-member
'bookmark_id': "{},{}".format(
child_context['username'], str(self.location)), # pylint: disable=no-member
})
fragment.add_content(self.system.render_template('vert_module.html', fragment_context))
@@ -172,7 +171,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
"""
Returns the highest priority icon class.
"""
child_classes = set(child.get_icon_class() for child in self.get_children())
child_classes = {child.get_icon_class() for child in self.get_children()}
new_class = 'other'
for higher_class in CLASS_PRIORITY:
if higher_class in child_classes:
@@ -189,7 +188,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
except Exception as exc: # pylint: disable=broad-except
log.exception("Unable to load child when parsing Vertical. Continuing...")
if system.error_tracker is not None:
system.error_tracker(u"ERROR: {0}".format(exc))
system.error_tracker(f"ERROR: {exc}")
continue
return {}, children
@@ -204,14 +203,14 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
"""
Gather all fields which can't be edited.
"""
non_editable_fields = super(VerticalBlock, self).non_editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments
non_editable_fields = super().non_editable_metadata_fields
non_editable_fields.extend([
self.fields['due'], # lint-amnesty, pylint: disable=unsubscriptable-object
])
return non_editable_fields
def studio_view(self, context):
fragment = super(VerticalBlock, self).studio_view(context) # lint-amnesty, pylint: disable=super-with-arguments
fragment = super().studio_view(context)
# This continues to use the old XModuleDescriptor javascript code to enabled studio editing.
# TODO: Remove this when studio better supports editing of pure XBlocks.
fragment.add_javascript('VerticalBlock = XModule.Descriptor;')
@@ -224,7 +223,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse
# return key/value fields in a Python dict object
# values may be numeric / string or dict
# default implementation is an empty dict
xblock_body = super(VerticalBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments
xblock_body = super().index_dictionary()
index_body = {
"display_name": self.display_name,
}

View File

@@ -12,14 +12,11 @@ from functools import wraps
import requests
import simplejson as json
import six
from django.conf import settings
from lxml import etree
from opaque_keys.edx.locator import BundleDefinitionLocator
from pysrt import SubRipFile, SubRipItem, SubRipTime
from pysrt.srtexc import Error
from six import text_type
from six.moves import range, zip
from openedx.core.djangolib import blockstore_cache
from openedx.core.lib import blockstore_api
@@ -71,7 +68,7 @@ def exception_decorator(func):
try:
return func(*args, **kwds)
except (TranscriptsGenerationException, UnicodeDecodeError) as ex:
log.exception(text_type(ex))
log.exception(str(ex))
raise NotFoundError # lint-amnesty, pylint: disable=raise-missing-from
return wrapper
@@ -254,7 +251,7 @@ def generate_subs_from_source(speed_subs, subs_type, subs_filedata, item, langua
srt_subs_obj = SubRipFile.from_string(subs_filedata)
except Exception as ex:
msg = _("Something wrong with SubRip transcripts file during parsing. Inner message is {error_message}").format(
error_message=text_type(ex)
error_message=str(ex)
)
raise TranscriptsGenerationException(msg) # lint-amnesty, pylint: disable=raise-missing-from
if not srt_subs_obj:
@@ -274,7 +271,7 @@ def generate_subs_from_source(speed_subs, subs_type, subs_filedata, item, langua
'end': sub_ends,
'text': sub_texts}
for speed, subs_id in six.iteritems(speed_subs):
for speed, subs_id in speed_subs.items():
save_subs_to_store(
generate_subs(speed, 1, subs),
subs_id,
@@ -308,7 +305,7 @@ def generate_srt_from_sjson(sjson_subs, speed):
end=SubRipTime(milliseconds=sjson_speed_1['end'][i]),
text=sjson_speed_1['text'][i]
)
output += (six.text_type(item))
output += (str(item))
output += '\n'
return output
@@ -346,7 +343,7 @@ def copy_or_rename_transcript(new_name, old_name, item, delete_old=False, user=N
If `old_name` is not found in storage, raises `NotFoundError`.
If `delete_old` is True, removes `old_name` files from storage.
"""
filename = u'subs_{0}.srt.sjson'.format(old_name)
filename = f'subs_{old_name}.srt.sjson'
content_location = StaticContent.compute_location(item.location.course_key, filename)
transcripts = contentstore().find(content_location).data.decode('utf-8')
save_subs_to_store(json.loads(transcripts), new_name, item)
@@ -447,7 +444,7 @@ def manage_video_subtitles_save(item, user, old_metadata=None, generate_translat
generate_sjson_for_all_speeds(
item,
item.transcripts[lang],
{speed: subs_id for subs_id, speed in six.iteritems(youtube_speed_dict(item))},
{speed: subs_id for subs_id, speed in youtube_speed_dict(item).items()},
lang,
)
except TranscriptException as ex: # lint-amnesty, pylint: disable=unused-variable
@@ -472,9 +469,9 @@ def subs_filename(subs_id, lang='en'):
Generate proper filename for storage.
"""
if lang == 'en':
return u'subs_{0}.srt.sjson'.format(subs_id)
return f'subs_{subs_id}.srt.sjson'
else:
return u'{0}_subs_{1}.srt.sjson'.format(lang, subs_id)
return f'{lang}_subs_{subs_id}.srt.sjson'
def generate_sjson_for_all_speeds(item, user_filename, result_subs_dict, lang):
@@ -489,7 +486,7 @@ def generate_sjson_for_all_speeds(item, user_filename, result_subs_dict, lang):
srt_transcripts = contentstore().find(Transcript.asset_location(item.location, user_filename))
except NotFoundError as ex:
raise TranscriptException(_("{exception_message}: Can't find uploaded transcripts: {user_filename}").format( # lint-amnesty, pylint: disable=raise-missing-from
exception_message=text_type(ex),
exception_message=str(ex),
user_filename=user_filename
))
@@ -545,7 +542,7 @@ def get_video_ids_info(edx_video_id, youtube_id_1_0, html5_sources):
Returns:
tuple: external or internal, video ids list
"""
clean = lambda item: item.strip() if isinstance(item, six.string_types) else item
clean = lambda item: item.strip() if isinstance(item, str) else item
external = not bool(clean(edx_video_id))
video_ids = [edx_video_id, youtube_id_1_0] + get_html5_ids(html5_sources)
@@ -617,23 +614,23 @@ def convert_video_transcript(file_name, content, output_format):
"""
name_and_extension = os.path.splitext(file_name)
basename, input_format = name_and_extension[0], name_and_extension[1][1:]
filename = u'{base_name}.{ext}'.format(base_name=basename, ext=output_format)
filename = f'{basename}.{output_format}'
converted_transcript = Transcript.convert(content, input_format=input_format, output_format=output_format)
return dict(filename=filename, content=converted_transcript)
class Transcript(object):
class Transcript:
"""
Container for transcript methods.
"""
SRT = u'srt'
TXT = u'txt'
SJSON = u'sjson'
SRT = 'srt'
TXT = 'txt'
SJSON = 'sjson'
mime_types = {
SRT: u'application/x-subrip; charset=utf-8',
TXT: u'text/plain; charset=utf-8',
SJSON: u'application/json',
SRT: 'application/x-subrip; charset=utf-8',
TXT: 'text/plain; charset=utf-8',
SJSON: 'application/json',
}
@staticmethod
@@ -655,7 +652,7 @@ class Transcript(object):
if input_format == 'srt':
# Standardize content into bytes for later decoding.
if isinstance(content, text_type):
if isinstance(content, str):
content = content.encode('utf-8')
if output_format == 'txt':
@@ -670,7 +667,7 @@ class Transcript(object):
error_handling=SubRipFile.ERROR_RAISE
)
except Error as ex: # Base exception from pysrt
raise TranscriptsGenerationException(text_type(ex)) # lint-amnesty, pylint: disable=raise-missing-from
raise TranscriptsGenerationException(str(ex)) # lint-amnesty, pylint: disable=raise-missing-from
return json.dumps(generate_sjson_from_srt(srt_subs))
@@ -731,7 +728,7 @@ class Transcript(object):
return StaticContent.compute_location(location.course_key, filename)
class VideoTranscriptsMixin(object):
class VideoTranscriptsMixin:
"""Mixin class for transcript functionality.
This is necessary for VideoBlock.
@@ -764,7 +761,7 @@ class VideoTranscriptsMixin(object):
if sub:
all_langs.update({'en': sub})
for language, filename in six.iteritems(all_langs):
for language, filename in all_langs.items():
try:
# for bumper videos, transcripts are stored in content store only
if is_bumper:
@@ -795,11 +792,11 @@ class VideoTranscriptsMixin(object):
if self.transcript_language in other_lang:
transcript_language = self.transcript_language
elif sub:
transcript_language = u'en'
transcript_language = 'en'
elif len(other_lang) > 0:
transcript_language = sorted(other_lang)[0]
else:
transcript_language = u'en'
transcript_language = 'en'
return transcript_language
def get_transcripts_info(self, is_bumper=False):
@@ -854,7 +851,7 @@ def get_transcript_from_val(edx_video_id, lang=None, output_format=Transcript.SR
"""
transcript = get_video_transcript_content(edx_video_id, lang)
if not transcript:
raise NotFoundError(u'Transcript not found for {}, lang: {}'.format(edx_video_id, lang))
raise NotFoundError(f'Transcript not found for {edx_video_id}, lang: {lang}')
transcript_conversion_props = dict(transcript, output_format=output_format)
transcript = convert_video_transcript(**transcript_conversion_props)
@@ -916,7 +913,7 @@ def get_transcript_from_contentstore(video, language, output_format, transcripts
"""
input_format, base_name, transcript_content = None, None, None
if output_format not in (Transcript.SRT, Transcript.SJSON, Transcript.TXT):
raise NotFoundError('Invalid transcript format `{output_format}`'.format(output_format=output_format))
raise NotFoundError(f'Invalid transcript format `{output_format}`')
sub, other_languages = transcripts_info['sub'], transcripts_info['transcripts']
transcripts = dict(other_languages)
@@ -925,7 +922,7 @@ def get_transcript_from_contentstore(video, language, output_format, transcripts
possible_sub_ids = [youtube_id, sub, video.youtube_id_1_0] + get_html5_ids(video.html5_sources)
for sub_id in possible_sub_ids:
try:
transcripts[u'en'] = sub_id
transcripts['en'] = sub_id
input_format, base_name, transcript_content = get_transcript_for_video(
video.location,
subs_id=sub_id,
@@ -942,8 +939,8 @@ def get_transcript_from_contentstore(video, language, output_format, transcripts
))
# add language prefix to transcript file only if language is not None
language_prefix = '{}_'.format(language) if language else ''
transcript_name = u'{}{}.{}'.format(language_prefix, base_name, output_format)
language_prefix = f'{language}_' if language else ''
transcript_name = f'{language_prefix}{base_name}.{output_format}'
transcript_content = Transcript.convert(transcript_content, input_format=input_format, output_format=output_format)
if not transcript_content.strip():
raise NotFoundError('No transcript content')
@@ -991,7 +988,7 @@ def get_transcript_from_blockstore(video_block, language, output_format, transcr
tuple containing content, filename, mimetype
"""
if output_format not in (Transcript.SRT, Transcript.SJSON, Transcript.TXT):
raise NotFoundError('Invalid transcript format `{output_format}`'.format(output_format=output_format))
raise NotFoundError(f'Invalid transcript format `{output_format}`')
transcripts = transcripts_info['transcripts']
if language not in transcripts:
raise NotFoundError("Video {} does not have a transcript file defined for the '{}' language in its OLX.".format(
@@ -1017,7 +1014,7 @@ def get_transcript_from_blockstore(video_block, language, output_format, transcr
))
# Now convert the transcript data to the requested format:
filename_no_extension = os.path.splitext(filename)[0]
output_filename = '{}.{}'.format(filename_no_extension, output_format)
output_filename = f'{filename_no_extension}.{output_format}'
output_transcript = Transcript.convert(
content_binary.decode('utf-8'),
input_format=Transcript.SRT,

View File

@@ -10,7 +10,6 @@ import json
import logging
import math
import six
from django.core.files.base import ContentFile
from django.utils.timezone import now
from edxval.api import create_external_video, create_or_update_video_transcript, delete_video_transcript
@@ -47,15 +46,15 @@ def to_boolean(value):
"""
Convert a value from a GET or POST request parameter to a bool
"""
if isinstance(value, six.binary_type):
if isinstance(value, bytes):
value = value.decode('ascii', errors='replace')
if isinstance(value, six.text_type):
if isinstance(value, str):
return value.lower() == 'true'
else:
return bool(value)
class VideoStudentViewHandlers(object):
class VideoStudentViewHandlers:
"""
Handlers for video module instance.
"""
@@ -91,7 +90,7 @@ class VideoStudentViewHandlers(object):
value = now()
if key == 'speed' and math.isnan(value):
message = u"Invalid speed value {}, must be a float.".format(value)
message = f"Invalid speed value {value}, must be a float."
log.warning(message)
return json.dumps({'success': False, 'error': message})
@@ -102,8 +101,8 @@ class VideoStudentViewHandlers(object):
return json.dumps({'success': True})
log.debug(u"GET {0}".format(data))
log.debug(u"DISPATCH {0}".format(dispatch))
log.debug(f"GET {data}")
log.debug(f"DISPATCH {dispatch}")
raise NotFoundError('Unexpected dispatch type')
@@ -159,7 +158,7 @@ class VideoStudentViewHandlers(object):
generate_sjson_for_all_speeds(
self,
other_lang[self.transcript_language],
{speed: youtube_id for youtube_id, speed in six.iteritems(youtube_ids)},
{speed: youtube_id for youtube_id, speed in youtube_ids.items()},
self.transcript_language
)
sjson_transcript = Transcript.asset(self.location, youtube_id, self.transcript_language).data
@@ -218,7 +217,7 @@ class VideoStudentViewHandlers(object):
if asset_path:
response = Response(
status=307,
location='/static/{0}/{1}'.format(
location='/static/{}/{}'.format(
asset_path,
subs_filename(transcript_name, self.transcript_language)
)
@@ -240,14 +239,14 @@ class VideoStudentViewHandlers(object):
"""
completion_service = self.runtime.service(self, 'completion')
if completion_service is None: # lint-amnesty, pylint: disable=no-else-raise
raise JsonHandlerError(500, u"No completion service found")
raise JsonHandlerError(500, "No completion service found")
elif not completion_service.completion_tracking_enabled():
raise JsonHandlerError(404, u"Completion tracking is not enabled and API calls are unexpected")
raise JsonHandlerError(404, "Completion tracking is not enabled and API calls are unexpected")
if not isinstance(data['completion'], (int, float)): # lint-amnesty, pylint: disable=no-else-raise
message = u"Invalid completion value {}. Must be a float in range [0.0, 1.0]"
message = "Invalid completion value {}. Must be a float in range [0.0, 1.0]"
raise JsonHandlerError(400, message.format(data['completion']))
elif not 0.0 <= data['completion'] <= 1.0:
message = u"Invalid completion value {}. Must be in range [0.0, 1.0]"
message = "Invalid completion value {}. Must be in range [0.0, 1.0]"
raise JsonHandlerError(400, message.format(data['completion']))
self.runtime.publish(self, "completion", data)
return {"result": "ok"}
@@ -272,7 +271,7 @@ class VideoStudentViewHandlers(object):
headerlist.append(
(
'Content-Disposition',
'attachment; filename="{}"'.format(filename.encode('utf-8') if six.PY2 else filename)
f'attachment; filename="{filename}"'
)
)
@@ -419,7 +418,7 @@ class VideoStudentViewHandlers(object):
return response
class VideoStudioViewHandlers(object):
class VideoStudioViewHandlers:
"""
Handlers for Studio view.
"""
@@ -443,15 +442,15 @@ class VideoStudioViewHandlers(object):
available_translations = self.available_translations(transcripts, verify_assets=True)
if missing:
error = _(u'The following parameters are required: {missing}.').format(missing=', '.join(missing))
error = _('The following parameters are required: {missing}.').format(missing=', '.join(missing))
elif (
data['language_code'] != data['new_language_code'] and data['new_language_code'] in available_translations
):
error = _(u'A transcript with the "{language_code}" language code already exists.'.format( # lint-amnesty, pylint: disable=translation-of-non-string
error = _('A transcript with the "{language_code}" language code already exists.'.format( # lint-amnesty, pylint: disable=translation-of-non-string
language_code=data['new_language_code']
))
elif 'file' not in data:
error = _(u'A transcript file is required.')
error = _('A transcript file is required.')
return error
@@ -500,7 +499,7 @@ class VideoStudioViewHandlers(object):
if not edx_video_id:
# Back-populate the video ID for an external video.
# pylint: disable=attribute-defined-outside-init
self.edx_video_id = edx_video_id = create_external_video(display_name=u'external video')
self.edx_video_id = edx_video_id = create_external_video(display_name='external video')
try:
# Convert SRT transcript into an SJSON format
@@ -528,7 +527,7 @@ class VideoStudioViewHandlers(object):
response = Response(
json={
'error': _(
u'There is a problem with this transcript file. Try to upload a different file.'
'There is a problem with this transcript file. Try to upload a different file.'
)
},
status=400
@@ -545,7 +544,7 @@ class VideoStudioViewHandlers(object):
if edx_video_id:
delete_video_transcript(video_id=edx_video_id, language_code=language)
if language == u'en':
if language == 'en':
# remove any transcript file from content store for the video ids
possible_sub_ids = [
self.sub, # pylint: disable=access-member-before-definition
@@ -567,7 +566,7 @@ class VideoStudioViewHandlers(object):
elif request.method == 'GET':
language = request.GET.get('language_code')
if not language:
return Response(json={'error': _(u'Language is required.')}, status=400)
return Response(json={'error': _('Language is required.')}, status=400)
try:
transcript_content, transcript_name, mime_type = get_transcript(
@@ -576,9 +575,7 @@ class VideoStudioViewHandlers(object):
response = Response(transcript_content, headerlist=[
(
'Content-Disposition',
'attachment; filename="{}"'.format(
transcript_name.encode('utf8') if six.PY2 else transcript_name
)
f'attachment; filename="{transcript_name}"'
),
('Content-Language', language),
('Content-Type', mime_type)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Video is ungraded Xmodule for support video content.
It's new improved video module, which support additional feature:
- Can play non-YouTube video sources via in-browser HTML5 video player.
@@ -20,7 +19,6 @@ import logging
from collections import OrderedDict, defaultdict
from operator import itemgetter
import six
from django.conf import settings
from edx_django_utils.cache import RequestCache
from lxml import etree
@@ -105,8 +103,8 @@ log = logging.getLogger(__name__)
# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file
_ = lambda text: text
EXPORT_IMPORT_COURSE_DIR = u'course'
EXPORT_IMPORT_STATIC_DIR = u'static'
EXPORT_IMPORT_COURSE_DIR = 'course'
EXPORT_IMPORT_STATIC_DIR = 'static'
@XBlock.wants('settings', 'completion', 'i18n', 'request_cache')
@@ -338,7 +336,7 @@ class VideoBlock(
if getattr(self, 'video_speed_optimizations', True) and cdn_url:
branding_info = BrandingInfoConfig.get_config().get(self.system.user_location)
if self.edx_video_id and edxval_api and video_status != u'external':
if self.edx_video_id and edxval_api and video_status != 'external':
for index, source_url in enumerate(sources):
new_url = rewrite_video_url(cdn_url, source_url)
if new_url:
@@ -478,7 +476,7 @@ class VideoBlock(
is the override of the general XBlock method, and it will also ask
its superclass to validate.
"""
validation = super(VideoBlock, self).validate() # lint-amnesty, pylint: disable=super-with-arguments
validation = super().validate()
if not isinstance(validation, StudioValidation):
validation = StudioValidation.copy(validation)
@@ -564,7 +562,7 @@ class VideoBlock(
@property
def editable_metadata_fields(self):
editable_fields = super(VideoBlock, self).editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments
editable_fields = super().editable_metadata_fields
settings_service = self.runtime.service(self, 'settings')
if settings_service:
@@ -593,7 +591,7 @@ class VideoBlock(
possible_sub_ids = [self.sub, self.youtube_id_1_0] + get_html5_ids(self.html5_sources)
for sub_id in possible_sub_ids:
try:
_, sub_id, _ = get_transcript(self, lang=u'en', output_format=Transcript.TXT)
_, sub_id, _ = get_transcript(self, lang='en', output_format=Transcript.TXT)
transcripts_info['transcripts'] = dict(transcripts_info['transcripts'], en=sub_id)
break
except NotFoundError:
@@ -675,7 +673,7 @@ class VideoBlock(
# Mild workaround to ensure that tests pass -- if a field
# is set to its default value, we don't need to write it out.
if youtube_string and youtube_string != '1.00:3_yD_cEKoCk':
xml.set('youtube', six.text_type(youtube_string))
xml.set('youtube', str(youtube_string))
xml.set('url_name', self.url_name)
attrs = [
('display_name', self.display_name),
@@ -692,13 +690,13 @@ class VideoBlock(
if value:
if key in self.fields and self.fields[key].is_set_on(self): # lint-amnesty, pylint: disable=unsubscriptable-object, unsupported-membership-test
try:
xml.set(key, six.text_type(value))
xml.set(key, str(value))
except UnicodeDecodeError:
exception_message = format_xml_exception_message(self.location, key, value)
log.exception(exception_message)
# If exception is UnicodeDecodeError set value using unicode 'utf-8' scheme.
log.info("Setting xml value using 'utf-8' scheme.")
xml.set(key, six.text_type(value, 'utf-8'))
xml.set(key, str(value, 'utf-8'))
except ValueError:
exception_message = format_xml_exception_message(self.location, key, value)
log.exception(exception_message)
@@ -740,7 +738,7 @@ class VideoBlock(
video_id=edx_video_id,
resource_fs=resource_fs,
static_dir=EXPORT_IMPORT_STATIC_DIR,
course_id=six.text_type(self.runtime.course_id.for_branch(None))
course_id=str(self.runtime.course_id.for_branch(None))
)
# Update xml with edxval metadata
xml.append(exported_metadata['xml'])
@@ -780,15 +778,15 @@ class VideoBlock(
A full youtube url to the video whose ID is passed in
"""
if youtube_id:
return u'https://www.youtube.com/watch?v={0}'.format(youtube_id)
return f'https://www.youtube.com/watch?v={youtube_id}'
else:
return u''
return ''
def get_context(self):
"""
Extend context by data for transcript basic tab.
"""
_context = super(VideoBlock, self).get_context() # lint-amnesty, pylint: disable=super-with-arguments
_context = super().get_context()
metadata_fields = copy.deepcopy(self.editable_metadata_fields)
@@ -891,7 +889,7 @@ class VideoBlock(
Arguments:
id_generator is used to generate course-specific urls and identifiers
"""
if isinstance(xml, six.string_types):
if isinstance(xml, str):
xml = etree.fromstring(xml)
field_data = {}
@@ -937,7 +935,7 @@ class VideoBlock(
normalized_speed = speed[:-1] if speed.endswith('0') else speed
# If the user has specified html5 sources, make sure we don't use the default video
if youtube_id != '' or 'html5_sources' in field_data:
field_data['youtube_id_{0}'.format(normalized_speed.replace('.', '_'))] = youtube_id
field_data['youtube_id_{}'.format(normalized_speed.replace('.', '_'))] = youtube_id
elif attr in conversions:
field_data[attr] = conversions[attr](value)
elif attr not in cls.fields: # lint-amnesty, pylint: disable=unsupported-membership-test
@@ -1016,7 +1014,7 @@ class VideoBlock(
return edx_video_id
def index_dictionary(self):
xblock_body = super(VideoBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments
xblock_body = super().index_dictionary()
video_body = {
"display_name": self.display_name,
}
@@ -1061,7 +1059,7 @@ class VideoBlock(
"""
Returns the VAL data for the requested video profiles for the given course.
"""
return edxval_api.get_video_info_for_course_and_profiles(six.text_type(course_id), video_profile_names)
return edxval_api.get_video_info_for_course_and_profiles(str(course_id), video_profile_names)
def student_view_data(self, context=None):
"""

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Module contains utils specific for video_module but not for transcripts.
"""
@@ -6,13 +5,11 @@ Module contains utils specific for video_module but not for transcripts.
import logging
from collections import OrderedDict
from urllib.parse import parse_qs, urlencode, urlparse, urlsplit, urlunsplit
import six
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import URLValidator
from six.moves import zip
from six.moves.urllib.parse import parse_qs, urlencode, urlparse, urlsplit, urlunsplit
log = logging.getLogger(__name__)
@@ -106,7 +103,7 @@ def format_xml_exception_message(location, key, value):
when setting xml attributes.
"""
exception_message = "Block-location:{location}, Key:{key}, Value:{value}".format(
location=six.text_type(location),
location=str(location),
key=key,
value=value
)

View File

@@ -14,7 +14,7 @@ from xmodule.fields import RelativeTime
_ = lambda text: text
class VideoFields(object):
class VideoFields:
"""Fields for `VideoBlock`."""
display_name = String(
help=_("The display name for this component."),

View File

@@ -12,8 +12,6 @@ import logging
from pkg_resources import resource_string
import six
from six.moves import map
from web_fragments.fragment import Fragment
from xblock.fields import Boolean, Dict, Integer, List, Scope, String
from xmodule.editing_module import EditingMixin
@@ -141,7 +139,7 @@ class WordCloudBlock( # pylint: disable=abstract-method
def get_state(self):
"""Return success json answer for client."""
if self.submitted:
total_count = sum(six.itervalues(self.all_words))
total_count = sum(self.all_words.values())
return json.dumps({
'status': 'success',
'submitted': True,
@@ -318,7 +316,7 @@ class WordCloudBlock( # pylint: disable=abstract-method
# values may be numeric / string or dict
# default implementation is an empty dict
xblock_body = super(WordCloudBlock, self).index_dictionary() # lint-amnesty, pylint: disable=super-with-arguments
xblock_body = super().index_dictionary()
index_body = {
"display_name": self.display_name,

View File

@@ -7,7 +7,6 @@ import time
from collections import namedtuple
from functools import partial
import six
import yaml
from contracts import contract, new_contract
from django.utils.encoding import python_2_unicode_compatible
@@ -16,8 +15,6 @@ from lxml import etree
from opaque_keys.edx.asides import AsideDefinitionKeyV2, AsideUsageKeyV2
from opaque_keys.edx.keys import UsageKey
from pkg_resources import resource_exists, resource_isdir, resource_listdir, resource_string
from six import text_type
from six.moves import map
from web_fragments.fragment import Fragment
from webob import Response
from webob.multidict import MultiDict
@@ -78,8 +75,8 @@ STUDIO_VIEW = 'studio_view'
PREVIEW_VIEWS = [STUDENT_VIEW, PUBLIC_VIEW, AUTHOR_VIEW]
DEFAULT_PUBLIC_VIEW_MESSAGE = (
u'This content is only accessible to enrolled learners. '
u'Sign in or register, and enroll in this course to view it.'
'This content is only accessible to enrolled learners. '
'Sign in or register, and enroll in this course to view it.'
)
# Make '_' a no-op so we can scrape strings. Using lambda instead of
@@ -203,7 +200,7 @@ def dummy_track(_event_type, _event):
pass
class HTMLSnippet(object):
class HTMLSnippet:
"""
A base class defining an interface for an object that is able to present an
html snippet, along with associated javascript and css
@@ -300,7 +297,7 @@ class HTMLSnippet(object):
Return the html used to display this snippet
"""
raise NotImplementedError(
"get_html() must be provided by specific modules - not present in {0}"
"get_html() must be provided by specific modules - not present in {}"
.format(self.__class__))
@@ -319,7 +316,7 @@ def shim_xmodule_js(fragment, js_module_name):
add_webpack_to_fragment(fragment, 'XModuleShim')
class XModuleFields(object):
class XModuleFields:
"""
Common fields for XModules.
"""
@@ -369,7 +366,7 @@ class XModuleMixin(XModuleFields, XBlock):
self.xmodule_runtime = None
self._asides = []
super(XModuleMixin, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(*args, **kwargs)
@property
def runtime(self):
@@ -484,8 +481,8 @@ class XModuleMixin(XModuleFields, XBlock):
result[field.name] = field.read_json(self)
except TypeError as exception:
exception_message = "{message}, Block-location:{location}, Field-name:{field_name}".format(
message=text_type(exception),
location=text_type(self.location),
message=str(exception),
location=str(self.location),
field_name=field.name
)
raise TypeError(exception_message) # lint-amnesty, pylint: disable=raise-missing-from
@@ -551,7 +548,7 @@ class XModuleMixin(XModuleFields, XBlock):
return [
child
for child
in super(XModuleMixin, self).get_children(usage_id_filter) # lint-amnesty, pylint: disable=super-with-arguments
in super().get_children(usage_id_filter)
if child is not None
]
@@ -561,9 +558,9 @@ class XModuleMixin(XModuleFields, XBlock):
is an error while retrieving the block.
"""
try:
child = super(XModuleMixin, self).get_child(usage_id) # lint-amnesty, pylint: disable=super-with-arguments
child = super().get_child(usage_id)
except ItemNotFoundError:
log.warning(u'Unable to load item %s, skipping', usage_id)
log.warning('Unable to load item %s, skipping', usage_id)
return None
if child is None:
@@ -810,14 +807,14 @@ class XModuleMixin(XModuleFields, XBlock):
Default message for blocks that don't implement public_view
"""
alert_html = HTML(
u'<div class="page-banner"><div class="alert alert-warning">'
u'<span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span>'
u'<div class="message-content">{}</div></div></div>'
'<div class="page-banner"><div class="alert alert-warning">'
'<span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span>'
'<div class="message-content">{}</div></div></div>'
)
if self.display_name:
display_text = _(
u'{display_name} is only accessible to enrolled learners. '
'{display_name} is only accessible to enrolled learners. '
'Sign in or register, and enroll in this course to view it.'
).format(
display_name=self.display_name
@@ -828,7 +825,7 @@ class XModuleMixin(XModuleFields, XBlock):
return Fragment(alert_html.format(display_text))
class ProxyAttribute(object):
class ProxyAttribute:
"""
A (python) descriptor that proxies attribute access.
@@ -876,7 +873,7 @@ descriptor_attr = partial(ProxyAttribute, 'descriptor') # pylint: disable=inval
module_runtime_attr = partial(ProxyAttribute, 'xmodule_runtime') # pylint: disable=invalid-name
class XModuleToXBlockMixin(object):
class XModuleToXBlockMixin:
"""
Common code needed by XModule and XBlocks converted from XModules.
"""
@@ -892,7 +889,7 @@ class XModuleToXBlockMixin(object):
"""
XBlock handler that wraps `handle_ajax`
"""
class FileObjForWebobFiles(object):
class FileObjForWebobFiles:
"""
Turn Webob cgi.FieldStorage uploaded files into pure file objects.
@@ -912,7 +909,7 @@ class XModuleToXBlockMixin(object):
# WebOb requests have multiple entries for uploaded files. handle_ajax
# expects a single entry as a list.
request_post = MultiDict(request.POST)
for key in set(six.iterkeys(request.POST)):
for key in set(request.POST.keys()):
if hasattr(request.POST[key], "file"):
request_post[key] = list(map(FileObjForWebobFiles, request.POST.getall(key)))
@@ -955,7 +952,7 @@ class XModule(XModuleToXBlockMixin, HTMLSnippet, XModuleMixin): # lint-amnesty,
# Set the descriptor first so that we can proxy to it
self.descriptor = descriptor
self._runtime = None
super(XModule, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(*args, **kwargs)
self.runtime.xmodule_instance = self
@property
@@ -968,12 +965,12 @@ class XModule(XModuleToXBlockMixin, HTMLSnippet, XModuleMixin): # lint-amnesty,
def __str__(self):
# xss-lint: disable=python-wrap-html
return u'<x_module(id={0})>'.format(self.id) # lint-amnesty, pylint: disable=no-member
return f'<x_module(id={self.id})>' # lint-amnesty, pylint: disable=no-member
def handle_ajax(self, _dispatch, _data):
""" dispatch is last part of the URL.
data is a dictionary-like object with the content of the request"""
return u""
return ""
def get_child(self, usage_id):
if usage_id in self._child_cache:
@@ -1028,13 +1025,13 @@ def policy_key(location):
Get the key for a location in a policy file. (Since the policy file is
specific to a course, it doesn't need the full location url).
"""
return u'{cat}/{name}'.format(cat=location.block_type, name=location.block_id)
return f'{location.block_type}/{location.block_id}'
Template = namedtuple("Template", "metadata data children")
class ResourceTemplates(object):
class ResourceTemplates:
"""
Gets the templates associated w/ a containing cls. The cls must have a 'template_dir_name' attribute.
It finds the templates as directly in this directory under 'templates'.
@@ -1071,7 +1068,7 @@ class ResourceTemplates(object):
if getattr(cls, 'template_dir_name', None):
dirname = os.path.join('templates', cls.template_dir_name) # lint-amnesty, pylint: disable=no-member
if not resource_isdir(__name__, dirname):
log.warning(u"No resource directory {dir} found when loading {cls_name} templates".format(
log.warning("No resource directory {dir} found when loading {cls_name} templates".format(
dir=dirname,
cls_name=cls.__name__,
))
@@ -1099,7 +1096,7 @@ class ResourceTemplates(object):
return template
class XModuleDescriptorToXBlockMixin(object):
class XModuleDescriptorToXBlockMixin:
"""
Common code needed by XModuleDescriptor and XBlocks converted from XModules.
"""
@@ -1133,9 +1130,9 @@ class XModuleDescriptorToXBlockMixin(object):
legacy XModule code. Use the "normal" XBlock parsing code.
"""
try:
return super(XModuleDescriptorToXBlockMixin, cls).parse_xml_new_runtime(node, runtime, keys)
return super().parse_xml_new_runtime(node, runtime, keys)
except AttributeError:
return super(XModuleDescriptorToXBlockMixin, cls).parse_xml(node, runtime, keys, id_generator=None)
return super().parse_xml(node, runtime, keys, id_generator=None)
@classmethod
def from_xml(cls, xml_data, system, id_generator):
@@ -1226,7 +1223,7 @@ class XModuleDescriptor(XModuleDescriptorToXBlockMixin, HTMLSnippet, ResourceTem
XModuleDescriptor.__init__ takes the same arguments as xblock.core:XBlock.__init__
"""
super(XModuleDescriptor, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(*args, **kwargs)
# update_version is the version which last updated this xblock v prev being the penultimate updater
# leaving off original_version since it complicates creation w/o any obv value yet and is computable
# by following previous until None
@@ -1271,7 +1268,7 @@ class XModuleDescriptor(XModuleDescriptorToXBlockMixin, HTMLSnippet, ResourceTem
performance if we have to rely on lists and equality rather than sets,
dictionaries, and identity-based hash functions.
"""
return super(XModuleDescriptor, self).__hash__() # lint-amnesty, pylint: disable=super-with-arguments
return super().__hash__()
def __repr__(self):
return (
@@ -1345,7 +1342,7 @@ class XModuleDescriptor(XModuleDescriptorToXBlockMixin, HTMLSnippet, ResourceTem
return Fragment(self.get_html())
class ConfigurableFragmentWrapper(object):
class ConfigurableFragmentWrapper:
"""
Runtime mixin that allows for composition of many `wrap_xblock` wrappers
"""
@@ -1357,7 +1354,7 @@ class ConfigurableFragmentWrapper(object):
...
return wrapped_frag
"""
super(ConfigurableFragmentWrapper, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(**kwargs)
if wrappers is not None:
self.wrappers = wrappers
else:
@@ -1411,7 +1408,7 @@ def descriptor_global_local_resource_url(block, uri):
raise NotImplementedError("Applications must monkey-patch this function before using local_resource_url for studio_view") # lint-amnesty, pylint: disable=line-too-long
class MetricsMixin(object):
class MetricsMixin:
"""
Mixin for adding metric logging for render and handle methods in the DescriptorSystem and ModuleSystem.
"""
@@ -1420,7 +1417,7 @@ class MetricsMixin(object):
start_time = time.time()
try:
status = "success"
return super(MetricsMixin, self).render(block, view_name, context=context) # lint-amnesty, pylint: disable=super-with-arguments
return super().render(block, view_name, context=context)
except:
status = "failure"
@@ -1431,12 +1428,12 @@ class MetricsMixin(object):
duration = end_time - start_time
course_id = getattr(self, 'course_id', '')
tags = [ # lint-amnesty, pylint: disable=unused-variable
u'view_name:{}'.format(view_name),
u'action:render',
u'action_status:{}'.format(status),
u'course_id:{}'.format(course_id),
u'block_type:{}'.format(block.scope_ids.block_type),
u'block_family:{}'.format(block.entry_point),
f'view_name:{view_name}',
'action:render',
f'action_status:{status}',
f'course_id:{course_id}',
f'block_type:{block.scope_ids.block_type}',
f'block_family:{block.entry_point}',
]
log.debug(
"%.3fs - render %s.%s (%s)",
@@ -1450,7 +1447,7 @@ class MetricsMixin(object):
start_time = time.time()
try:
status = "success"
return super(MetricsMixin, self).handle(block, handler_name, request, suffix=suffix) # lint-amnesty, pylint: disable=super-with-arguments
return super().handle(block, handler_name, request, suffix=suffix)
except:
status = "failure"
@@ -1461,12 +1458,12 @@ class MetricsMixin(object):
duration = end_time - start_time
course_id = getattr(self, 'course_id', '')
tags = [ # lint-amnesty, pylint: disable=unused-variable
u'handler_name:{}'.format(handler_name),
u'action:handle',
u'action_status:{}'.format(status),
u'course_id:{}'.format(course_id),
u'block_type:{}'.format(block.scope_ids.block_type),
u'block_family:{}'.format(block.entry_point),
f'handler_name:{handler_name}',
'action:handle',
f'action_status:{status}',
f'course_id:{course_id}',
f'block_type:{block.scope_ids.block_type}',
f'block_family:{block.entry_point}',
]
log.debug(
"%.3fs - handle %s.%s (%s)",
@@ -1504,7 +1501,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
"""
kwargs.setdefault('id_reader', OpaqueKeyReader())
kwargs.setdefault('id_generator', AsideKeyGenerator())
super(DescriptorSystem, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(**kwargs)
# This is used by XModules to write out separate files during xml export
self.export_fs = None
@@ -1529,7 +1526,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
"""
if block_type in self.disabled_xblock_types():
return self.default_class
return super(DescriptorSystem, self).load_block_type(block_type) # lint-amnesty, pylint: disable=super-with-arguments
return super().load_block_type(block_type)
def get_field_provenance(self, xblock, field):
"""
@@ -1576,7 +1573,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
"""
See :meth:`xblock.runtime.Runtime:applicable_aside_types` for documentation.
"""
potential_set = set(super(DescriptorSystem, self).applicable_aside_types(block)) # lint-amnesty, pylint: disable=super-with-arguments
potential_set = set(super().applicable_aside_types(block))
if getattr(block, 'xmodule_runtime', None) is not None:
if hasattr(block.xmodule_runtime, 'applicable_aside_types'):
application_set = set(block.xmodule_runtime.applicable_aside_types(block))
@@ -1613,7 +1610,7 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
An object implementing the requested service, or None.
"""
# getting the service from parent module. making sure of block service declarations.
service = super(DescriptorSystem, self).service(block=block, service_name=service_name) # lint-amnesty, pylint: disable=super-with-arguments
service = super().service(block=block, service_name=service_name)
# Passing the block to service if it is callable e.g. ModuleI18nService. It is the responsibility of calling
# service to handle the passing argument.
if callable(service):
@@ -1631,7 +1628,7 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr
created from that xml
"""
super(XMLParsingSystem, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(**kwargs)
self.process_xml = process_xml
def _usage_id_from_node(self, node, parent_id, id_generator=None):
@@ -1724,7 +1721,7 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr
"""
course_key = xblock.scope_ids.usage_id.course_key
for field in six.itervalues(xblock.fields):
for field in xblock.fields.values():
if field.is_set_on(xblock):
field_value = getattr(xblock, field.name)
if field_value is None:
@@ -1734,8 +1731,8 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr
elif isinstance(field, ReferenceList):
setattr(xblock, field.name, [self._make_usage_key(course_key, ele) for ele in field_value])
elif isinstance(field, ReferenceValueDict):
for key, subvalue in six.iteritems(field_value):
assert isinstance(subvalue, six.string_types)
for key, subvalue in field_value.items():
assert isinstance(subvalue, str)
field_value[key] = self._make_usage_key(course_key, subvalue)
setattr(xblock, field.name, field_value)
@@ -1833,7 +1830,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
# explicit field_data during construct_xblock.
kwargs.setdefault('id_reader', getattr(descriptor_runtime, 'id_reader', OpaqueKeyReader()))
kwargs.setdefault('id_generator', getattr(descriptor_runtime, 'id_generator', AsideKeyGenerator()))
super(ModuleSystem, self).__init__(field_data=field_data, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(field_data=field_data, **kwargs)
self.STATIC_URL = static_url
self.xqueue = xqueue
@@ -1885,7 +1882,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
# Remove value set transiently by XBlock
kwargs.pop('_view_name')
return "{}{}".format(self.__class__.__name__, kwargs)
return f"{self.__class__.__name__}{kwargs}"
@property
def ajax_url(self):
@@ -1919,7 +1916,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
An object implementing the requested service, or None.
"""
# getting the service from parent module. making sure of block service declarations.
service = super(ModuleSystem, self).service(block=block, service_name=service_name) # lint-amnesty, pylint: disable=super-with-arguments
service = super().service(block=block, service_name=service_name)
# Passing the block to service if it is callable e.g. ModuleI18nService. It is the responsibility of calling
# service to handle the passing argument.
if callable(service):
@@ -1927,7 +1924,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime):
return service
class CombinedSystem(object):
class CombinedSystem:
"""
This class is a shim to allow both pure XBlocks and XModuleDescriptors
that have been bound as XModules to access both the attributes of ModuleSystem
@@ -2029,7 +2026,7 @@ class CombinedSystem(object):
Always set the attr on the DescriptorSystem.
"""
if name in self.__slots__:
return super(CombinedSystem, self).__setattr__(name, value) # lint-amnesty, pylint: disable=super-with-arguments
return super().__setattr__(name, value)
if self._module_system:
setattr(self._module_system, name, value)
@@ -2045,10 +2042,10 @@ class CombinedSystem(object):
delattr(self._descriptor_system, name)
def __repr__(self):
return "CombinedSystem({!r}, {!r})".format(self._module_system, self._descriptor_system)
return f"CombinedSystem({self._module_system!r}, {self._descriptor_system!r})"
class DoNothingCache(object):
class DoNothingCache:
"""A duck-compatible object to use in ModuleSystem when there's no cache."""
def get(self, _key):
return None

View File

@@ -45,9 +45,9 @@ def is_pointer_tag(xml_obj):
Returns a bool.
"""
if xml_obj.tag != "course":
expected_attr = set(['url_name'])
expected_attr = {'url_name'}
else:
expected_attr = set(['url_name', 'course', 'org'])
expected_attr = {'url_name', 'course', 'org'}
actual_attr = set(xml_obj.attrib.keys())
@@ -63,7 +63,7 @@ def serialize_field(value):
If the value is a string, then we simply return what was passed in.
Otherwise, we return json.dumps on the input value.
"""
if isinstance(value, six.string_types):
if isinstance(value, str):
return value
return json.dumps(value, cls=EdxJSONEncoder)
@@ -101,7 +101,7 @@ def deserialize_field(field, value):
return value
class XmlParserMixin(object):
class XmlParserMixin:
"""
Class containing XML parsing functionality shared between XBlock and XModuleDescriptor.
"""
@@ -208,7 +208,7 @@ class XmlParserMixin(object):
return cls.file_to_xml(xml_file)
except Exception as err: # lint-amnesty, pylint: disable=broad-except
# Add info about where we are, but keep the traceback
msg = 'Unable to load file contents at path %s for item %s: %s ' % (
msg = 'Unable to load file contents at path {} for item {}: {} '.format(
filepath, def_id, err)
six.reraise(Exception, msg, sys.exc_info()[2])
@@ -275,7 +275,7 @@ class XmlParserMixin(object):
Returns a dictionary {key: value}.
"""
metadata = {'xml_attributes': {}}
for attr, val in six.iteritems(xml_object.attrib):
for attr, val in xml_object.attrib.items():
# VS[compat]. Remove after all key translations done
attr = cls._translate(attr)
@@ -295,7 +295,7 @@ class XmlParserMixin(object):
Add the keys in policy to metadata, after processing them
through the attrmap. Updates the metadata dict in place.
"""
for attr, value in six.iteritems(policy):
for attr, value in policy.items():
attr = cls._translate(attr)
if attr not in cls.fields:
# Store unknown attributes coming from policy.json
@@ -400,9 +400,9 @@ class XmlParserMixin(object):
legacy XModule code. Use the "normal" XBlock parsing code.
"""
try:
return super(XmlParserMixin, cls).parse_xml_new_runtime(node, runtime, keys)
return super().parse_xml_new_runtime(node, runtime, keys)
except AttributeError:
return super(XmlParserMixin, cls).parse_xml(node, runtime, keys, id_generator=None)
return super().parse_xml(node, runtime, keys, id_generator=None)
@classmethod
def _get_url_name(cls, node):
@@ -423,9 +423,7 @@ class XmlParserMixin(object):
@classmethod
def _format_filepath(cls, category, name):
return u'{category}/{name}.{ext}'.format(category=category,
name=name,
ext=cls.filename_extension)
return f'{category}/{name}.{cls.filename_extension}'
def export_to_file(self):
"""If this returns True, write the definition of this descriptor to a separate
@@ -472,7 +470,7 @@ class XmlParserMixin(object):
xml_object.set(attr, val)
except Exception: # lint-amnesty, pylint: disable=broad-except
logging.exception(
u'Failed to serialize metadata attribute %s with value %s in module %s. This could mean data loss!!!', # lint-amnesty, pylint: disable=line-too-long
'Failed to serialize metadata attribute %s with value %s in module %s. This could mean data loss!!!', # lint-amnesty, pylint: disable=line-too-long
attr, val, self.url_name
)
@@ -520,7 +518,7 @@ class XmlParserMixin(object):
"""
Return a list of all metadata fields that cannot be edited.
"""
non_editable_fields = super(XmlParserMixin, self).non_editable_metadata_fields # lint-amnesty, pylint: disable=super-with-arguments
non_editable_fields = super().non_editable_metadata_fields
non_editable_fields.append(XmlParserMixin.xml_attributes)
return non_editable_fields
@@ -551,7 +549,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method
# This only exists to satisfy subclasses that both:
# a) define from_xml themselves
# b) call super(..).from_xml(..)
return super(XmlMixin, cls).parse_xml(
return super().parse_xml(
etree.fromstring(xml_data),
system,
None, # This is ignored by XmlParserMixin
@@ -568,7 +566,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method
# from XModuleDescriptor, which actually calls `from_xml`.
return super(XmlParserMixin, cls).parse_xml(node, runtime, keys, id_generator) # pylint: disable=bad-super-call
else:
return super(XmlMixin, cls).parse_xml(node, runtime, keys, id_generator)
return super().parse_xml(node, runtime, keys, id_generator)
@classmethod
def parse_xml_new_runtime(cls, node, runtime, keys):
@@ -577,9 +575,9 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method
legacy XModule code. Use the "normal" XBlock parsing code.
"""
try:
return super(XmlMixin, cls).parse_xml_new_runtime(node, runtime, keys)
return super().parse_xml_new_runtime(node, runtime, keys)
except AttributeError:
return super(XmlMixin, cls).parse_xml(node, runtime, keys, id_generator=None)
return super().parse_xml(node, runtime, keys, id_generator=None)
def export_to_xml(self, resource_fs): # lint-amnesty, pylint: disable=unused-argument
"""
@@ -599,7 +597,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method
# a) define export_to_xml themselves
# b) call super(..).export_to_xml(..)
node = Element(self.category)
super(XmlMixin, self).add_xml_to_node(node) # lint-amnesty, pylint: disable=super-with-arguments
super().add_xml_to_node(node)
return etree.tostring(node)
def add_xml_to_node(self, node):
@@ -612,7 +610,7 @@ class XmlMixin(XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method
# from XModuleDescriptor, which actually calls `export_to_xml`.
super(XmlParserMixin, self).add_xml_to_node(node) # pylint: disable=bad-super-call
else:
super(XmlMixin, self).add_xml_to_node(node) # lint-amnesty, pylint: disable=super-with-arguments
super().add_xml_to_node(node)
class XmlDescriptor(XmlMixin, XModuleDescriptor): # lint-amnesty, pylint: disable=abstract-method