Ran pyupgrade on lms/djangoapps

Ran pyupgrade on lms/djangoapps/lms_xblock
Ran pyupgrade on lms/djangoapps/lti_provider
This commit is contained in:
usamasadiq
2021-02-16 17:19:59 +05:00
parent ba16e05899
commit f9cfbf027c
24 changed files with 140 additions and 152 deletions

View File

@@ -12,8 +12,8 @@ class LMSXBlockConfig(AppConfig):
"""
Default configuration for the "lms.djangoapps.lms_xblock" Django application.
"""
name = u'lms.djangoapps.lms_xblock'
verbose_name = u'LMS XBlock'
name = 'lms.djangoapps.lms_xblock'
verbose_name = 'LMS XBlock'
def ready(self):
from .runtime import handler_url, local_resource_url

View File

@@ -24,7 +24,7 @@ class LmsFieldData(SplitFieldData):
self._authored_data = authored_data
self._student_data = student_data
super(LmsFieldData, self).__init__({ # lint-amnesty, pylint: disable=super-with-arguments
super().__init__({
Scope.content: authored_data,
Scope.settings: authored_data,
Scope.parent: authored_data,

View File

@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
@@ -19,7 +16,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
('disabled_blocks', models.TextField(default=u'about course_info static_tab', help_text=u'Space-separated list of XBlocks on which XBlockAsides should never render.')),
('disabled_blocks', models.TextField(default='about course_info static_tab', help_text='Space-separated list of XBlocks on which XBlockAsides should never render.')),
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
],
options={

View File

@@ -5,7 +5,6 @@ Namespace that defines fields common to all blocks used in the LMS
#from django.utils.translation import ugettext_noop as _
import six
from lazy import lazy
from xblock.core import XBlock, XBlockMixin
from xblock.exceptions import JsonHandlerError
@@ -21,16 +20,16 @@ from xmodule.partitions.partitions import NoSuchUserPartitionError, NoSuchUserPa
_ = lambda text: text
INVALID_USER_PARTITION_VALIDATION_COMPONENT = _(
u"This component's access settings refer to deleted or invalid group configurations."
"This component's access settings refer to deleted or invalid group configurations."
)
INVALID_USER_PARTITION_VALIDATION_UNIT = _(
u"This unit's access settings refer to deleted or invalid group configurations."
"This unit's access settings refer to deleted or invalid group configurations."
)
INVALID_USER_PARTITION_GROUP_VALIDATION_COMPONENT = _(
u"This component's access settings refer to deleted or invalid groups."
"This component's access settings refer to deleted or invalid groups."
)
INVALID_USER_PARTITION_GROUP_VALIDATION_UNIT = _(u"This unit's access settings refer to deleted or invalid groups.")
NONSENSICAL_ACCESS_RESTRICTION = _(u"This component's access settings contradict its parent's access settings.")
INVALID_USER_PARTITION_GROUP_VALIDATION_UNIT = _("This unit's access settings refer to deleted or invalid groups.")
NONSENSICAL_ACCESS_RESTRICTION = _("This component's access settings contradict its parent's access settings.")
class GroupAccessDict(Dict):
@@ -43,7 +42,7 @@ class GroupAccessDict(Dict):
def to_json(self, value):
if value is not None:
return {six.text_type(k): value[k] for k in value}
return {str(k): value[k] for k in value}
@XBlock.needs('partitions')
@@ -158,7 +157,7 @@ class LmsBlockMixin(XBlockMixin):
if user_partition.id == user_partition_id:
return user_partition
raise NoSuchUserPartitionError(u"could not find a UserPartition with ID [{}]".format(user_partition_id))
raise NoSuchUserPartitionError(f"could not find a UserPartition with ID [{user_partition_id}]")
def _has_nonsensical_access_settings(self):
"""
@@ -185,7 +184,7 @@ class LmsBlockMixin(XBlockMixin):
parent_group_access = parent.group_access
component_group_access = self.group_access
for user_partition_id, parent_group_ids in six.iteritems(parent_group_access):
for user_partition_id, parent_group_ids in parent_group_access.items():
component_group_ids = component_group_access.get(user_partition_id) # pylint: disable=no-member
if component_group_ids:
return parent_group_ids and not set(component_group_ids).issubset(set(parent_group_ids))
@@ -198,12 +197,12 @@ class LmsBlockMixin(XBlockMixin):
Validates the state of this xblock instance.
"""
_ = self.runtime.service(self, "i18n").ugettext
validation = super(LmsBlockMixin, self).validate() # lint-amnesty, pylint: disable=super-with-arguments
validation = super().validate()
has_invalid_user_partitions = False
has_invalid_groups = False
block_is_unit = is_unit(self)
for user_partition_id, group_ids in six.iteritems(self.group_access):
for user_partition_id, group_ids in self.group_access.items(): # lint-amnesty, pylint:disable=no-member
try:
user_partition = self._get_user_partition(user_partition_id)
except NoSuchUserPartitionError:
@@ -254,10 +253,10 @@ class LmsBlockMixin(XBlockMixin):
"""
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 completion_service.can_mark_block_complete_on_view(self):
raise JsonHandlerError(400, u"Block not configured for completion on view.")
raise JsonHandlerError(400, "Block not configured for completion on view.")
self.runtime.publish(self, "completion", data)
return {'result': 'ok'}

View File

@@ -23,8 +23,8 @@ class XBlockAsidesConfig(ConfigurationModel):
app_label = "lms_xblock"
disabled_blocks = TextField(
default=u"about course_info static_tab",
help_text=u"Space-separated list of XBlocks on which XBlockAsides should never render."
default="about course_info static_tab",
help_text="Space-separated list of XBlocks on which XBlockAsides should never render."
)
@classmethod

View File

@@ -3,7 +3,6 @@ Module implementing `xblock.runtime.Runtime` functionality for the LMS
"""
import six
import xblock.reference.plugins
from completion.services import CompletionService
from django.conf import settings
@@ -46,7 +45,7 @@ def handler_url(block, handler_name, suffix='', query='', thirdparty=False):
# to ask for handler URLs without a student context.
func = getattr(block.__class__, handler_name, None)
if not func:
raise ValueError(u"{!r} is not a function name".format(handler_name))
raise ValueError(f"{handler_name!r} is not a function name")
# Is the following necessary? ProxyAttribute causes an UndefinedContext error
# if trying this without the module system.
@@ -58,8 +57,8 @@ def handler_url(block, handler_name, suffix='', query='', thirdparty=False):
view_name = 'xblock_handler_noauth'
url = reverse(view_name, kwargs={
'course_id': six.text_type(block.location.course_key),
'usage_id': quote_slashes(six.text_type(block.scope_ids.usage_id)),
'course_id': str(block.location.course_key),
'usage_id': quote_slashes(str(block.scope_ids.usage_id)),
'handler': handler_name,
'suffix': suffix,
})
@@ -91,7 +90,7 @@ def local_resource_url(block, uri):
return xblock_local_resource_url(block, uri)
class UserTagsService(object):
class UserTagsService:
"""
A runtime class that provides an interface to the user service. It handles filling in
the current course id and current user.
@@ -115,7 +114,7 @@ class UserTagsService(object):
key: the key for the value we want
"""
if scope != user_course_tag_api.COURSE_SCOPE:
raise ValueError(u"unexpected scope {0}".format(scope))
raise ValueError(f"unexpected scope {scope}")
return user_course_tag_api.get_course_tag(
self._get_current_user(),
@@ -131,7 +130,7 @@ class UserTagsService(object):
value: the value to set
"""
if scope != user_course_tag_api.COURSE_SCOPE:
raise ValueError(u"unexpected scope {0}".format(scope))
raise ValueError(f"unexpected scope {scope}")
return user_course_tag_api.set_course_tag(
self._get_current_user(),
@@ -166,7 +165,7 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
services['teams'] = TeamsService()
services['teams_configuration'] = TeamsConfigurationService()
services['call_to_action'] = CallToActionService()
super(LmsModuleSystem, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(**kwargs)
def handler_url(self, *args, **kwargs): # lint-amnesty, pylint: disable=signature-differs
"""
@@ -205,8 +204,8 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
runtime_class = 'LmsRuntime'
extra_data = {
'block-id': quote_slashes(six.text_type(block.scope_ids.usage_id)),
'course-id': quote_slashes(six.text_type(block.course_id)),
'block-id': quote_slashes(str(block.scope_ids.usage_id)),
'course-id': quote_slashes(str(block.course_id)),
'url-selector': 'asideBaseUrl',
'runtime-class': runtime_class,
}
@@ -219,7 +218,7 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
view,
frag,
context,
usage_id_serializer=six.text_type,
usage_id_serializer=str,
request_token=self.request_token,
extra_data=extra_data,
)
@@ -244,6 +243,6 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
# (see https://openedx.atlassian.net/browse/TE-811)
return [
aside_type
for aside_type in super(LmsModuleSystem, self).applicable_aside_types(block) # lint-amnesty, pylint: disable=super-with-arguments
for aside_type in super().applicable_aside_types(block)
if aside_type != 'acid_aside'
]

View File

@@ -2,21 +2,23 @@
Tests of the LMS XBlock Runtime and associated utilities
"""
from unittest.mock import Mock, patch
from urllib.parse import urlparse
import pytest
from ddt import data, ddt
from django.conf import settings
from django.test import TestCase
from mock import Mock, patch
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locations import BlockUsageLocator, CourseLocator
from six.moves.urllib.parse import urlparse
from xblock.exceptions import NoSuchServiceError
from xblock.fields import ScopeIds
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.badges.tests.factories import BadgeClassFactory
from lms.djangoapps.badges.tests.test_models import get_image
from lms.djangoapps.lms_xblock.runtime import LmsModuleSystem
from common.djangoapps.student.tests.factories import UserFactory
from xmodule.modulestore.django import ModuleI18nService
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@@ -54,7 +56,7 @@ class TestHandlerUrl(TestCase):
"""Test the LMS handler_url"""
def setUp(self):
super(TestHandlerUrl, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.block = BlockMock(name='block', scope_ids=ScopeIds(None, None, None, 'dummy'))
self.course_key = CourseLocator("org", "course", "run")
self.runtime = LmsModuleSystem(
@@ -119,7 +121,7 @@ class TestUserServiceAPI(TestCase):
"""Test the user service interface"""
def setUp(self):
super(TestUserServiceAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course_id = CourseLocator("org", "course", "run")
self.user = UserFactory.create()
@@ -169,7 +171,7 @@ class TestBadgingService(ModuleStoreTestCase):
"""Test the badging service interface"""
def setUp(self):
super(TestBadgingService, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course_id = CourseKey.from_string('course-v1:org+course+run')
self.mock_block = Mock()
@@ -235,7 +237,7 @@ class TestI18nService(ModuleStoreTestCase):
def setUp(self):
""" Setting up tests """
super(TestI18nService, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course = CourseFactory.create()
self.test_language = 'dummy language'
self.runtime = LmsModuleSystem(

View File

@@ -5,7 +5,6 @@ Management command to resend all lti scores for the requested course.
import textwrap
import six
from django.core.management import BaseCommand
from opaque_keys.edx.keys import CourseKey
@@ -29,11 +28,11 @@ class Command(BaseCommand):
help = textwrap.dedent(__doc__)
def add_arguments(self, parser):
parser.add_argument(u'course_keys', type=CourseKey.from_string, nargs='*')
parser.add_argument('course_keys', type=CourseKey.from_string, nargs='*')
def handle(self, *args, **options):
if options[u'course_keys']:
for course_key in options[u'course_keys']:
if options['course_keys']:
for course_key in options['course_keys']:
for assignment in self._iter_course_assignments(course_key):
self._send_score(assignment)
else:
@@ -46,7 +45,7 @@ class Command(BaseCommand):
"""
tasks.send_composite_outcome.delay(
assignment.user_id,
six.text_type(assignment.course_key),
str(assignment.course_key),
assignment.id,
assignment.version_number,
)

View File

@@ -3,14 +3,14 @@ Test lti_provider management commands.
"""
import six
from unittest.mock import patch
from django.test import TestCase
from mock import patch
from opaque_keys.edx.keys import CourseKey, UsageKey
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.lti_provider.management.commands import resend_lti_scores
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
from common.djangoapps.student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.utils import TEST_DATA_DIR
from xmodule.modulestore.xml_importer import import_course_from_xml
@@ -34,7 +34,7 @@ class CommandArgsTestCase(TestCase):
assert len(args.course_keys) == 2
key = args.course_keys[0]
assert isinstance(key, CourseKey)
assert six.text_type(key) == 'course-v1:edX+test_course+2525_fall'
assert str(key) == 'course-v1:edX+test_course+2525_fall'
def test_no_course_keys(self):
parser = self._get_arg_parser()
@@ -49,25 +49,25 @@ class CommandExecutionTestCase(SharedModuleStoreTestCase):
@classmethod
def setUpClass(cls):
super(CommandExecutionTestCase, cls).setUpClass()
cls.course_key = cls.store.make_course_key(u'edX', u'lti_provider', u'3000')
super().setUpClass()
cls.course_key = cls.store.make_course_key('edX', 'lti_provider', '3000')
import_course_from_xml(
cls.store,
u'test_user',
'test_user',
TEST_DATA_DIR,
source_dirs=[u'simple'],
source_dirs=['simple'],
static_content_store=None,
target_id=cls.course_key,
raise_on_failure=True,
create_if_not_present=True,
)
cls.lti_block = u'block-v1:edX+lti_provider+3000+type@chapter+block@chapter_2'
cls.lti_block = 'block-v1:edX+lti_provider+3000+type@chapter+block@chapter_2'
def setUp(self):
super(CommandExecutionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory()
self.user2 = UserFactory(username=u'anotheruser')
self.client.login(username=self.user.username, password=u'test')
self.user2 = UserFactory(username='anotheruser')
self.client.login(username=self.user.username, password='test')
def _configure_lti(self, usage_key):
"""
@@ -76,21 +76,21 @@ class CommandExecutionTestCase(SharedModuleStoreTestCase):
consumer = LtiConsumer.objects.create()
outcome_service = OutcomeService.objects.create(
lti_consumer=consumer,
lis_outcome_service_url=u'https://lol.tools'
lis_outcome_service_url='https://lol.tools'
)
GradedAssignment.objects.create(
user=self.user,
course_key=self.course_key,
usage_key=usage_key,
outcome_service=outcome_service,
lis_result_sourcedid=u'abc',
lis_result_sourcedid='abc',
)
GradedAssignment.objects.create(
user=self.user2,
course_key=self.course_key,
usage_key=usage_key,
outcome_service=outcome_service,
lis_result_sourcedid=u'xyz',
lis_result_sourcedid='xyz',
)
def _scores_sent_with_args(self, *args, **kwargs):
@@ -111,5 +111,5 @@ class CommandExecutionTestCase(SharedModuleStoreTestCase):
assert self._scores_sent_with_args(course_keys=[self.course_key])
def test_command_with_wrong_course_key(self):
fake_course_key = self.store.make_course_key(u'not', u'the', u'course')
fake_course_key = self.store.make_course_key('not', 'the', 'course')
assert not self._scores_sent_with_args(course_keys=[fake_course_key])

View File

@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
from openedx.core.lib.hash_utils import create_hash256, short_token
from django.conf import settings
@@ -63,10 +61,10 @@ class Migration(migrations.Migration):
),
migrations.AlterUniqueTogether(
name='ltiuser',
unique_together=set([('lti_consumer', 'lti_user_id')]),
unique_together={('lti_consumer', 'lti_user_id')},
),
migrations.AlterUniqueTogether(
name='gradedassignment',
unique_together=set([('outcome_service', 'lis_result_sourcedid')]),
unique_together={('outcome_service', 'lis_result_sourcedid')},
),
]

View File

@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from openedx.core.lib.hash_utils import short_token
from django.db import migrations, models

View File

@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from django.db import migrations, models
import openedx.core.djangolib.fields

View File

@@ -125,7 +125,7 @@ class GradedAssignment(models.Model):
lis_result_sourcedid = models.CharField(max_length=255, db_index=True)
version_number = models.IntegerField(default=0)
class Meta(object):
class Meta:
unique_together = ('outcome_service', 'lis_result_sourcedid')
@@ -142,5 +142,5 @@ class LtiUser(models.Model):
lti_user_id = models.CharField(max_length=255)
edx_user = models.OneToOneField(User, on_delete=models.CASCADE)
class Meta(object):
class Meta:
unique_together = ('lti_consumer', 'lti_user_id')

View File

@@ -38,9 +38,9 @@ def store_outcome_parameters(request_params, user, lti_consumer):
# to figure out the result service URL. As it stands, though, this
# is a badly-formed LTI request
log.warning(
u"Outcome Service: lis_outcome_service_url parameter missing "
u"from scored assignment; we will be unable to return a score. "
u"Request parameters: %s",
"Outcome Service: lis_outcome_service_url parameter missing "
"from scored assignment; we will be unable to return a score. "
"Request parameters: %s",
request_params
)
return
@@ -141,8 +141,8 @@ def send_score_update(assignment, score):
# necessary.
if not (response and check_replace_result_response(response)):
log.error(
u"Outcome Service: Failed to update score on LTI consumer. "
u"User: %s, course: %s, usage: %s, score: %s, status: %s, body: %s",
"Outcome Service: Failed to update score on LTI consumer. "
"User: %s, course: %s, usage: %s, score: %s, status: %s, body: %s",
assignment.user,
assignment.course_key,
assignment.usage_key,
@@ -192,7 +192,7 @@ def check_replace_result_response(response):
# Pylint doesn't recognize members in the LXML module
if response.status_code != 200:
log.error(
u"Outcome service response: Unexpected status code %s",
"Outcome service response: Unexpected status code %s",
response.status_code
)
return False
@@ -201,7 +201,7 @@ def check_replace_result_response(response):
xml = response.content
root = etree.fromstring(xml)
except etree.ParseError as ex:
log.error(u"Outcome service response: Failed to parse XML: %s\n %s", ex, xml)
log.error("Outcome service response: Failed to parse XML: %s\n %s", ex, xml)
return False
major_codes = root.xpath(
@@ -209,14 +209,14 @@ def check_replace_result_response(response):
namespaces={'ns': 'http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0'})
if len(major_codes) != 1:
log.error(
u"Outcome service response: Expected exactly one imsx_codeMajor field in response. Received %s",
"Outcome service response: Expected exactly one imsx_codeMajor field in response. Received %s",
major_codes
)
return False
if major_codes[0].text != 'success':
log.error(
u"Outcome service response: Unexpected major code: %s.",
"Outcome service response: Unexpected major code: %s.",
major_codes[0].text
)
return False

View File

@@ -10,9 +10,9 @@ from opaque_keys.edx.keys import LearningContextKey
import lms.djangoapps.lti_provider.outcomes as outcomes
from lms.djangoapps.grades.api import signals as grades_signals
from lms.djangoapps.lti_provider.tasks import send_composite_outcome, send_leaf_outcome
from lms.djangoapps.lti_provider.views import parse_course_and_usage_keys
from xmodule.modulestore.django import modulestore
from lms.djangoapps.lti_provider.tasks import send_composite_outcome, send_leaf_outcome
log = logging.getLogger(__name__)
@@ -70,8 +70,8 @@ def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
)
else:
log.error(
u"Outcome Service: Required signal parameter is None. "
u"points_possible: %s, points_earned: %s, user_id: %s, "
u"course_id: %s, usage_id: %s",
"Outcome Service: Required signal parameter is None. "
"points_possible: %s, points_earned: %s, user_id: %s, "
"course_id: %s, usage_id: %s",
points_possible, points_earned, user_id, course_id, usage_id
)

View File

@@ -3,7 +3,6 @@ Subclass of oauthlib's RequestValidator that checks an OAuth signature.
"""
import six
from oauthlib.oauth1 import RequestValidator, SignatureOnlyEndpoint
@@ -18,7 +17,7 @@ class SignatureValidator(RequestValidator):
"""
def __init__(self, lti_consumer):
super(SignatureValidator, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments
super().__init__()
self.endpoint = SignatureOnlyEndpoint(self)
self.lti_consumer = lti_consumer
@@ -99,7 +98,7 @@ class SignatureValidator(RequestValidator):
:return: True if the signature matches, False if it does not.
"""
method = six.text_type(request.method)
method = str(request.method)
url = request.build_absolute_uri()
body = request.body

View File

@@ -46,7 +46,7 @@ def send_composite_outcome(user_id, course_id, assignment_id, version):
assignment = GradedAssignment.objects.get(id=assignment_id)
if version != assignment.version_number:
log.info(
u"Score passback for GradedAssignment %s skipped. More recent score available.",
"Score passback for GradedAssignment %s skipped. More recent score available.",
assignment.id
)
return

View File

@@ -3,14 +3,15 @@ Tests for the LTI outcome service handlers, both in outcomes.py and in tasks.py
"""
from unittest.mock import ANY, MagicMock, patch
from django.test import TestCase
from lxml import etree
from mock import ANY, MagicMock, patch
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
import lms.djangoapps.lti_provider.outcomes as outcomes
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls
@@ -21,7 +22,7 @@ class StoreOutcomeParametersTest(TestCase):
"""
def setUp(self):
super(StoreOutcomeParametersTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory.create()
self.course_key = CourseLocator(
org='some_org',
@@ -135,7 +136,7 @@ class SignAndSendReplaceResultTest(TestCase):
"""
def setUp(self):
super(SignAndSendReplaceResultTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course_key = CourseLocator(
org='some_org',
course='some_course',
@@ -185,7 +186,7 @@ class XmlHandlingTest(TestCase):
methods in outcomes.py
"""
response_xml = u"""
response_xml = """
<imsx_POXEnvelopeResponse xmlns = "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
<imsx_POXHeader>
<imsx_POXResponseHeaderInfo>
@@ -298,7 +299,7 @@ class TestAssignmentsForProblem(ModuleStoreTestCase):
"""
def setUp(self):
super(TestAssignmentsForProblem, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory.create()
self.user_id = self.user.id
self.outcome_service = self.create_outcome_service('outcomes')

View File

@@ -3,10 +3,11 @@ Tests for the SignatureValidator class.
"""
from unittest.mock import patch
import ddt
from django.test import TestCase
from django.test.client import RequestFactory
from mock import patch
from lms.djangoapps.lti_provider.models import LtiConsumer
from lms.djangoapps.lti_provider.signature_validator import SignatureValidator
@@ -30,7 +31,7 @@ class ClientKeyValidatorTest(TestCase):
"""
def setUp(self):
super(ClientKeyValidatorTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.lti_consumer = get_lti_consumer()
def test_valid_client_key(self):
@@ -60,7 +61,7 @@ class NonceValidatorTest(TestCase):
"""
def setUp(self):
super(NonceValidatorTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.lti_consumer = get_lti_consumer()
def test_valid_nonce(self):
@@ -91,7 +92,7 @@ class SignatureValidatorTest(TestCase):
"""
def setUp(self):
super(SignatureValidatorTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.lti_consumer = get_lti_consumer()
def test_get_existing_client_secret(self):
@@ -110,7 +111,7 @@ class SignatureValidatorTest(TestCase):
Verify that the signature validaton library method is called using the
correct parameters derived from the HttpRequest.
"""
body = u'oauth_signature_method=HMAC-SHA1&oauth_version=1.0'
body = 'oauth_signature_method=HMAC-SHA1&oauth_version=1.0'
content_type = 'application/x-www-form-urlencoded'
request = RequestFactory().post('/url', body, content_type=content_type)
headers = {'Content-Type': content_type}

View File

@@ -3,15 +3,15 @@ Tests for the LTI outcome service handlers, both in outcomes.py and in tasks.py
"""
from unittest.mock import MagicMock, patch
import ddt
import six
from django.test import TestCase
from mock import MagicMock, patch
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
import lms.djangoapps.lti_provider.tasks as tasks
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
class BaseOutcomeTest(TestCase):
@@ -19,7 +19,7 @@ class BaseOutcomeTest(TestCase):
Super type for tests of both the leaf and composite outcome celery tasks.
"""
def setUp(self):
super(BaseOutcomeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.course_key = CourseLocator(
org='some_org',
course='some_course',
@@ -96,7 +96,7 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
"""
def setUp(self):
super(SendCompositeOutcomeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.descriptor = MagicMock()
self.descriptor.location = BlockUsageLocator(
course_key=self.course_key,
@@ -123,7 +123,7 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
def test_outcome_with_score_score(self, earned, possible, expected):
self.course_grade.score_for_module = MagicMock(return_value=(earned, possible))
tasks.send_composite_outcome(
self.user.id, six.text_type(self.course_key), self.assignment.id, 1
self.user.id, str(self.course_key), self.assignment.id, 1
)
self.send_score_update_mock.assert_called_once_with(self.assignment, expected)
@@ -131,6 +131,6 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
self.assignment.version_number = 2
self.assignment.save()
tasks.send_composite_outcome(
self.user.id, six.text_type(self.course_key), self.assignment.id, 1
self.user.id, str(self.course_key), self.assignment.id, 1
)
assert self.course_grade_mock.call_count == 0

View File

@@ -4,17 +4,18 @@ Tests for the LTI user management functionality
import string
from unittest.mock import MagicMock, PropertyMock, patch
import pytest
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.exceptions import PermissionDenied
from django.test import TestCase
from django.test.client import RequestFactory
from mock import MagicMock, PropertyMock, patch
from six.moves import range
from common.djangoapps.student.tests.factories import UserFactory
from .. import users
from ..models import LtiConsumer, LtiUser
from common.djangoapps.student.tests.factories import UserFactory # lint-amnesty, pylint: disable=wrong-import-order
class UserManagementHelperTest(TestCase):
@@ -23,7 +24,7 @@ class UserManagementHelperTest(TestCase):
"""
def setUp(self):
super(UserManagementHelperTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.request = RequestFactory().post('/')
self.old_user = UserFactory.create()
self.new_user = UserFactory.create()
@@ -68,7 +69,7 @@ class UserManagementHelperTest(TestCase):
# Check that the username contains only allowable characters
for char in range(len(username)): # lint-amnesty, pylint: disable=consider-using-enumerate
assert username[char] in (string.ascii_letters + string.digits), \
u"Username has forbidden character '{}'".format(username[char])
"Username has forbidden character '{}'".format(username[char])
@patch('lms.djangoapps.lti_provider.users.switch_user', autospec=True)
@@ -79,7 +80,7 @@ class AuthenticateLtiUserTest(TestCase):
"""
def setUp(self):
super(AuthenticateLtiUserTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.lti_consumer = LtiConsumer(
consumer_name='TestConsumer',
consumer_key='TestKey',
@@ -146,7 +147,7 @@ class CreateLtiUserTest(TestCase):
"""
def setUp(self):
super(CreateLtiUserTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.lti_consumer = LtiConsumer(
consumer_name='TestConsumer',
consumer_key='TestKey',
@@ -183,7 +184,7 @@ class LtiBackendTest(TestCase):
"""
def setUp(self):
super(LtiBackendTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.edx_user = UserFactory.create()
self.edx_user.save()
self.lti_consumer = LtiConsumer(

View File

@@ -3,36 +3,36 @@ Tests for the LTI provider views
"""
import six
from unittest.mock import MagicMock, patch
from django.test import TestCase
from django.test.client import RequestFactory
from django.urls import reverse
from mock import MagicMock, patch
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.courseware.testutils import RenderXBlockTestMixin
from lms.djangoapps.lti_provider import models, views
from common.djangoapps.student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
LTI_DEFAULT_PARAMS = {
'roles': u'Instructor,urn:lti:instrole:ims/lis/Administrator',
'context_id': u'lti_launch_context_id',
'oauth_version': u'1.0',
'oauth_consumer_key': u'consumer_key',
'oauth_signature': u'OAuth Signature',
'oauth_signature_method': u'HMAC-SHA1',
'oauth_timestamp': u'OAuth Timestamp',
'oauth_nonce': u'OAuth Nonce',
'user_id': u'LTI_User',
'roles': 'Instructor,urn:lti:instrole:ims/lis/Administrator',
'context_id': 'lti_launch_context_id',
'oauth_version': '1.0',
'oauth_consumer_key': 'consumer_key',
'oauth_signature': 'OAuth Signature',
'oauth_signature_method': 'HMAC-SHA1',
'oauth_timestamp': 'OAuth Timestamp',
'oauth_nonce': 'OAuth Nonce',
'user_id': 'LTI_User',
}
LTI_OPTIONAL_PARAMS = {
'context_title': u'context title',
'context_label': u'context label',
'lis_result_sourcedid': u'result sourcedid',
'lis_outcome_service_url': u'outcome service URL',
'tool_consumer_instance_guid': u'consumer instance guid'
'context_title': 'context title',
'context_label': 'context label',
'lis_result_sourcedid': 'result sourcedid',
'lis_outcome_service_url': 'outcome service URL',
'tool_consumer_instance_guid': 'consumer instance guid'
}
COURSE_KEY = CourseLocator(org='some_org', course='some_course', run='some_run')
@@ -62,13 +62,13 @@ def build_launch_request(extra_post_data=None, param_to_delete=None):
return request
class LtiTestMixin(object):
class LtiTestMixin:
"""
Mixin for LTI tests
"""
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_LTI_PROVIDER': True})
def setUp(self):
super(LtiTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
# Always accept the OAuth signature
self.mock_verify = MagicMock(return_value=True)
patcher = patch('lms.djangoapps.lti_provider.signature_validator.SignatureValidator.verify', self.mock_verify)
@@ -94,7 +94,7 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
Verifies that the LTI launch succeeds when passed a valid request.
"""
request = build_launch_request()
views.lti_launch(request, six.text_type(COURSE_KEY), six.text_type(USAGE_KEY))
views.lti_launch(request, str(COURSE_KEY), str(USAGE_KEY))
render.assert_called_with(request, USAGE_KEY)
@patch('lms.djangoapps.lti_provider.views.render_courseware')
@@ -105,7 +105,7 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
Verifies that the LTI launch succeeds when passed a valid request.
"""
request = build_launch_request(extra_post_data=LTI_OPTIONAL_PARAMS)
views.lti_launch(request, six.text_type(COURSE_KEY), six.text_type(USAGE_KEY))
views.lti_launch(request, str(COURSE_KEY), str(USAGE_KEY))
store_params.assert_called_with(
dict(list(ALL_PARAMS.items()) + list(LTI_OPTIONAL_PARAMS.items())),
request.user,
@@ -122,8 +122,8 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
request = build_launch_request()
views.lti_launch(
request,
six.text_type(COURSE_PARAMS['course_key']),
six.text_type(COURSE_PARAMS['usage_key'])
str(COURSE_PARAMS['course_key']),
str(COURSE_PARAMS['usage_key'])
)
store_params.assert_called_with(ALL_PARAMS, request.user, self.consumer)
@@ -175,7 +175,7 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
consumer = models.LtiConsumer.objects.get(
consumer_key=LTI_DEFAULT_PARAMS['oauth_consumer_key']
)
assert consumer.instance_guid == u'consumer instance guid'
assert consumer.instance_guid == 'consumer instance guid'
class LtiLaunchTestRender(LtiTestMixin, RenderXBlockTestMixin, ModuleStoreTestCase):
@@ -192,8 +192,8 @@ class LtiLaunchTestRender(LtiTestMixin, RenderXBlockTestMixin, ModuleStoreTestCa
lti_launch_url = reverse(
'lti_provider_launch',
kwargs={
'course_id': six.text_type(self.course.id),
'usage_id': six.text_type(usage_key)
'course_id': str(self.course.id),
'usage_id': str(usage_key)
}
)
if url_encoded_params:

View File

@@ -13,10 +13,9 @@ from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.exceptions import PermissionDenied
from django.db import IntegrityError, transaction
from six.moves import range
from lms.djangoapps.lti_provider.models import LtiUser
from common.djangoapps.student.models import UserProfile
from lms.djangoapps.lti_provider.models import LtiUser
def authenticate_lti_user(request, lti_user_id, lti_consumer):
@@ -55,7 +54,7 @@ def create_lti_user(lti_user_id, lti_consumer):
while not created:
try:
edx_user_id = generate_random_edx_username()
edx_email = "{}@{}".format(edx_user_id, settings.LTI_USER_EMAIL_DOMAIN)
edx_email = f"{edx_user_id}@{settings.LTI_USER_EMAIL_DOMAIN}"
with transaction.atomic():
edx_user = User.objects.create_user(
username=edx_user_id,
@@ -112,7 +111,7 @@ def generate_random_edx_username():
return username
class LtiBackend(object):
class LtiBackend:
"""
A Django authentication backend that authenticates users via LTI. This
backend will only return a User object if it is associated with an LTI

View File

@@ -5,19 +5,18 @@ LTI Provider view functions
import logging
import six
from django.conf import settings
from django.http import Http404, HttpResponseBadRequest, HttpResponseForbidden
from django.views.decorators.csrf import csrf_exempt
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey, UsageKey
from common.djangoapps.util.views import add_p3p_header
from lms.djangoapps.lti_provider.models import LtiConsumer
from lms.djangoapps.lti_provider.outcomes import store_outcome_parameters
from lms.djangoapps.lti_provider.signature_validator import SignatureValidator
from lms.djangoapps.lti_provider.users import authenticate_lti_user
from openedx.core.lib.url_utils import unquote_slashes
from common.djangoapps.util.views import add_p3p_header
log = logging.getLogger("edx.lti_provider")
@@ -78,7 +77,7 @@ def lti_launch(request, course_id, usage_id):
course_key, usage_key = parse_course_and_usage_keys(course_id, usage_id)
except InvalidKeyError:
log.error(
u'Invalid course key %s or usage key %s from request %s',
'Invalid course key %s or usage key %s from request %s',
course_id,
usage_id,
request
@@ -146,7 +145,7 @@ def render_courseware(request, usage_key):
"""
# return an HttpResponse object that contains the template and necessary context to render the courseware.
from lms.djangoapps.courseware.views.views import render_xblock
return render_xblock(request, six.text_type(usage_key), check_if_enrolled=False)
return render_xblock(request, str(usage_key), check_if_enrolled=False)
def parse_course_and_usage_keys(course_id, usage_id):