diff --git a/.travis.yml b/.travis.yml index f1ba242d663c70bba60a0f5bc29e30451c23470e..1990ee85f2ff5900095954b4fc4eb13ac91ccdda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python sudo: false install: -- pip install -r requirements/travis.txt + - pip install -r requirements/travis.txt after_success: coveralls env: global: @@ -12,19 +12,16 @@ deploy: user: edx distributions: sdist bdist_wheel on: - python: 3.5 + python: 3.8 tags: true password: secure: DKlhHIFctJS9k/1sdlKfL34MwVIHxZn6QwrQ4/jMaiucNARP7MUoTEhd5wEN7wNMyafsYfkY960/dJuqgF6ztZzt7jYX+Nu9o0YEOM742f5hcqQcn/k2GrU2X5+hMgAVUL3YP4JlZwst4pRM1eRlzXgsoxqCET84V2biS1d04ivJgKO5T9NNHTeIQDRDpSpUVuloY1qVMS6IFewLjL6XZuCYtCBXBcBN29EDFvy8v683JAZyz332Xr8R0yF/u09XFKnW+migeiT9gWNafIKXgDAidr0gbkF4r71OdGCUxhCwa+/IHnAYCptajzd4QUd2gj5yOccbVhtUondK3DSA6NaAHdwFjmU7XS5XouDlMS83wyTbqGlEXj9dEuY6lq/UXeUjvfmbqUc1W5qi7eKGxY2qZ1+3HucnCVlPbzgEVMxnPN/YtPe59SSay60gFD7KyZfxxavLsuhSFM4+aZ/hyW9pI1vu+k9UuVVEw9QisUORHHg5YYC75BsVXI5kkhXAF7F880cFlV+DPEt7mwM0xsAPcbyStmmJ+7sXkoI6bWF+QsveqgY4SPYD14bZ8v3PK4b5UzrQOHSEpa1NNrm7942lnkySoC5Rm6YIShnLdJ+Gdf8wb4RezqnhmZcKVc/9QXQcUga+nj5CRUb9wFVncmak2tf8aAvfqeML8pHzkrs= jobs: include: - - name: Python 3.5 - Tests - script: make test - python: "3.5" - - name: Python 3.8 - Tests - script: make test - python: "3.8" - - name: Code Quality - script: make quality - python: "3.5" \ No newline at end of file + - name: Python 3.8 - Tests + script: make test + python: '3.8' + - name: Code Quality + script: make quality + python: '3.8' diff --git a/lti_consumer/apps.py b/lti_consumer/apps.py index 197d55e978263ffb728412e0d15148d511c79146..e50a43198a6e757e6f544f9becc0bb0633d396f9 100644 --- a/lti_consumer/apps.py +++ b/lti_consumer/apps.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- """ lti_consumer Django application initialization. """ -from __future__ import absolute_import, unicode_literals from django.apps import AppConfig diff --git a/lti_consumer/lti_1p1/consumer.py b/lti_consumer/lti_1p1/consumer.py index 96fd516a85462ca1103543981516152f9d229f58..1290fc9861af67eade8626a8d43af11b44ee4e15 100644 --- a/lti_consumer/lti_1p1/consumer.py +++ b/lti_consumer/lti_1p1/consumer.py @@ -69,7 +69,7 @@ def parse_result_json(json_str): try: json_obj = json.loads(json_str) except (ValueError, TypeError) as err: - msg = "Supplied JSON string in request body could not be decoded: {}".format(json_str) + msg = f"Supplied JSON string in request body could not be decoded: {json_str!r}" log.error("[LTI] %s", msg) raise Lti1p1Error(msg) from err @@ -87,7 +87,7 @@ def parse_result_json(json_str): # '@type' must be "Result" result_type = json_obj.get("@type") if result_type != "Result": - msg = "JSON object does not contain correct @type attribute (should be 'Result', is z{})".format(result_type) + msg = f"JSON object does not contain correct @type attribute (should be 'Result', is z{result_type!r})" log.error("[LTI] %s", msg) raise Lti1p1Error(msg) @@ -304,15 +304,15 @@ class LtiConsumer1p1: # Parse headers to pass to template as part of context: oauth_signature = dict([param.strip().replace('"', '').split('=') for param in oauth_signature.split(',')]) - oauth_signature[u'oauth_nonce'] = oauth_signature.pop(u'OAuth oauth_nonce') + oauth_signature['oauth_nonce'] = oauth_signature.pop('OAuth oauth_nonce') # oauthlib encodes signature with # 'Content-Type': 'application/x-www-form-urlencoded' # so '='' becomes '%3D'. # We send form via browser, so browser will encode it again, # So we need to decode signature back: - oauth_signature[u'oauth_signature'] = urllib.parse.unquote( - oauth_signature[u'oauth_signature'] + oauth_signature['oauth_signature'] = urllib.parse.unquote( + oauth_signature['oauth_signature'] ) # Add LTI parameters to OAuth parameters for sending in form. diff --git a/lti_consumer/lti_1p1/contrib/tests/test_django.py b/lti_consumer/lti_1p1/contrib/tests/test_django.py index 6c32791e1038b219690ba06579f6ddcef8a36ab0..3925478927afcca08a5e7b82baf70960388c4413 100644 --- a/lti_consumer/lti_1p1/contrib/tests/test_django.py +++ b/lti_consumer/lti_1p1/contrib/tests/test_django.py @@ -1,10 +1,10 @@ -# -*- coding: utf-8 -*- """ Unit tests for lti_consumer.lti module """ +from unittest.mock import ANY, Mock, patch + from django.test.testcases import TestCase -from mock import Mock, patch, ANY from lti_consumer.lti_1p1.contrib.django import lti_embed diff --git a/lti_consumer/lti_1p1/oauth.py b/lti_consumer/lti_1p1/oauth.py index e77802095621c9dfc57a29ef67affcf0fb8c0d5e..c1a127f23f155d07604ef1a631008f830d9f2a98 100644 --- a/lti_consumer/lti_1p1/oauth.py +++ b/lti_consumer/lti_1p1/oauth.py @@ -52,7 +52,7 @@ def get_oauth_request_signature(key, secret, url, headers, body): # oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D" _, headers, _ = client.sign( str(url.strip()), - http_method=u'POST', + http_method='POST', body=body, headers=headers ) @@ -148,17 +148,17 @@ def log_authorization_header(request, client_key, client_secret): log.debug("[LTI] oauth_body_hash = %s", oauth_body_hash) client = oauth1.Client(client_key, client_secret) params = client.get_oauth_params(request) - params.append((u'oauth_body_hash', oauth_body_hash)) + params.append(('oauth_body_hash', oauth_body_hash)) mock_request = SignedRequest( uri=str(urllib.parse.unquote(request.url)), headers=request.headers, - body=u"", - decoded_body=u"", + body="", + decoded_body="", oauth_params=params, http_method=str(request.method), ) sig = client.get_oauth_signature(mock_request) - mock_request.oauth_params.append((u'oauth_signature', sig)) + mock_request.oauth_params.append(('oauth_signature', sig)) __, headers, _ = client._render(mock_request) # pylint: disable=protected-access log.debug( diff --git a/lti_consumer/lti_1p1/tests/test_consumer.py b/lti_consumer/lti_1p1/tests/test_consumer.py index 0e294a37a0cd21c95f7cd7e331b8b7dedafd21b5..88482b1c70f5f3710a2f6154f4ec994f0cfe3da5 100644 --- a/lti_consumer/lti_1p1/tests/test_consumer.py +++ b/lti_consumer/lti_1p1/tests/test_consumer.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- """ Unit tests for lti_consumer.lti_1p1.consumer module """ import unittest -from mock import Mock, patch +from unittest.mock import Mock, patch from lti_consumer.lti_1p1.exceptions import Lti1p1Error from lti_consumer.lti_1p1.consumer import LtiConsumer1p1, parse_result_json @@ -13,74 +12,74 @@ from lti_consumer.tests.unit.test_utils import make_request INVALID_JSON_INPUTS = [ ([ - 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.0-1.0."), + ], "score value outside the permitted range of 0.0-1.0."), ([ - u''' + ''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", "resultScore": -2}''' # score out of range - ], u"score value outside the permitted range of 0.0-1.0."), + ], "score value outside the permitted range of 0.0-1.0."), ([ - 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"), ] VALID_JSON_INPUTS = [ - (u''' + (''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", - "resultScore": 0.1}''', 0.1, u""), # no comment means we expect "" - (u''' + "resultScore": 0.1}''', 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}]''', 0.1, u""), # OK to have array of objects -- just take the first. @id is okay too - (u''' + "resultScore": 0.1}]''', 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": "ಠ益ಠ"}''', 0.1, u"ಠ益ಠ"), # unicode comment - (u''' + "comment": "ಠ益ಠ"}''', 0.1, "ಠ益ಠ"), # unicode comment + (''' {"@type": "Result", - "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result"}''', None, u""), # no score means we expect None - (u''' + "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result"}''', None, ""), # no score means we expect None + (''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", - "resultScore": 0.0}''', 0.0, u""), # test lower score boundary - (u''' + "resultScore": 0.0}''', 0.0, ""), # test lower score boundary + (''' {"@type": "Result", "@context": "http://purl.imsglobal.org/ctx/lis/v2/Result", - "resultScore": 1.0}''', 1.0, u""), # test upper score boundary + "resultScore": 1.0}''', 1.0, ""), # test upper score boundary ] GET_RESULT_RESPONSE = { diff --git a/lti_consumer/lti_1p1/tests/test_oauth.py b/lti_consumer/lti_1p1/tests/test_oauth.py index d7ef35bf061f055f869c7a53d31f8061a532355d..619dd6af2fc5c4faf9cb241b46694e91914440d9 100644 --- a/lti_consumer/lti_1p1/tests/test_oauth.py +++ b/lti_consumer/lti_1p1/tests/test_oauth.py @@ -4,7 +4,7 @@ Unit tests for lti_consumer.oauth module import unittest -from mock import Mock, patch +from unittest.mock import Mock, patch from lti_consumer.lti_1p1.exceptions import Lti1p1Error from lti_consumer.lti_1p1.oauth import (get_oauth_request_signature, @@ -13,14 +13,14 @@ from lti_consumer.lti_1p1.oauth import (get_oauth_request_signature, from lti_consumer.tests.unit.test_utils import make_request OAUTH_PARAMS = [ - (u'oauth_nonce', u'80966668944732164491378916897'), - (u'oauth_timestamp', u'1378916897'), - (u'oauth_version', u'1.0'), - (u'oauth_signature_method', u'HMAC-SHA1'), - (u'oauth_consumer_key', u'test'), - (u'oauth_signature', u'frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D'), + ('oauth_nonce', '80966668944732164491378916897'), + ('oauth_timestamp', '1378916897'), + ('oauth_version', '1.0'), + ('oauth_signature_method', 'HMAC-SHA1'), + ('oauth_consumer_key', 'test'), + ('oauth_signature', 'frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D'), ] -OAUTH_PARAMS_WITH_BODY_HASH = OAUTH_PARAMS + [(u'oauth_body_hash', u'2jmj7l5rSw0yVb/vlWAYkK/YBwk=')] +OAUTH_PARAMS_WITH_BODY_HASH = OAUTH_PARAMS + [('oauth_body_hash', '2jmj7l5rSw0yVb/vlWAYkK/YBwk=')] class TestGetOauthRequestSignature(unittest.TestCase): @@ -36,7 +36,7 @@ class TestGetOauthRequestSignature(unittest.TestCase): mock_client_sign.return_value = '', {'Authorization': ''}, '' signature = get_oauth_request_signature('test', 'secret', '', {}, '') - mock_client_sign.assert_called_with('', http_method=u'POST', body='', headers={}) + mock_client_sign.assert_called_with('', http_method='POST', body='', headers={}) self.assertEqual(signature, '') @patch('oauthlib.oauth1.Client.sign') diff --git a/lti_consumer/lti_1p3/constants.py b/lti_consumer/lti_1p3/constants.py index 4fbb5574271c913c58e6600e37dd8cc61d12bc9f..54e6781141c78d74c765e22498166acf92dd376c 100644 --- a/lti_consumer/lti_1p3/constants.py +++ b/lti_consumer/lti_1p3/constants.py @@ -35,12 +35,12 @@ LTI_1P3_ROLE_MAP = { } -LTI_1P3_ACCESS_TOKEN_REQUIRED_CLAIMS = set([ +LTI_1P3_ACCESS_TOKEN_REQUIRED_CLAIMS = { "grant_type", "client_assertion_type", "client_assertion", "scope", -]) +} LTI_1P3_ACCESS_TOKEN_SCOPES = [ diff --git a/lti_consumer/lti_1p3/extensions/rest_framework/serializers.py b/lti_consumer/lti_1p3/extensions/rest_framework/serializers.py index cc89ceb29469db05a45728d208c3c1d808a2293b..30afb794623f5709594836eda4619dee9b685377 100644 --- a/lti_consumer/lti_1p3/extensions/rest_framework/serializers.py +++ b/lti_consumer/lti_1p3/extensions/rest_framework/serializers.py @@ -32,7 +32,7 @@ class UsageKeyField(serializers.Field): try: return UsageKey.from_string(data) except InvalidKeyError as err: - raise serializers.ValidationError("Invalid usage key: {}".format(data)) from err + raise serializers.ValidationError(f"Invalid usage key: {data!r}") from err class LtiAgsLineItemSerializer(serializers.ModelSerializer): diff --git a/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_authentication.py b/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_authentication.py index 3530115218c149ed405a41b83e4590bedce0cf60..97b4ac65ee5a7e8567a45dedd3c259d469f4b69c 100644 --- a/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_authentication.py +++ b/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_authentication.py @@ -1,19 +1,17 @@ """ Unit tests for LTI 1.3 consumer implementation """ -from __future__ import absolute_import, unicode_literals -import ddt -from mock import MagicMock, patch +from unittest.mock import MagicMock, patch +import ddt from Cryptodome.PublicKey import RSA from django.test.testcases import TestCase from rest_framework import exceptions -from lti_consumer.models import LtiConfiguration from lti_consumer.lti_1p3.consumer import LtiConsumer1p3 from lti_consumer.lti_1p3.extensions.rest_framework.authentication import Lti1p3ApiAuthentication - +from lti_consumer.models import LtiConfiguration # Variables required for testing and verification ISS = "http://test-platform.example/" @@ -79,7 +77,7 @@ class TestLtiAuthentication(TestCase): expiration=3600 ) mock_request.headers = { - "Authorization": "Bearer {}".format(token), + "Authorization": f"Bearer {token}", } # Set the lti config id in the "url" diff --git a/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_permissions.py b/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_permissions.py index be5d50041be8730b658cc09e1fad4bd6b381ab19..2c749c9fe3c72101efb7ad2e3d7a9c30187070b6 100644 --- a/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_permissions.py +++ b/lti_consumer/lti_1p3/tests/extensions/rest_framework/test_permissions.py @@ -1,18 +1,16 @@ """ Unit tests for LTI 1.3 consumer implementation """ -from __future__ import absolute_import, unicode_literals -import ddt -from mock import MagicMock +from unittest.mock import MagicMock +import ddt from Cryptodome.PublicKey import RSA from django.test.testcases import TestCase -from lti_consumer.models import LtiConfiguration from lti_consumer.lti_1p3.consumer import LtiConsumer1p3 from lti_consumer.lti_1p3.extensions.rest_framework.permissions import LtiAgsPermissions - +from lti_consumer.models import LtiConfiguration # Variables required for testing and verification ISS = "http://test-platform.example/" @@ -96,7 +94,7 @@ class TestLtiAuthentication(TestCase): # Make token and include it in the mock request token = self._make_token(token_scopes) self.mock_request.headers = { - "Authorization": "Bearer {}".format(token) + "Authorization": f"Bearer {token}" } # Test list view @@ -124,7 +122,7 @@ class TestLtiAuthentication(TestCase): # Make token and include it in the mock request token = self._make_token([]) self.mock_request.headers = { - "Authorization": "Bearer {}".format(token) + "Authorization": f"Bearer {token}" } # Test list view @@ -163,7 +161,7 @@ class TestLtiAuthentication(TestCase): # Make token and include it in the mock request token = self._make_token(token_scopes) self.mock_request.headers = { - "Authorization": "Bearer {}".format(token) + "Authorization": f"Bearer {token}" } for action in ['create', 'update', 'partial_update', 'delete']: @@ -184,7 +182,7 @@ class TestLtiAuthentication(TestCase): # Make token and include it in the mock request token = self._make_token([]) self.mock_request.headers = { - "Authorization": "Bearer {}".format(token) + "Authorization": f"Bearer {token}" } # Test list view @@ -210,7 +208,7 @@ class TestLtiAuthentication(TestCase): # Make token and include it in the mock request token = self._make_token(token_scopes) self.mock_request.headers = { - "Authorization": "Bearer {}".format(token) + "Authorization": f"Bearer {token}" } # Test results view @@ -237,7 +235,7 @@ class TestLtiAuthentication(TestCase): # Make token and include it in the mock request token = self._make_token(token_scopes) self.mock_request.headers = { - "Authorization": "Bearer {}".format(token) + "Authorization": f"Bearer {token}" } # Test scores view diff --git a/lti_consumer/lti_1p3/tests/test_ags.py b/lti_consumer/lti_1p3/tests/test_ags.py index 94f4cd30f794fe294f5939df81e7de11e158f5f8..483162bec63703e73cbb929ac6e388ba208afe10 100644 --- a/lti_consumer/lti_1p3/tests/test_ags.py +++ b/lti_consumer/lti_1p3/tests/test_ags.py @@ -1,7 +1,6 @@ """ Unit tests for LTI 1.3 consumer implementation """ -from __future__ import absolute_import, unicode_literals from django.test.testcases import TestCase diff --git a/lti_consumer/lti_1p3/tests/test_consumer.py b/lti_consumer/lti_1p3/tests/test_consumer.py index 65e795627827d30409b4f069446769d0daec94fe..e748c30e42f3d89baf36a6a3f1a917c445b435fa 100644 --- a/lti_consumer/lti_1p3/tests/test_consumer.py +++ b/lti_consumer/lti_1p3/tests/test_consumer.py @@ -1,24 +1,21 @@ """ Unit tests for LTI 1.3 consumer implementation """ -from __future__ import absolute_import, unicode_literals import json -from urllib.parse import urlparse, parse_qs -import ddt - -from mock import patch -from django.test.testcases import TestCase +from unittest.mock import patch +from urllib.parse import parse_qs, urlparse +import ddt from Cryptodome.PublicKey import RSA +from django.test.testcases import TestCase from jwkest.jwk import load_jwks from jwkest.jws import JWS -from lti_consumer.lti_1p3.constants import LTI_1P3_CONTEXT_TYPE -from lti_consumer.lti_1p3.consumer import LtiConsumer1p3, LtiAdvantageConsumer -from lti_consumer.lti_1p3.ags import LtiAgs from lti_consumer.lti_1p3 import exceptions - +from lti_consumer.lti_1p3.ags import LtiAgs +from lti_consumer.lti_1p3.constants import LTI_1P3_CONTEXT_TYPE +from lti_consumer.lti_1p3.consumer import LtiAdvantageConsumer, LtiConsumer1p3 # Variables required for testing and verification ISS = "http://test-platform.example/" diff --git a/lti_consumer/lti_1p3/tests/test_key_handlers.py b/lti_consumer/lti_1p3/tests/test_key_handlers.py index cde6127868768862601266c30876fb3cb9bd84b7..ab7a7734e299f57bd9b170a5a76ad87c6525938a 100644 --- a/lti_consumer/lti_1p3/tests/test_key_handlers.py +++ b/lti_consumer/lti_1p3/tests/test_key_handlers.py @@ -1,20 +1,19 @@ """ Unit tests for LTI 1.3 consumer implementation """ -from __future__ import absolute_import, unicode_literals import json -import ddt - -from mock import patch -from django.test.testcases import TestCase +from unittest.mock import patch +import ddt from Cryptodome.PublicKey import RSA +from django.test.testcases import TestCase from jwkest.jwk import RSAKey, load_jwks from jwkest.jws import JWS -from lti_consumer.lti_1p3.key_handlers import PlatformKeyHandler, ToolKeyHandler from lti_consumer.lti_1p3 import exceptions +from lti_consumer.lti_1p3.key_handlers import PlatformKeyHandler, ToolKeyHandler + from .utils import create_jwt diff --git a/lti_consumer/lti_xblock.py b/lti_consumer/lti_xblock.py index 8bb24545c1b56bdea600ce84f8e421a480c643fb..523a1a859cfad4abe4af6e27319c1659e4bcb018 100644 --- a/lti_consumer/lti_xblock.py +++ b/lti_consumer/lti_xblock.py @@ -99,9 +99,9 @@ DOCS_ANCHOR_TAG_OPEN = ( ) RESULT_SERVICE_SUFFIX_PARSER = re.compile(r"^user/(?P<anon_id>\w+)", re.UNICODE) ROLE_MAP = { - 'student': u'Student', - 'staff': u'Administrator', - 'instructor': u'Instructor', + 'student': 'Student', + 'staff': 'Administrator', + 'instructor': 'Instructor', } @@ -624,7 +624,7 @@ class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): """ Get system user role and convert it to LTI role. """ - return ROLE_MAP.get(self.runtime.get_user_role(), u'Student') + return ROLE_MAP.get(self.runtime.get_user_role(), 'Student') @property def course(self): @@ -716,7 +716,7 @@ class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): makes resource_link_id to be unique among courses inside same system. """ return str(urllib.parse.quote( - "{}-{}".format(self.runtime.hostname, self.location.html_id()) # pylint: disable=no-member + f"{self.runtime.hostname}-{self.location.html_id()}" # pylint: disable=no-member )) @property @@ -1193,7 +1193,7 @@ class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): args.append(request.body) response_body = getattr( self, - "_result_service_{}".format(request.method.lower()) + f"_result_service_{request.method.lower()}" )(*args) except (AttributeError, LtiError): return Response(status=404) @@ -1286,7 +1286,7 @@ class LtiConsumerXBlock(StudioEditableXBlockMixin, XBlock): """ self.set_user_module_score(user, None, None) - def set_user_module_score(self, user, score, max_score, comment=u''): + def set_user_module_score(self, user, score, max_score, comment=''): """ Sets the module user state, including grades and comments, and also scoring in db's courseware_studentmodule diff --git a/lti_consumer/models.py b/lti_consumer/models.py index 17daab6be295652790604b0a077146c0008772e7..bd162fafc735166bd7bd34a388accab1f2557d13 100644 --- a/lti_consumer/models.py +++ b/lti_consumer/models.py @@ -307,7 +307,7 @@ class LtiConfiguration(models.Model): return self._get_lti_1p1_consumer() def __str__(self): - return "[{}] {} - {}".format(self.config_store, self.version, self.location) + return f"[{self.config_store}] {self.version} - {self.location}" class Meta: app_label = 'lti_consumer' diff --git a/lti_consumer/outcomes.py b/lti_consumer/outcomes.py index a96b8ff9b16330352bee07f024dd635f85be8542..d715ff245b2a6529dcd2d5a62a1da1f0ae580bb2 100644 --- a/lti_consumer/outcomes.py +++ b/lti_consumer/outcomes.py @@ -194,13 +194,13 @@ class OutcomeService: values = { 'imsx_codeMajor': 'success', - 'imsx_description': 'Score for {sourced_id} is now {score}'.format(sourced_id=sourced_id, score=score), + 'imsx_description': f'Score for {sourced_id} is now {score}', 'imsx_messageIdentifier': escape(imsx_message_identifier), 'response': '<replaceResultResponse/>' } - log.debug(u"[LTI]: Grade is saved.") + log.debug("[LTI]: Grade is saved.") return response_xml_template.format(**values) unsupported_values['imsx_messageIdentifier'] = escape(imsx_message_identifier) - log.debug(u"[LTI]: Incorrect action.") + log.debug("[LTI]: Incorrect action.") return response_xml_template.format(**unsupported_values) diff --git a/lti_consumer/plugin/urls.py b/lti_consumer/plugin/urls.py index 1cf1d7f563db419ed0c5ed3dc31ee688370cff18..2f68bd5a718490fe6d4b7f24aae1ffb0ab3b56d7 100644 --- a/lti_consumer/plugin/urls.py +++ b/lti_consumer/plugin/urls.py @@ -2,7 +2,6 @@ URL mappings for LTI Consumer plugin. """ -from __future__ import absolute_import from django.conf import settings from django.conf.urls import url, include @@ -26,7 +25,7 @@ router.register(r'lti-ags', LtiAgsLineItemViewset, basename='lti-ags-view') app_name = 'lti_consumer' urlpatterns = [ url( - 'lti_consumer/v1/public_keysets/{}$'.format(settings.USAGE_ID_PATTERN), + f'lti_consumer/v1/public_keysets/{settings.USAGE_ID_PATTERN}$', public_keyset_endpoint, name='lti_consumer.public_keyset_endpoint' ), @@ -36,7 +35,7 @@ urlpatterns = [ name='lti_consumer.launch_gate' ), url( - 'lti_consumer/v1/token/{}$'.format(settings.USAGE_ID_PATTERN), + f'lti_consumer/v1/token/{settings.USAGE_ID_PATTERN}$', access_token_endpoint, name='lti_consumer.access_token' ), diff --git a/lti_consumer/tests/unit/plugin/test_views.py b/lti_consumer/tests/unit/plugin/test_views.py index f83e1ec29ba9c27d3826c4fe03e46d6df4933803..be6030247d481f1fe307161c20622d3e73734de3 100644 --- a/lti_consumer/tests/unit/plugin/test_views.py +++ b/lti_consumer/tests/unit/plugin/test_views.py @@ -2,7 +2,7 @@ Tests for LTI 1.3 endpoint views. """ import json -from mock import patch +from unittest.mock import patch from django.http import HttpResponse from django.test.testcases import TestCase @@ -19,7 +19,7 @@ class TestLti1p3KeysetEndpoint(TestCase): super().setUp() self.location = 'block-v1:course+test+2020+type@problem+block@test' - self.url = '/lti_consumer/v1/public_keysets/{}'.format(self.location) + self.url = f'/lti_consumer/v1/public_keysets/{self.location}' # Set up LTI Configuration self.lti_config = LtiConfiguration.objects.create( @@ -116,7 +116,7 @@ class TestLti1p3AccessTokenEndpoint(TestCase): super().setUp() self.location = 'block-v1:course+test+2020+type@problem+block@test' - self.url = '/lti_consumer/v1/token/{}'.format(self.location) + self.url = f'/lti_consumer/v1/token/{self.location}' # Patch settings calls to LMS method xblock_handler_patcher = patch( diff --git a/lti_consumer/tests/unit/plugin/test_views_lti_ags.py b/lti_consumer/tests/unit/plugin/test_views_lti_ags.py index cb40c291855acaaa0a892fd66d4a1a4e745f27c5..cbe3b3efe69848c0763b5ef38f54ea23dc01d853 100644 --- a/lti_consumer/tests/unit/plugin/test_views_lti_ags.py +++ b/lti_consumer/tests/unit/plugin/test_views_lti_ags.py @@ -3,7 +3,7 @@ Tests for LTI Advantage Assignments and Grades Service views. """ import json from datetime import timedelta -from mock import patch, PropertyMock, Mock +from unittest.mock import patch, PropertyMock, Mock from Cryptodome.PublicKey import RSA import ddt @@ -90,7 +90,7 @@ class LtiAgsLineItemViewSetTestCase(APITransactionTestCase): }) # pylint: disable=no-member self.client.credentials( - HTTP_AUTHORIZATION="Bearer {}".format(token) + HTTP_AUTHORIZATION=f"Bearer {token}" ) diff --git a/lti_consumer/tests/unit/test_api.py b/lti_consumer/tests/unit/test_api.py index e0b92e28a4758d981842e46da402a3b4c1eaae6f..888d229e04e6def90e1c685c6110839d01aacb9f 100644 --- a/lti_consumer/tests/unit/test_api.py +++ b/lti_consumer/tests/unit/test_api.py @@ -1,15 +1,16 @@ """ Tests for LTI API. """ +from unittest.mock import Mock, patch + from Cryptodome.PublicKey import RSA from django.test.testcases import TestCase -from mock import Mock, patch from lti_consumer.api import ( _get_or_create_local_lti_config, - get_lti_consumer, get_lti_1p3_launch_info, get_lti_1p3_launch_start_url, + get_lti_consumer ) from lti_consumer.lti_xblock import LtiConsumerXBlock from lti_consumer.models import LtiConfiguration diff --git a/lti_consumer/tests/unit/test_lti_xblock.py b/lti_consumer/tests/unit/test_lti_xblock.py index bfbac794de115b639842ac5af40df6d98d8bce09..9fb1358f5c553ab3f50da6494acc85c4541da8c0 100644 --- a/lti_consumer/tests/unit/test_lti_xblock.py +++ b/lti_consumer/tests/unit/test_lti_xblock.py @@ -2,25 +2,23 @@ Unit tests for LtiConsumerXBlock """ -from datetime import timedelta import json import urllib.parse +from datetime import timedelta +from unittest.mock import Mock, NonCallableMock, PropertyMock, patch import ddt from Cryptodome.PublicKey import RSA from django.test.testcases import TestCase from django.utils import timezone from jwkest.jwk import RSAKey -from mock import Mock, PropertyMock, NonCallableMock, patch from lti_consumer.api import get_lti_1p3_launch_info from lti_consumer.exceptions import LtiError +from lti_consumer.lti_1p3.tests.utils import create_jwt from lti_consumer.lti_xblock import LtiConsumerXBlock, parse_handler_suffix from lti_consumer.tests.unit import test_utils -from lti_consumer.tests.unit.test_utils import (FAKE_USER_ID, make_request, - make_xblock) -from lti_consumer.lti_1p3.tests.utils import create_jwt - +from lti_consumer.tests.unit.test_utils import FAKE_USER_ID, make_request, make_xblock HTML_PROBLEM_PROGRESS = '<div class="problem-progress">' HTML_ERROR_MESSAGE = '<h3 class="error_message">' @@ -164,7 +162,7 @@ class TestProperties(TestLtiConsumerXBlock): key = 'test' secret = 'secret' self.xblock.lti_id = provider - type(mock_course).lti_passports = PropertyMock(return_value=["{}:{}:{}".format(provider, key, secret)]) + type(mock_course).lti_passports = PropertyMock(return_value=[f"{provider}:{key}:{secret}"]) lti_provider_key, lti_provider_secret = self.xblock.lti_provider_key_secret self.assertEqual(lti_provider_key, key) @@ -179,7 +177,7 @@ class TestProperties(TestLtiConsumerXBlock): key = '1:10:test' secret = 'secret' self.xblock.lti_id = provider - type(mock_course).lti_passports = PropertyMock(return_value=["{}:{}:{}".format(provider, key, secret)]) + type(mock_course).lti_passports = PropertyMock(return_value=[f"{provider}:{key}:{secret}"]) lti_provider_key, lti_provider_secret = self.xblock.lti_provider_key_secret self.assertEqual(lti_provider_key, key) @@ -194,7 +192,7 @@ class TestProperties(TestLtiConsumerXBlock): key = 'test' secret = 'secret' self.xblock.lti_id = 'wrong_provider' - type(mock_course).lti_passports = PropertyMock(return_value=["{}:{}:{}".format(provider, key, secret)]) + type(mock_course).lti_passports = PropertyMock(return_value=[f"{provider}:{key}:{secret}"]) lti_provider_key, lti_provider_secret = self.xblock.lti_provider_key_secret self.assertEqual(lti_provider_key, '') @@ -209,7 +207,7 @@ class TestProperties(TestLtiConsumerXBlock): key = 'test' secret = 'secret' self.xblock.lti_id = provider - type(mock_course).lti_passports = PropertyMock(return_value=["{}{}{}".format(provider, key, secret)]) + type(mock_course).lti_passports = PropertyMock(return_value=[f"{provider}{key}{secret}"]) with self.assertRaises(LtiError): _, _ = self.xblock.lti_provider_key_secret @@ -242,7 +240,7 @@ class TestProperties(TestLtiConsumerXBlock): """ self.assertEqual( self.xblock.resource_link_id, - "{}-{}".format(self.xblock.runtime.hostname, self.xblock.location.html_id()) + f"{self.xblock.runtime.hostname}-{self.xblock.location.html_id()}" ) @patch('lti_consumer.lti_xblock.LtiConsumerXBlock.context_id') @@ -255,14 +253,14 @@ class TestProperties(TestLtiConsumerXBlock): mock_resource_link_id.__get__ = Mock(return_value='resource_link_id') mock_context_id.__get__ = Mock(return_value='context_id') - self.assertEqual(self.xblock.lis_result_sourcedid, "context_id:resource_link_id:{}".format(FAKE_USER_ID)) + self.assertEqual(self.xblock.lis_result_sourcedid, f"context_id:resource_link_id:{FAKE_USER_ID}") def test_outcome_service_url(self): """ Test `outcome_service_url` calls `runtime.handler_url` with thirdparty kwarg """ handler_url = 'http://localhost:8005/outcome_service_handler' - self.xblock.runtime.handler_url = Mock(return_value="{}/?".format(handler_url)) + self.xblock.runtime.handler_url = Mock(return_value=f"{handler_url}/?") url = self.xblock.outcome_service_url self.xblock.runtime.handler_url.assert_called_with(self.xblock, 'outcome_service_handler', thirdparty=True) @@ -273,7 +271,7 @@ class TestProperties(TestLtiConsumerXBlock): Test `result_service_url` calls `runtime.handler_url` with thirdparty kwarg """ handler_url = 'http://localhost:8005/result_service_handler' - self.xblock.runtime.handler_url = Mock(return_value="{}/?".format(handler_url)) + self.xblock.runtime.handler_url = Mock(return_value=f"{handler_url}/?") url = self.xblock.result_service_url self.xblock.runtime.handler_url.assert_called_with(self.xblock, 'result_service_handler', thirdparty=True) @@ -291,12 +289,12 @@ class TestProperties(TestLtiConsumerXBlock): self.xblock.custom_parameters = ['param_1=true', 'param_2 = false', 'lti_version=1.1'] expected_params = { - u'custom_component_display_name': self.xblock.display_name, - u'custom_component_due_date': now.strftime('%Y-%m-%d %H:%M:%S'), - u'custom_component_graceperiod': str(one_day.total_seconds()), - u'custom_param_1': u'true', - u'custom_param_2': u'false', - u'lti_version': u'1.1' + 'custom_component_display_name': self.xblock.display_name, + 'custom_component_due_date': now.strftime('%Y-%m-%d %H:%M:%S'), + 'custom_component_graceperiod': str(one_day.total_seconds()), + 'custom_param_1': 'true', + 'custom_param_2': 'false', + 'lti_version': '1.1' } params = self.xblock.prefixed_custom_parameters @@ -450,7 +448,7 @@ class TestGetLti1p1Consumer(TestLtiConsumerXBlock): secret = 'secret' self.xblock.lti_id = provider self.xblock.location = 'block-v1:course+test+2020+type@problem+block@test' - type(mock_course).lti_passports = PropertyMock(return_value=["{}:{}:{}".format(provider, key, secret)]) + type(mock_course).lti_passports = PropertyMock(return_value=[f"{provider}:{key}:{secret}"]) with patch('lti_consumer.models.LtiConfiguration.block', return_value=self.xblock): self.xblock._get_lti_consumer() # pylint: disable=protected-access @@ -614,7 +612,7 @@ class TestLtiLaunchHandler(TestLtiConsumerXBlock): provider = 'lti_provider' key = 'test' secret = 'secret' - type(mock_course).lti_passports = PropertyMock(return_value=["{}:{}:{}".format(provider, key, secret)]) + type(mock_course).lti_passports = PropertyMock(return_value=[f"{provider}:{key}:{secret}"]) request = make_request('', 'GET') response = self.xblock.lti_launch_handler(request) @@ -888,7 +886,7 @@ class TestResultServiceHandler(TestLtiConsumerXBlock): Test `get_outcome_service_url` with default parameter """ handler_url = 'http://localhost:8005/outcome_service_handler' - self.xblock.runtime.handler_url = Mock(return_value="{}/?".format(handler_url)) + self.xblock.runtime.handler_url = Mock(return_value=f"{handler_url}/?") url = self.xblock.get_outcome_service_url() self.xblock.runtime.handler_url.assert_called_with(self.xblock, 'outcome_service_handler', thirdparty=True) @@ -899,7 +897,7 @@ class TestResultServiceHandler(TestLtiConsumerXBlock): Test `get_outcome_service_url` calls service name grade_handler """ handler_url = 'http://localhost:8005/outcome_service_handler' - self.xblock.runtime.handler_url = Mock(return_value="{}/?".format(handler_url)) + self.xblock.runtime.handler_url = Mock(return_value=f"{handler_url}/?") url = self.xblock.get_outcome_service_url('grade_handler') self.xblock.runtime.handler_url.assert_called_with(self.xblock, 'outcome_service_handler', thirdparty=True) @@ -910,7 +908,7 @@ class TestResultServiceHandler(TestLtiConsumerXBlock): Test `get_outcome_service_url` calls with service name lti_2_0_result_rest_handler """ handler_url = 'http://localhost:8005/result_service_handler' - self.xblock.runtime.handler_url = Mock(return_value="{}/?".format(handler_url)) + self.xblock.runtime.handler_url = Mock(return_value=f"{handler_url}/?") url = self.xblock.get_outcome_service_url('lti_2_0_result_rest_handler') self.xblock.runtime.handler_url.assert_called_with(self.xblock, 'result_service_handler', thirdparty=True) @@ -1051,7 +1049,7 @@ class TestParseSuffix(TestLtiConsumerXBlock): Test `parse_handler_suffix` when `suffix` parameter can be parsed :return: """ - parsed = parse_handler_suffix("user/{}".format(FAKE_USER_ID)) + parsed = parse_handler_suffix(f"user/{FAKE_USER_ID}") self.assertEqual(parsed, FAKE_USER_ID) @@ -1088,21 +1086,21 @@ class TestGetContext(TestLtiConsumerXBlock): """ Test that allowed tags are not escaped in context['comment'] """ - comment = u'<{0}>This is a comment</{0}>!'.format(tag) + comment = '<{0}>This is a comment</{0}>!'.format(tag) self.xblock.set_user_module_score(Mock(), 0.92, 1.0, comment) context = self.xblock._get_context_for_template() # pylint: disable=protected-access - self.assertIn('<{}>'.format(tag), context['comment']) + self.assertIn(f'<{tag}>', context['comment']) def test_comment_retains_image_src(self): """ Test that image tag has src and other attrs are sanitized """ - comment = u'<img src="example.com/image.jpeg" onerror="myFunction()">' + comment = '<img src="example.com/image.jpeg" onerror="myFunction()">' self.xblock.set_user_module_score(Mock(), 0.92, 1.0, comment) context = self.xblock._get_context_for_template() # pylint: disable=protected-access - self.assertIn(u'<img src="example.com/image.jpeg">', context['comment']) + self.assertIn('<img src="example.com/image.jpeg">', context['comment']) @ddt.ddt @@ -1204,7 +1202,7 @@ class TestLtiConsumer1p3XBlock(TestCase): # Craft request sent back by LTI tool request = make_request('', 'GET') request.query_string = ( - "client_id={}&".format(client_id) + + f"client_id={client_id}&" + "redirect_uri=http://tool.example/launch&" + "state=state_test_123&" + "nonce=nonce&" + diff --git a/lti_consumer/tests/unit/test_models.py b/lti_consumer/tests/unit/test_models.py index 2375fb6b94dcc0260d6ed21b86f7880748a93b8f..1a8079107519ee075da738636a0ca3b88aabfc51 100644 --- a/lti_consumer/tests/unit/test_models.py +++ b/lti_consumer/tests/unit/test_models.py @@ -2,16 +2,16 @@ Unit tests for LTI models. """ from datetime import timedelta +from unittest.mock import patch + from Cryptodome.PublicKey import RSA -from django.utils import timezone from django.test.testcases import TestCase - +from django.utils import timezone from jwkest.jwk import RSAKey -from mock import patch from lti_consumer.lti_1p1.consumer import LtiConsumer1p1 from lti_consumer.lti_xblock import LtiConsumerXBlock -from lti_consumer.models import LtiAgsLineItem, LtiConfiguration, LtiAgsScore +from lti_consumer.models import LtiAgsLineItem, LtiAgsScore, LtiConfiguration from lti_consumer.tests.unit.test_utils import make_xblock @@ -102,7 +102,7 @@ class TestLtiConfigurationModel(TestCase): self.assertEqual( str(lti_config), - "[CONFIG_ON_XBLOCK] lti_1p3 - {}".format(dummy_location) + f"[CONFIG_ON_XBLOCK] lti_1p3 - {dummy_location}" ) def test_lti_consumer_ags_enabled(self): diff --git a/lti_consumer/tests/unit/test_outcomes.py b/lti_consumer/tests/unit/test_outcomes.py index c27672d560cecfed4e151d6495f38d0aa99204ec..9fe0337751e84e1b8a807c8438bba5e9e7a5fa21 100644 --- a/lti_consumer/tests/unit/test_outcomes.py +++ b/lti_consumer/tests/unit/test_outcomes.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Unit tests for lti_consumer.outcomes module """ @@ -7,7 +6,7 @@ import textwrap import unittest from copy import copy -from mock import Mock, PropertyMock, patch +from unittest.mock import Mock, PropertyMock, patch from lti_consumer.exceptions import LtiError from lti_consumer.outcomes import OutcomeService, parse_grade_xml_body @@ -321,10 +320,10 @@ class TestParseGradeXmlBody(unittest.TestCase): msg_id, sourced_id, score, action = parse_grade_xml_body(request_body_template) - self.assertEqual(msg_id, u'ţéšţ_message_id') - self.assertEqual(sourced_id, u'ţéšţ_sourced_id') + self.assertEqual(msg_id, 'ţéšţ_message_id') + self.assertEqual(sourced_id, 'ţéšţ_sourced_id') self.assertEqual(score, 1.0) - self.assertEqual(action, u'ţéšţ_action') + self.assertEqual(action, 'ţéšţ_action') class TestOutcomeService(TestLtiConsumerXBlock): diff --git a/lti_consumer/tests/unit/test_utils.py b/lti_consumer/tests/unit/test_utils.py index da42a607c88249342afb543b51f2c337e45114c3..f45158759c3057a10aa637c5d68475e45078a384 100644 --- a/lti_consumer/tests/unit/test_utils.py +++ b/lti_consumer/tests/unit/test_utils.py @@ -2,7 +2,7 @@ Utility functions used within unit tests """ -from mock import Mock +from unittest.mock import Mock from webob import Request from workbench.runtime import WorkbenchRuntime from xblock.fields import ScopeIds diff --git a/lti_consumer/utils.py b/lti_consumer/utils.py index bbce7853ef9e3aeb49ae0638d1fe81daa8f55f68..80fa8bf8d7bc34579627ac877e6e6bec1c26c039 100644 --- a/lti_consumer/utils.py +++ b/lti_consumer/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Utility functions for LTI Consumer block """ diff --git a/requirements/base.txt b/requirements/base.txt index 6cbb5b593b2e5e6d5727f8ec23773ebad437efae..6a07b76538ff535d61c97ecd369a90277115a5d8 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,19 +5,19 @@ # make upgrade # appdirs==1.4.4 # via fs -bleach==3.2.1 # via -r requirements/base.in +bleach==3.2.2 # via -r requirements/base.in certifi==2020.12.5 # via requests chardet==4.0.0 # via requests django-filter==2.4.0 # via -r requirements/base.in django==2.2.17 # via -c requirements/constraints.txt, -r requirements/base.in, django-filter, edx-opaque-keys, jsonfield2 edx-opaque-keys[django]==2.1.1 # via -r requirements/base.in -fs==2.4.11 # via xblock +fs==2.4.12 # via xblock future==0.18.2 # via pyjwkest idna==2.10 # via requests jsonfield2==3.0.3 # via -c requirements/constraints.txt, -r requirements/base.in lazy==1.4 # via -r requirements/base.in lxml==4.6.2 # via -r requirements/base.in, xblock -mako==1.1.3 # via -r requirements/base.in, xblock-utils +mako==1.1.4 # via -r requirements/base.in, xblock-utils markupsafe==1.1.1 # via mako, xblock oauthlib==3.1.0 # via -r requirements/base.in packaging==20.8 # via bleach @@ -27,14 +27,13 @@ pyjwkest==1.4.2 # via -r requirements/base.in pymongo==3.11.2 # via edx-opaque-keys pyparsing==2.4.7 # via packaging python-dateutil==2.8.1 # via xblock -pytz==2020.4 # via django, fs, xblock -pyyaml==5.3.1 # via xblock +pytz==2020.5 # via django, fs, xblock +pyyaml==5.4.1 # via xblock requests==2.25.1 # via pyjwkest simplejson==3.17.2 # via xblock-utils six==1.15.0 # via bleach, edx-opaque-keys, fs, pyjwkest, python-dateutil, stevedore, xblock sqlparse==0.4.1 # via django stevedore==1.32.0 # via -c requirements/constraints.txt, edx-opaque-keys -typing==3.7.4.3 # via fs urllib3==1.26.2 # via requests web-fragments==0.3.2 # via xblock, xblock-utils webencodings==0.5.1 # via bleach diff --git a/requirements/pip_tools.txt b/requirements/pip_tools.txt index f3a39fcfab74abed3efd4ba37622e6dad825b44b..a6f6c30fd9e516961a0b2d8fa44ae6128408fd60 100644 --- a/requirements/pip_tools.txt +++ b/requirements/pip_tools.txt @@ -5,8 +5,7 @@ # make upgrade # click==7.1.2 # via pip-tools -pip-tools==5.4.0 # via -r requirements/pip_tools.in -six==1.15.0 # via pip-tools +pip-tools==5.5.0 # via -r requirements/pip_tools.in # The following packages are considered to be unsafe in a requirements file: # pip diff --git a/requirements/test.txt b/requirements/test.txt index 5ff2002fb3df380d0260fc3d7f7c0b1725caf33e..b32edd276708e90ec8886b8e3d08cb2264e2c165 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -6,33 +6,33 @@ # appdirs==1.4.4 # via -r requirements/base.txt, fs astroid==2.4.2 # via pylint, pylint-celery -bleach==3.2.1 # via -r requirements/base.txt -boto3==1.16.42 # via fs-s3fs -botocore==1.19.42 # via boto3, s3transfer +bleach==3.2.2 # via -r requirements/base.txt +boto3==1.16.57 # via fs-s3fs +botocore==1.19.57 # via boto3, s3transfer certifi==2020.12.5 # via -r requirements/base.txt, requests chardet==4.0.0 # via -r requirements/base.txt, requests click-log==0.3.2 # via edx-lint click==7.1.2 # via click-log, edx-lint coverage==5.3.1 # via coveralls -coveralls==2.2.0 # via -r requirements/test.in +coveralls==3.0.0 # via -r requirements/test.in ddt==1.4.1 # via -r requirements/test.in django-filter==2.4.0 # via -r requirements/base.txt -django-pyfs==2.2 # via -r requirements/test.in +django-pyfs==3.0 # via -r requirements/test.in djangorestframework==3.9.4 # via -c requirements/constraints.txt, -r requirements/test.in docopt==0.6.2 # via coveralls edx-lint==1.6 # via -r requirements/test.in edx-opaque-keys[django]==2.1.1 # via -r requirements/base.txt fs-s3fs==1.1.1 # via django-pyfs -fs==2.4.11 # via -r requirements/base.txt, django-pyfs, fs-s3fs, xblock +fs==2.4.12 # via -r requirements/base.txt, django-pyfs, fs-s3fs, xblock future==0.18.2 # via -r requirements/base.txt, pyjwkest idna==2.10 # via -r requirements/base.txt, requests -isort==4.3.21 # via pylint +isort==5.7.0 # via pylint jmespath==0.10.0 # via boto3, botocore jsonfield2==3.0.3 # via -c requirements/constraints.txt, -r requirements/base.txt lazy-object-proxy==1.4.3 # via astroid lazy==1.4 # via -r requirements/base.txt lxml==4.6.2 # via -r requirements/base.txt, xblock -mako==1.1.3 # via -r requirements/base.txt, xblock-utils +mako==1.1.4 # via -r requirements/base.txt, xblock-utils markupsafe==1.1.1 # via -r requirements/base.txt, mako, xblock mccabe==0.6.1 # via pylint mock==3.0.5 # via -c requirements/constraints.txt, -r requirements/test.in @@ -49,17 +49,15 @@ pylint==2.6.0 # via edx-lint, pylint-celery, pylint-django, pylint-p pymongo==3.11.2 # via -r requirements/base.txt, edx-opaque-keys pyparsing==2.4.7 # via -r requirements/base.txt, packaging python-dateutil==2.8.1 # via -r requirements/base.txt, botocore, xblock -pytz==2020.4 # via -r requirements/base.txt, django, fs, xblock -pyyaml==5.3.1 # via -r requirements/base.txt, xblock +pytz==2020.5 # via -r requirements/base.txt, django, fs, xblock +pyyaml==5.4.1 # via -r requirements/base.txt, xblock requests==2.25.1 # via -r requirements/base.txt, coveralls, pyjwkest -s3transfer==0.3.3 # via boto3 +s3transfer==0.3.4 # via boto3 simplejson==3.17.2 # via -r requirements/base.txt, xblock-utils six==1.15.0 # via -r requirements/base.txt, astroid, bleach, edx-lint, edx-opaque-keys, fs, fs-s3fs, mock, pyjwkest, python-dateutil, stevedore, xblock sqlparse==0.4.1 # via -r requirements/base.txt, django stevedore==1.32.0 # via -c requirements/constraints.txt, -r requirements/base.txt, edx-opaque-keys toml==0.10.2 # via pylint -typed-ast==1.4.1 # via astroid -typing==3.7.4.3 # via -r requirements/base.txt, fs urllib3==1.26.2 # via -r requirements/base.txt, botocore, requests web-fragments==0.3.2 # via -r requirements/base.txt, xblock, xblock-utils webencodings==0.5.1 # via -r requirements/base.txt, bleach diff --git a/requirements/tox.txt b/requirements/tox.txt index 97c27e44ff99bc0b55622e450bc73bd8ed79499d..e265effdd40a6847d100db6a762bfa9fbf1dbacb 100644 --- a/requirements/tox.txt +++ b/requirements/tox.txt @@ -7,14 +7,11 @@ appdirs==1.4.4 # via virtualenv distlib==0.3.1 # via virtualenv filelock==3.0.12 # via tox, virtualenv -importlib-metadata==2.1.1 # via pluggy, tox, virtualenv -importlib-resources==3.2.1 # via virtualenv packaging==20.8 # via tox pluggy==0.13.1 # via tox py==1.10.0 # via tox pyparsing==2.4.7 # via packaging six==1.15.0 # via tox, virtualenv toml==0.10.2 # via tox -tox==3.20.1 # via -r requirements/tox.in -virtualenv==20.2.2 # via tox -zipp==1.1.1 # via -c requirements/constraints.txt, importlib-metadata, importlib-resources +tox==3.21.2 # via -r requirements/tox.in +virtualenv==20.4.0 # via tox diff --git a/requirements/travis.txt b/requirements/travis.txt index 3d7651c8dfc1f7fb0bae5b578b9115d8639fbd16..432c01c076d652f0c792f2feccabf6d7378aee14 100644 --- a/requirements/travis.txt +++ b/requirements/travis.txt @@ -6,19 +6,19 @@ # appdirs==1.4.4 # via -r requirements/test.txt, -r requirements/tox.txt, fs, virtualenv astroid==2.4.2 # via -r requirements/test.txt, pylint, pylint-celery -bleach==3.2.1 # via -r requirements/test.txt -boto3==1.16.42 # via -r requirements/test.txt, fs-s3fs -botocore==1.19.42 # via -r requirements/test.txt, boto3, s3transfer +bleach==3.2.2 # via -r requirements/test.txt +boto3==1.16.57 # via -r requirements/test.txt, fs-s3fs +botocore==1.19.57 # via -r requirements/test.txt, boto3, s3transfer certifi==2020.12.5 # via -r requirements/test.txt, requests chardet==4.0.0 # via -r requirements/test.txt, requests click-log==0.3.2 # via -r requirements/test.txt, edx-lint click==7.1.2 # via -r requirements/test.txt, click-log, edx-lint coverage==5.3.1 # via -r requirements/test.txt, coveralls -coveralls==2.2.0 # via -r requirements/test.txt +coveralls==3.0.0 # via -r requirements/test.txt ddt==1.4.1 # via -r requirements/test.txt distlib==0.3.1 # via -r requirements/tox.txt, virtualenv django-filter==2.4.0 # via -r requirements/test.txt -django-pyfs==2.2 # via -r requirements/test.txt +django-pyfs==3.0 # via -r requirements/test.txt django==2.2.17 # via -c requirements/constraints.txt, -r requirements/test.txt, django-filter, django-pyfs, edx-opaque-keys, jsonfield2, xblock-sdk djangorestframework==3.9.4 # via -c requirements/constraints.txt, -r requirements/test.txt docopt==0.6.2 # via -r requirements/test.txt, coveralls @@ -26,18 +26,16 @@ edx-lint==1.6 # via -r requirements/test.txt edx-opaque-keys[django]==2.1.1 # via -r requirements/test.txt filelock==3.0.12 # via -r requirements/tox.txt, tox, virtualenv fs-s3fs==1.1.1 # via -r requirements/test.txt, django-pyfs -fs==2.4.11 # via -r requirements/test.txt, django-pyfs, fs-s3fs, xblock +fs==2.4.12 # via -r requirements/test.txt, django-pyfs, fs-s3fs, xblock future==0.18.2 # via -r requirements/test.txt, pyjwkest idna==2.10 # via -r requirements/test.txt, requests -importlib-metadata==2.1.1 # via -r requirements/tox.txt, pluggy, tox, virtualenv -importlib-resources==3.2.1 # via -r requirements/tox.txt, virtualenv -isort==4.3.21 # via -r requirements/test.txt, pylint +isort==5.7.0 # via -r requirements/test.txt, pylint jmespath==0.10.0 # via -r requirements/test.txt, boto3, botocore jsonfield2==3.0.3 # via -c requirements/constraints.txt, -r requirements/test.txt lazy-object-proxy==1.4.3 # via -r requirements/test.txt, astroid lazy==1.4 # via -r requirements/test.txt lxml==4.6.2 # via -r requirements/test.txt, xblock -mako==1.1.3 # via -r requirements/test.txt, xblock-utils +mako==1.1.4 # via -r requirements/test.txt, xblock-utils markupsafe==1.1.1 # via -r requirements/test.txt, mako, xblock mccabe==0.6.1 # via -r requirements/test.txt, pylint mock==3.0.5 # via -c requirements/constraints.txt, -r requirements/test.txt @@ -56,20 +54,18 @@ pylint==2.6.0 # via -r requirements/test.txt, edx-lint, pylint-celer pymongo==3.11.2 # via -r requirements/test.txt, edx-opaque-keys pyparsing==2.4.7 # via -r requirements/test.txt, -r requirements/tox.txt, packaging python-dateutil==2.8.1 # via -r requirements/test.txt, botocore, xblock -pytz==2020.4 # via -r requirements/test.txt, django, fs, xblock -pyyaml==5.3.1 # via -r requirements/test.txt, xblock +pytz==2020.5 # via -r requirements/test.txt, django, fs, xblock +pyyaml==5.4.1 # via -r requirements/test.txt, xblock requests==2.25.1 # via -r requirements/test.txt, coveralls, pyjwkest -s3transfer==0.3.3 # via -r requirements/test.txt, boto3 +s3transfer==0.3.4 # via -r requirements/test.txt, boto3 simplejson==3.17.2 # via -r requirements/test.txt, xblock-utils six==1.15.0 # via -r requirements/test.txt, -r requirements/tox.txt, astroid, bleach, edx-lint, edx-opaque-keys, fs, fs-s3fs, mock, pyjwkest, python-dateutil, stevedore, tox, virtualenv, xblock sqlparse==0.4.1 # via -r requirements/test.txt, django stevedore==1.32.0 # via -c requirements/constraints.txt, -r requirements/test.txt, edx-opaque-keys toml==0.10.2 # via -r requirements/test.txt, -r requirements/tox.txt, pylint, tox -tox==3.20.1 # via -r requirements/tox.txt -typed-ast==1.4.1 # via -r requirements/test.txt, astroid -typing==3.7.4.3 # via -r requirements/test.txt, fs +tox==3.21.2 # via -r requirements/tox.txt urllib3==1.26.2 # via -r requirements/test.txt, botocore, requests -virtualenv==20.2.2 # via -r requirements/tox.txt, tox +virtualenv==20.4.0 # via -r requirements/tox.txt, tox web-fragments==0.3.2 # via -r requirements/test.txt, xblock, xblock-utils webencodings==0.5.1 # via -r requirements/test.txt, bleach webob==1.8.6 # via -r requirements/test.txt, xblock @@ -77,7 +73,6 @@ wrapt==1.12.1 # via -r requirements/test.txt, astroid xblock-sdk==0.2.2 # via -r requirements/test.txt xblock-utils==2.1.2 # via -r requirements/test.txt xblock==1.4.0 # via -r requirements/test.txt, xblock-utils -zipp==1.1.1 # via -c requirements/constraints.txt, -r requirements/tox.txt, importlib-metadata, importlib-resources # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/setup.py b/setup.py index 822b9a869c380fc4aa685cec72c58ee2d58cc0a6..6e7e4dc23c94dac2c936cb69d32c639a569efefd 100644 --- a/setup.py +++ b/setup.py @@ -80,7 +80,6 @@ setup( 'License :: OSI Approved :: GNU Affero General Public License v3', 'Natural Language :: English', "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.8", ] ) diff --git a/test.py b/test.py index eb32b0414d31a1f1ff415be54bc7f526c47f4d52..582c72e8a534481559c025b2ce6eae392d94ff03 100644 --- a/test.py +++ b/test.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ Run tests for the LTI Consumer XBlock """ @@ -8,7 +7,7 @@ import os import sys if __name__ == '__main__': - os.environ.setdefault('DJANGO_SETTINGS_MODULE', u'test_settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_settings') try: from django.conf import settings # pylint: disable=wrong-import-position @@ -27,7 +26,7 @@ if __name__ == '__main__': ) raise - settings.INSTALLED_APPS += (u'lti_consumer',) + settings.INSTALLED_APPS += ('lti_consumer',) arguments = sys.argv[1:] options = [argument for argument in arguments if argument.startswith('-')]