refactor: Ran pyupgrade on openedx/core

Ran pyupgrade on openedx/core/{lib, tests}
This commit is contained in:
Usama Sadiq
2021-03-11 19:07:19 +05:00
parent 8de47ef51f
commit 068ac5290f
36 changed files with 169 additions and 189 deletions

View File

@@ -76,8 +76,8 @@ class BearerAuthentication(BaseAuthentication):
token = self.get_access_token(access_token)
except AuthenticationFailed as exc:
raise AuthenticationFailed({ # lint-amnesty, pylint: disable=raise-missing-from
u'error_code': OAUTH2_TOKEN_ERROR,
u'developer_message': exc.detail
'error_code': OAUTH2_TOKEN_ERROR,
'developer_message': exc.detail
})
if not token: # lint-amnesty, pylint: disable=no-else-raise

View File

@@ -16,7 +16,7 @@ class ExpandableField(Field): # lint-amnesty, pylint: disable=abstract-method
assert 'collapsed_serializer' in kwargs and 'expanded_serializer' in kwargs
self.collapsed = kwargs.pop('collapsed_serializer')
self.expanded = kwargs.pop('expanded_serializer')
super(ExpandableField, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(**kwargs)
def to_representation(self, obj): # lint-amnesty, pylint: disable=arguments-differ
"""
@@ -47,8 +47,8 @@ class AbsoluteURLField(URLField):
request = self.context.get('request', None)
assert request is not None, (
u"`%s` requires the request in the serializer context. "
u"Add `context={'request': request}` when instantiating the serializer." % self.__class__.__name__
"`%s` requires the request in the serializer context. "
"Add `context={'request': request}` when instantiating the serializer." % self.__class__.__name__
)
if value.startswith(('http:', 'https:')):

View File

@@ -22,11 +22,11 @@ class PutAsCreateMixin(CreateModelMixin):
# First, try to update the existing instance
try:
try:
return super(PutAsCreateMixin, self).update(request, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
return super().update(request, *args, **kwargs)
except Http404:
# If no instance exists yet, create it.
# This is backwards-compatible with the behavior of DRF v2.
return super(PutAsCreateMixin, self).create(request, *args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
return super().create(request, *args, **kwargs)
# Backwards compatibility with DRF v2 behavior, which would catch model-level
# validation errors and return a 400

View File

@@ -71,11 +71,11 @@ class TypedFileUploadParser(FileUploadParser):
ext = '.{}'.format(fileparts[1])
if ext.lower() not in self.file_extensions[media_type]:
errmsg = (
u'File extension does not match requested Content-type. '
u'Filename: "{filename}", Content-type: "{contenttype}"'
'File extension does not match requested Content-type. '
'Filename: "{filename}", Content-type: "{contenttype}"'
)
raise ParseError(errmsg.format(filename=filename, contenttype=media_type))
return super(TypedFileUploadParser, self).parse(stream, media_type, parser_context) # lint-amnesty, pylint: disable=super-with-arguments
return super().parse(stream, media_type, parser_context)
class MergePatchParser(JSONParser):

View File

@@ -6,7 +6,6 @@ Serializers to be used in APIs.
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey, UsageKey
from rest_framework import serializers
import six
class CollapsedReferenceSerializer(serializers.HyperlinkedModelSerializer):
@@ -32,14 +31,14 @@ class CollapsedReferenceSerializer(serializers.HyperlinkedModelSerializer):
self.Meta.model = model_class
super(CollapsedReferenceSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(*args, **kwargs)
self.fields[id_source] = serializers.CharField(read_only=True)
self.fields['url'].view_name = view_name
self.fields['url'].lookup_field = lookup_field
self.fields['url'].lookup_url_kwarg = lookup_field
class Meta(object):
class Meta:
fields = ("url",)
@@ -48,14 +47,14 @@ class CourseKeyField(serializers.Field):
def to_representation(self, data): # lint-amnesty, pylint: disable=arguments-differ
"""Convert a course key to unicode. """
return six.text_type(data)
return str(data)
def to_internal_value(self, data):
"""Convert unicode to a course key. """
try:
return CourseKey.from_string(data)
except InvalidKeyError as ex:
raise serializers.ValidationError(u"Invalid course key: {msg}".format(msg=ex.msg)) # lint-amnesty, pylint: disable=no-member
raise serializers.ValidationError(f"Invalid course key: {ex.msg}") # lint-amnesty, pylint: disable=no-member
class UsageKeyField(serializers.Field):
@@ -63,11 +62,11 @@ class UsageKeyField(serializers.Field):
def to_representation(self, data): # lint-amnesty, pylint: disable=arguments-differ
"""Convert a usage key to unicode. """
return six.text_type(data)
return str(data)
def to_internal_value(self, data):
"""Convert unicode to a usage key. """
try:
return UsageKey.from_string(data)
except InvalidKeyError as ex:
raise serializers.ValidationError(u"Invalid usage key: {msg}".format(msg=ex.msg)) # lint-amnesty, pylint: disable=no-member
raise serializers.ValidationError(f"Invalid usage key: {ex.msg}") # lint-amnesty, pylint: disable=no-member

View File

@@ -5,7 +5,6 @@ Helpers for API tests.
import base64
import json
import re
import six
from django.test import TestCase
from django.test.utils import override_settings
@@ -50,7 +49,7 @@ class ApiTestCase(TestCase):
allow_header = resp.get("Allow")
assert allow_header is not None
allowed_methods = re.split('[^A-Z]+', allow_header)
six.assertCountEqual(self, allowed_methods, expected_methods)
self.assertCountEqual(allowed_methods, expected_methods)
def assertSelfReferential(self, obj):
"""Assert that accessing the "url" entry in the given object returns the same object"""
@@ -86,6 +85,6 @@ class ApiTestCase(TestCase):
# Django rest framework interprets basic auth headers
# as an attempt to authenticate with the API.
# We don't want this for views available to anonymous users.
basic_auth_header = "Basic " + base64.b64encode('username:password'.encode('utf-8')).decode('utf-8')
basic_auth_header = "Basic " + base64.b64encode(b'username:password').decode('utf-8')
response = getattr(self.client, method)(uri, HTTP_AUTHORIZATION=basic_auth_header)
assert response.status_code != 403

View File

@@ -11,7 +11,7 @@ import jwt
JWT_AUTH = 'JWT_AUTH'
class JwtMixin(object):
class JwtMixin:
""" Mixin with JWT-related helper functions. """
JWT_SECRET_KEY = getattr(settings, JWT_AUTH)['JWT_SECRET_KEY'] if hasattr(settings, JWT_AUTH) else ''

View File

@@ -62,7 +62,7 @@ class OAuth2AllowInActiveUsersTests(TestCase): # lint-amnesty, pylint: disable=
OAUTH2_BASE_TESTING_URL = '/oauth2-inactive-test/'
def setUp(self):
super(OAuth2AllowInActiveUsersTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.dot_adapter = adapters.DOTAdapter()
self.csrf_client = APIClient(enforce_csrf_checks=True)
self.username = 'john'
@@ -96,7 +96,7 @@ class OAuth2AllowInActiveUsersTests(TestCase): # lint-amnesty, pylint: disable=
def _create_authorization_header(self, token=None):
if token is None:
token = self.dot_access_token.token
return "Bearer {0}".format(token)
return f"Bearer {token}"
def get_with_bearer_token(self, target_url, params=None, token=None):
"""
@@ -224,7 +224,7 @@ class BearerAuthenticationTests(OAuth2AllowInActiveUsersTests): # lint-amnesty,
OAUTH2_BASE_TESTING_URL = '/oauth2-test/'
def setUp(self):
super(BearerAuthenticationTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
# Since this is testing back to previous version, user should be set to true
self.user.is_active = True
self.user.save()

View File

@@ -5,7 +5,6 @@ Test Custom Exceptions
import ddt
from django.test import TestCase
from rest_framework import exceptions as drf_exceptions
import six
@ddt.ddt
@@ -16,8 +15,8 @@ class TestDictExceptionsAllowDictDetails(TestCase):
def test_drf_errors_are_not_coerced_to_strings(self):
# Demonstrate that dictionaries in exceptions are not coerced to strings.
exc = drf_exceptions.AuthenticationFailed({u'error_code': -1})
assert not isinstance(exc.detail, six.string_types)
exc = drf_exceptions.AuthenticationFailed({'error_code': -1})
assert not isinstance(exc.detail, str)
@ddt.data(
drf_exceptions.AuthenticationFailed,
@@ -27,14 +26,14 @@ class TestDictExceptionsAllowDictDetails(TestCase):
drf_exceptions.PermissionDenied,
)
def test_exceptions_allows_dict_detail(self, exception_class):
exc = exception_class({u'error_code': -1})
assert exc.detail == {u'error_code': u'-1'}
exc = exception_class({'error_code': -1})
assert exc.detail == {'error_code': '-1'}
def test_method_not_allowed_allows_dict_detail(self):
exc = drf_exceptions.MethodNotAllowed(u'POST', {u'error_code': -1})
assert exc.detail == {u'error_code': u'-1'}
exc = drf_exceptions.MethodNotAllowed('POST', {'error_code': -1})
assert exc.detail == {'error_code': '-1'}
def test_not_acceptable_allows_dict_detail(self):
exc = drf_exceptions.NotAcceptable({u'error_code': -1}, available_renderers=['application/json'])
assert exc.detail == {u'error_code': u'-1'}
exc = drf_exceptions.NotAcceptable({'error_code': -1}, available_renderers=['application/json'])
assert exc.detail == {'error_code': '-1'}
assert exc.available_renderers == ['application/json']

View File

@@ -6,7 +6,7 @@ from django.test import TestCase
from openedx.core.lib.api.fields import AbsoluteURLField
class MockRequest(object):
class MockRequest:
""" Mock request object. """
ROOT = 'http://example.com'
@@ -20,7 +20,7 @@ class AbsoluteURLFieldTests(TestCase):
""" Tests for the AbsoluteURLField. """
def setUp(self):
super(AbsoluteURLFieldTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.field = AbsoluteURLField()
self.field._context = {'request': MockRequest()} # pylint:disable=protected-access

View File

@@ -18,7 +18,7 @@ class TestTypedFileUploadParser(APITestCase):
"""
def setUp(self):
super(TestTypedFileUploadParser, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.parser = parsers.TypedFileUploadParser()
self.request_factory = APIRequestFactory()
upload_media_types = {'image/png', 'image/jpeg', 'application/octet-stream'}

View File

@@ -12,7 +12,7 @@ from common.djangoapps.student.tests.factories import UserFactory
from openedx.core.lib.api.permissions import IsCourseStaffInstructor, IsMasterCourseStaffInstructor, IsStaffOrOwner
class TestObject(object):
class TestObject:
""" Fake class for object permission tests. """
def __init__(self, user=None, course_id=None):
self.user = user
@@ -22,7 +22,7 @@ class TestObject(object):
class TestCcxObject(TestObject):
""" Fake class for object permission for CCX Courses """
def __init__(self, user=None, course_id=None):
super(TestCcxObject, self).__init__(user, course_id) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(user, course_id)
self.coach = user
@@ -30,7 +30,7 @@ class IsCourseStaffInstructorTests(TestCase):
""" Test for IsCourseStaffInstructor permission class. """
def setUp(self):
super(IsCourseStaffInstructorTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.permission = IsCourseStaffInstructor()
self.coach = UserFactory()
self.user = UserFactory()
@@ -63,11 +63,11 @@ class IsMasterCourseStaffInstructorTests(TestCase):
""" Test for IsMasterCourseStaffInstructorTests permission class. """
def setUp(self):
super(IsMasterCourseStaffInstructorTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.permission = IsMasterCourseStaffInstructor()
master_course_id = 'edx/test123/run'
self.user = UserFactory()
self.get_request = RequestFactory().get('/?master_course_id={}'.format(master_course_id))
self.get_request = RequestFactory().get(f'/?master_course_id={master_course_id}')
self.get_request.user = self.user
self.post_request = RequestFactory().post('/', data={'master_course_id': master_course_id})
self.post_request.user = self.user
@@ -108,7 +108,7 @@ class IsStaffOrOwnerTests(TestCase):
""" Tests for IsStaffOrOwner permission class. """
def setUp(self):
super(IsStaffOrOwnerTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.permission = IsStaffOrOwner()
self.request = RequestFactory().get('/')
self.obj = TestObject()
@@ -148,7 +148,7 @@ class IsStaffOrOwnerTests(TestCase):
def test_has_permission_as_owner_with_get(self):
""" Owners always have permission to make GET actions. """
user = UserFactory()
request = RequestFactory().get('/?username={}'.format(user.username))
request = RequestFactory().get(f'/?username={user.username}')
request.user = user
assert self.permission.has_permission(request, None)
@@ -174,7 +174,7 @@ class IsStaffOrOwnerTests(TestCase):
def test_has_permission_as_non_owner(self):
""" Non-owners should not have permission. """
user = UserFactory()
request = RequestFactory().get('/?username={}'.format(user.username))
request = RequestFactory().get(f'/?username={user.username}')
request.user = UserFactory()
assert not self.permission.has_permission(request, None)

View File

@@ -25,7 +25,7 @@ class MockAPIView(DeveloperErrorViewMixin, APIView):
"""
Mock GET handler for testing.
"""
return Response("Success {}".format(course_id))
return Response(f"Success {course_id}")
urlpatterns = [
url(r'^mock/(?P<course_id>.*)/$', MockAPIView.as_view()), # Only works with new-style course keys
@@ -51,7 +51,7 @@ class VerifyCourseExistsTestCase(SharedModuleStoreTestCase, APITestCase):
org="This", course="IsA", run="Course",
default_store=ModuleStoreEnum.Type.split,
)
response = self.client.get('/mock/{}/'.format(course.id))
response = self.client.get(f'/mock/{course.id}/')
assert response.status_code == 200
def test_course_with_outdated_overview_200(self):
@@ -62,5 +62,5 @@ class VerifyCourseExistsTestCase(SharedModuleStoreTestCase, APITestCase):
course_overview = CourseOverview.get_from_id(course.id)
course_overview.version = CourseOverview.VERSION - 1
course_overview.save()
response = self.client.get('/mock/{}/'.format(course.id))
response = self.client.get(f'/mock/{course.id}/')
assert response.status_code == 200

View File

@@ -20,7 +20,6 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.request import clone_request
from rest_framework.response import Response
from rest_framework.views import APIView
from six import text_type, iteritems
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.user_api.accounts import BIO_MAX_LENGTH
@@ -35,11 +34,11 @@ class DeveloperErrorResponseException(Exception):
Intended to be used with and by DeveloperErrorViewMixin.
"""
def __init__(self, response):
super(DeveloperErrorResponseException, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments
super().__init__()
self.response = response
class DeveloperErrorViewMixin(object):
class DeveloperErrorViewMixin:
"""
A view mixin to handle common error cases other than validation failure
(auth failure, method not allowed, etc.) by generating an error response
@@ -93,19 +92,19 @@ class DeveloperErrorViewMixin(object):
elif isinstance(exc, APIException):
return self._make_error_response(exc.status_code, exc.detail)
elif isinstance(exc, Http404) or isinstance(exc, ObjectDoesNotExist): # lint-amnesty, pylint: disable=consider-merging-isinstance
return self._make_error_response(404, text_type(exc) or "Not found.")
return self._make_error_response(404, str(exc) or "Not found.")
elif isinstance(exc, ValidationError):
return self._make_validation_error_response(exc)
else:
raise # lint-amnesty, pylint: disable=misplaced-bare-raise
class ExpandableFieldViewMixin(object):
class ExpandableFieldViewMixin:
"""A view mixin to add expansion information to the serializer context for later use by an ExpandableField."""
def get_serializer_context(self):
"""Adds expand information from query parameters to the serializer context to support expandable fields."""
result = super(ExpandableFieldViewMixin, self).get_serializer_context() # lint-amnesty, pylint: disable=super-with-arguments
result = super().get_serializer_context()
result['expand'] = [x for x in self.request.query_params.get('expand', '').split(',') if x]
return result
@@ -141,7 +140,7 @@ def clean_errors(error):
This cursively handles the nesting of errors.
"""
if isinstance(error, ErrorDetail):
return text_type(error)
return str(error)
if isinstance(error, list):
return [clean_errors(el) for el in error]
else:
@@ -153,15 +152,15 @@ def add_serializer_errors(serializer, data, field_errors):
"""Adds errors from serializer validation to field_errors. data is the original data to deserialize."""
if not serializer.is_valid():
errors = serializer.errors
for key, error in iteritems(errors):
for key, error in errors.items():
error = clean_errors(error)
if key == 'bio':
user_message = _(u"The about me field must be at most {} characters long.".format(BIO_MAX_LENGTH)) # lint-amnesty, pylint: disable=translation-of-non-string
user_message = _(f"The about me field must be at most {BIO_MAX_LENGTH} characters long.") # lint-amnesty, pylint: disable=translation-of-non-string
else:
user_message = _(u"This value is invalid.")
user_message = _("This value is invalid.")
field_errors[key] = {
'developer_message': u"Value '{field_value}' is not valid for field '{field_name}': {error}".format(
'developer_message': "Value '{field_value}' is not valid for field '{field_name}': {error}".format(
field_value=data.get(key, ''), field_name=key, error=error
),
'user_message': user_message,
@@ -323,12 +322,12 @@ class LazySequence(Sequence):
def __repr__(self):
if self._exhausted:
return u"LazySequence({!r}, {!r})".format(
return "LazySequence({!r}, {!r})".format(
self._data,
self.est_len,
)
else:
return u"LazySequence(itertools.chain({!r}, {!r}), {!r})".format(
return "LazySequence(itertools.chain({!r}, {!r}), {!r})".format(
self._data,
self.iterable,
self.est_len,
@@ -386,7 +385,7 @@ def require_post_params(required_params):
request = args[0]
missing_params = set(required_params) - set(request.POST.keys())
if missing_params:
msg = u"Missing POST parameters: {missing}".format(
msg = "Missing POST parameters: {missing}".format(
missing=", ".join(missing_params)
)
return HttpResponseBadRequest(msg)
@@ -426,7 +425,7 @@ def verify_course_exists(view_func):
if not CourseOverview.course_exists(course_key):
raise self.api_error(
status_code=status.HTTP_404_NOT_FOUND,
developer_message=u"Requested grade for unknown course {course}".format(course=text_type(course_key)),
developer_message="Requested grade for unknown course {course}".format(course=str(course_key)),
error_code='course_does_not_exist'
)

View File

@@ -10,7 +10,6 @@ import dateutil.parser
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
import requests
import six
from .models import (
Bundle,
@@ -43,7 +42,7 @@ def api_request(method, url, **kwargs):
"""
if not settings.BLOCKSTORE_API_AUTH_TOKEN:
raise ImproperlyConfigured("Cannot use Blockstore unless BLOCKSTORE_API_AUTH_TOKEN is set.")
kwargs.setdefault('headers', {})['Authorization'] = "Token {}".format(settings.BLOCKSTORE_API_AUTH_TOKEN)
kwargs.setdefault('headers', {})['Authorization'] = f"Token {settings.BLOCKSTORE_API_AUTH_TOKEN}"
response = requests.request(method, url, **kwargs)
if response.status_code == 404:
raise NotFound
@@ -115,7 +114,7 @@ def get_collection(collection_uuid):
try:
data = api_request('get', api_url('collections', str(collection_uuid)))
except NotFound:
raise CollectionNotFound("Collection {} does not exist.".format(collection_uuid)) # lint-amnesty, pylint: disable=raise-missing-from
raise CollectionNotFound(f"Collection {collection_uuid} does not exist.") # lint-amnesty, pylint: disable=raise-missing-from
return _collection_from_response(data)
@@ -170,7 +169,7 @@ def get_bundle(bundle_uuid):
try:
data = api_request('get', api_url('bundles', str(bundle_uuid)))
except NotFound:
raise BundleNotFound("Bundle {} does not exist.".format(bundle_uuid)) # lint-amnesty, pylint: disable=raise-missing-from
raise BundleNotFound(f"Bundle {bundle_uuid} does not exist.") # lint-amnesty, pylint: disable=raise-missing-from
return _bundle_from_response(data)
@@ -202,7 +201,8 @@ def update_bundle(bundle_uuid, **fields):
if "collection_uuid" in fields:
data["collection_uuid"] = str(fields.pop("collection_uuid"))
if fields:
raise ValueError("Unexpected extra fields passed to update_bundle: {}".format(fields.keys()))
raise ValueError(f"Unexpected extra fields passed " # pylint: disable=dict-keys-not-iterating
f"to update_bundle: {fields.keys()}")
result = api_request('patch', api_url('bundles', str(bundle_uuid)), json=data)
return _bundle_from_response(result)
@@ -224,7 +224,7 @@ def get_draft(draft_uuid):
try:
data = api_request('get', api_url('drafts', str(draft_uuid)))
except NotFound:
raise DraftNotFound("Draft does not exist: {}".format(draft_uuid)) # lint-amnesty, pylint: disable=raise-missing-from
raise DraftNotFound(f"Draft does not exist: {draft_uuid}") # lint-amnesty, pylint: disable=raise-missing-from
return _draft_from_response(data)
@@ -354,7 +354,7 @@ def get_bundle_file_metadata(bundle_uuid, path, use_draft=None):
return files_dict[path]
except KeyError:
raise BundleFileNotFound( # lint-amnesty, pylint: disable=raise-missing-from
"Bundle {} (draft: {}) does not contain a file {}".format(bundle_uuid, use_draft, path)
f"Bundle {bundle_uuid} (draft: {use_draft}) does not contain a file {path}"
)
@@ -409,7 +409,7 @@ def encode_str_for_draft(input_str):
"""
Given a string, return UTF-8 representation that is then base64 encoded.
"""
if isinstance(input_str, six.text_type):
if isinstance(input_str, str):
binary = input_str.encode('utf8')
else:
binary = input_str

View File

@@ -6,7 +6,6 @@ from datetime import datetime
from uuid import UUID
import attr
import six
def _convert_to_uuid(value):
@@ -16,50 +15,50 @@ def _convert_to_uuid(value):
@attr.s(frozen=True)
class Collection(object):
class Collection:
"""
Metadata about a blockstore collection
"""
uuid = attr.ib(type=UUID, converter=_convert_to_uuid)
title = attr.ib(type=six.text_type)
title = attr.ib(type=str)
@attr.s(frozen=True)
class Bundle(object):
class Bundle:
"""
Metadata about a blockstore bundle
"""
uuid = attr.ib(type=UUID, converter=_convert_to_uuid)
title = attr.ib(type=six.text_type)
description = attr.ib(type=six.text_type)
slug = attr.ib(type=six.text_type)
title = attr.ib(type=str)
description = attr.ib(type=str)
slug = attr.ib(type=str)
drafts = attr.ib(type=dict) # Dict of drafts, where keys are the draft names and values are draft UUIDs
# Note that if latest_version is 0, it means that no versions yet exist
latest_version = attr.ib(type=int, validator=attr.validators.instance_of(int))
@attr.s(frozen=True)
class Draft(object):
class Draft:
"""
Metadata about a blockstore draft
"""
uuid = attr.ib(type=UUID, converter=_convert_to_uuid)
bundle_uuid = attr.ib(type=UUID, converter=_convert_to_uuid)
name = attr.ib(type=six.text_type)
name = attr.ib(type=str)
updated_at = attr.ib(type=datetime, validator=attr.validators.instance_of(datetime))
files = attr.ib(type=dict)
links = attr.ib(type=dict)
@attr.s(frozen=True)
class BundleFile(object):
class BundleFile:
"""
Metadata about a file in a blockstore bundle or draft.
"""
path = attr.ib(type=six.text_type)
path = attr.ib(type=str)
size = attr.ib(type=int)
url = attr.ib(type=six.text_type)
hash_digest = attr.ib(type=six.text_type)
url = attr.ib(type=str)
hash_digest = attr.ib(type=str)
@attr.s(frozen=True)
@@ -71,17 +70,17 @@ class DraftFile(BundleFile):
@attr.s(frozen=True)
class LinkReference(object):
class LinkReference:
"""
A pointer to a specific BundleVersion
"""
bundle_uuid = attr.ib(type=UUID, converter=_convert_to_uuid)
version = attr.ib(type=int)
snapshot_digest = attr.ib(type=six.text_type)
snapshot_digest = attr.ib(type=str)
@attr.s(frozen=True)
class LinkDetails(object):
class LinkDetails:
"""
Details about a specific link in a BundleVersion or Draft
"""

View File

@@ -37,7 +37,7 @@ def ensure_queue_env(desired_env):
(
queue
for queue in queues
if '.{}.'.format(desired_env) in queue
if f'.{desired_env}.' in queue
),
None
)

View File

@@ -43,13 +43,13 @@ def _get_prerequisite_milestone(prereq_content_key):
))
if not milestones:
log.warning(u"Could not find gating milestone for prereq UsageKey %s", prereq_content_key)
log.warning("Could not find gating milestone for prereq UsageKey %s", prereq_content_key)
return None
if len(milestones) > 1:
# We should only ever have one gating milestone per UsageKey
# Log a warning here and pick the first one
log.warning(u"Multiple gating milestones found for prereq UsageKey %s", prereq_content_key)
log.warning("Multiple gating milestones found for prereq UsageKey %s", prereq_content_key)
return milestones[0]
@@ -68,7 +68,7 @@ def _validate_min_score(min_score):
GatingValidationError: If the minimum score is not valid
"""
if min_score:
message = _(u"%(min_score)s is not a valid grade percentage") % {'min_score': min_score}
message = _("%(min_score)s is not a valid grade percentage") % {'min_score': min_score}
try:
min_score = int(min_score)
except ValueError:
@@ -183,7 +183,7 @@ def add_prerequisite(course_key, prereq_content_key):
"""
milestone = milestones_api.add_milestone(
{
'name': _(u'Gating milestone for {usage_key}').format(usage_key=str(prereq_content_key)),
'name': _('Gating milestone for {usage_key}').format(usage_key=str(prereq_content_key)),
'namespace': "{usage_key}{qualifier}".format(
usage_key=prereq_content_key,
qualifier=GATING_NAMESPACE_QUALIFIER
@@ -445,7 +445,7 @@ def get_subsection_grade_percentage(subsection_usage_key, user):
subsection_grade = subsection_grade_factory.update(subsection_structure[subsection_usage_key])
return _get_subsection_percentage(subsection_grade)
except ItemNotFoundError as err:
log.warning(u"Could not find course_block for subsection=%s error=%s", subsection_usage_key, err)
log.warning("Could not find course_block for subsection=%s error=%s", subsection_usage_key, err)
return 0.0
@@ -487,7 +487,7 @@ def get_subsection_completion_percentage(subsection_usage_key, user):
)
except ItemNotFoundError as err:
log.warning(u"Could not find course_block for subsection=%s error=%s", subsection_usage_key, err)
log.warning("Could not find course_block for subsection=%s error=%s", subsection_usage_key, err)
return subsection_completion_percentage
@@ -505,14 +505,14 @@ def _get_minimum_required_percentage(milestone):
min_score = int(requirements.get('min_score'))
except (ValueError, TypeError):
log.warning(
u'Gating: Failed to find minimum score for gating milestone %s, defaulting to 100',
'Gating: Failed to find minimum score for gating milestone %s, defaulting to 100',
json.dumps(milestone)
)
try:
min_completion = int(requirements.get('min_completion', 0))
except (ValueError, TypeError):
log.warning(
u'Gating: Failed to find minimum completion percentage for gating milestone %s, defaulting to 100',
'Gating: Failed to find minimum completion percentage for gating milestone %s, defaulting to 100',
json.dumps(milestone)
)
return min_score, min_completion

View File

@@ -5,7 +5,7 @@ A wrapper class to communicate with Gating api
from . import api as gating_api
class GatingService(object):
class GatingService:
"""
An XBlock service to talk to the Gating api.
"""

View File

@@ -3,15 +3,14 @@ Tests for the gating API
"""
import unittest
from unittest.mock import Mock, patch
import pytest
import six
from completion.models import BlockCompletion
from ddt import data, ddt, unpack
from django.conf import settings
from milestones import api as milestones_api
from milestones.tests.utils import MilestonesTestCaseMixin
from mock import Mock, patch
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.gating import api as lms_gating_api
@@ -37,7 +36,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin):
"""
Initial data setup
"""
super(TestGatingApi, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
# create course
self.course = CourseFactory.create(
@@ -77,7 +76,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin):
self.generic_milestone = {
'name': 'Test generic milestone',
'namespace': six.text_type(self.seq1.location),
'namespace': str(self.seq1.location),
}
@patch('openedx.core.lib.gating.api.log.warning')
@@ -147,7 +146,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin):
prereqs = gating_api.get_prerequisites(self.course.id)
assert len(prereqs) == 1
assert prereqs[0]['block_display_name'] == self.seq1.display_name
assert prereqs[0]['block_usage_key'] == six.text_type(self.seq1.location)
assert prereqs[0]['block_usage_key'] == str(self.seq1.location)
assert gating_api.is_prerequisite(self.course.id, self.seq1.location)
gating_api.remove_prerequisite(self.seq1.location)
@@ -164,7 +163,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin):
prereq_content_key, min_score, min_completion = gating_api.get_required_content(
self.course.id, self.seq2.location
)
assert prereq_content_key == six.text_type(self.seq1.location)
assert prereq_content_key == str(self.seq1.location)
assert min_score == 100
assert min_completion == 100
@@ -193,7 +192,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin):
milestone = milestones_api.get_course_content_milestones(self.course.id, self.seq2.location, 'requires')[0]
assert gating_api.get_gated_content(self.course, staff) == []
assert gating_api.get_gated_content(self.course, student) == [six.text_type(self.seq2.location)]
assert gating_api.get_gated_content(self.course, student) == [str(self.seq2.location)]
milestones_api.add_user_milestone({'id': student.id}, milestone)
@@ -300,7 +299,7 @@ class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin):
component = ItemFactory.create(
parent_location=self.vertical.location,
category=component_type,
display_name=u'{} block'.format(component_type)
display_name=f'{component_type} block'
)
with patch.object(BlockCompletion, 'get_learning_context_completions') as course_block_completions_mock:

View File

@@ -3,7 +3,6 @@
import json
import pprint
import six
def assert_event_matches(expected, actual, tolerate=None):
@@ -86,7 +85,7 @@ def assert_event_matches(expected, actual, tolerate=None):
raise AssertionError('Unexpected differences found in structs:\n\n' + '\n'.join(message_lines))
class EventMatchTolerates(object):
class EventMatchTolerates:
"""
Represents groups of flags that specify the level of tolerance for deviation between an expected event and an actual
event.
@@ -196,7 +195,7 @@ def parse_event_payload(event):
parsed. It will never modify the event in place.
"""
payload_key = 'event' if 'event' in event else 'data'
if payload_key in event and isinstance(event[payload_key], six.string_types):
if payload_key in event and isinstance(event[payload_key], str):
event = event.copy()
try:
event[payload_key] = json.loads(event[payload_key])
@@ -224,18 +223,18 @@ def compare_structs(expected, actual, should_strict_compare=None, path=None):
actual_keys = frozenset(list(actual.keys()))
for key in expected_keys - actual_keys:
differences.append(u'{0}: not found in actual'.format(_path_to_string(path + [key])))
differences.append('{}: not found in actual'.format(_path_to_string(path + [key])))
if should_strict_compare is not None and should_strict_compare(path):
for key in actual_keys - expected_keys:
differences.append(u'{0}: only defined in actual'.format(_path_to_string(path + [key])))
differences.append('{}: only defined in actual'.format(_path_to_string(path + [key])))
for key in expected_keys & actual_keys:
child_differences = compare_structs(expected[key], actual[key], should_strict_compare, path + [key])
differences.extend(child_differences)
elif expected != actual:
differences.append(u'{path}: {a} != {b} (expected != actual)'.format(
differences.append('{path}: {a} != {b} (expected != actual)'.format(
path=_path_to_string(path),
a=repr(expected),
b=repr(actual)

View File

@@ -1,14 +1,12 @@
# -*- coding: utf-8 -*-
"""
Tests for cache_utils.py
"""
from unittest import TestCase
from unittest.mock import Mock
import ddt
import six
from edx_django_utils.cache import RequestCache
from mock import Mock
from openedx.core.lib.cache_utils import request_cached
@@ -177,16 +175,16 @@ class TestRequestCachedDecorator(TestCase):
A dummy function that expects an str and unicode arguments.
"""
assert isinstance(arg1, str), 'First parameter has to be of type `str`'
assert isinstance(arg2, six.text_type), 'Second parameter has to be of type `unicode`'
assert isinstance(arg2, str), 'Second parameter has to be of type `unicode`'
return True
assert dummy_function('Hello', u'World'), 'Should be callable with ASCII chars'
assert dummy_function('H∂llå', u'Wørld'), 'Should be callable with non-ASCII chars'
assert dummy_function('Hello', 'World'), 'Should be callable with ASCII chars'
assert dummy_function('H∂llå', 'Wørld'), 'Should be callable with non-ASCII chars'
wrapped = request_cached()(dummy_function) # lint-amnesty, pylint: disable=no-value-for-parameter
assert wrapped('Hello', u'World'), 'Wrapper should handle ASCII only chars'
assert wrapped('H∂llå', u'Wørld'), 'Wrapper should handle non-ASCII chars'
assert wrapped('Hello', 'World'), 'Wrapper should handle ASCII only chars'
assert wrapped('H∂llå', 'Wørld'), 'Wrapper should handle non-ASCII chars'
def test_request_cached_with_none_result(self):
"""
@@ -276,7 +274,7 @@ class TestRequestCachedDecorator(TestCase):
"""Simple wrapper to let us decorate our mock."""
return to_be_wrapped(*args, **kwargs)
arg_map_function = lambda arg: six.text_type(arg == 1)
arg_map_function = lambda arg: str(arg == 1)
wrapped = request_cached(arg_map_function=arg_map_function)(mock_wrapper) # lint-amnesty, pylint: disable=no-value-for-parameter
# This will be a miss, and make an underlying call.

View File

@@ -1,8 +1,8 @@
""" Tests of specific tabs. """
from unittest import TestCase
from unittest.mock import Mock, patch
import pytest
from mock import Mock, patch
import xmodule.tabs as xmodule_tabs
from openedx.core.lib.course_tabs import CourseTabPluginManager
@@ -40,7 +40,7 @@ class KeyCheckerTestCase(TestCase):
"""Test cases for KeyChecker class"""
def setUp(self):
super(KeyCheckerTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.valid_keys = ['a', 'b']
self.invalid_keys = ['a', 'v', 'g']
@@ -58,7 +58,7 @@ class NeedNameTestCase(TestCase):
"""Test cases for NeedName validator"""
def setUp(self):
super(NeedNameTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.valid_dict1 = {'a': 1, 'name': 2}
self.valid_dict2 = {'name': 1}

View File

@@ -4,7 +4,6 @@ Tests for functionality in openedx/core/lib/courses.py.
import ddt
import six
from django.test.utils import override_settings
from xmodule.modulestore import ModuleStoreEnum
@@ -30,25 +29,25 @@ class CourseImageTestCase(ModuleStoreTestCase):
"""Test image URL formatting."""
course = CourseFactory.create()
self.verify_url(
six.text_type(course.id.make_asset_key('asset', course.course_image)),
str(course.id.make_asset_key('asset', course.course_image)),
course_image_url(course)
)
def test_non_ascii_image_name(self):
""" Verify that non-ascii image names are cleaned """
course_image = u'before_\N{SNOWMAN}_after.jpg'
course_image = 'before_\N{SNOWMAN}_after.jpg'
course = CourseFactory.create(course_image=course_image)
self.verify_url(
six.text_type(course.id.make_asset_key('asset', course_image.replace(u'\N{SNOWMAN}', '_'))),
str(course.id.make_asset_key('asset', course_image.replace('\N{SNOWMAN}', '_'))),
course_image_url(course)
)
def test_spaces_in_image_name(self):
""" Verify that image names with spaces in them are cleaned """
course_image = u'before after.jpg'
course = CourseFactory.create(course_image=u'before after.jpg')
course_image = 'before after.jpg'
course = CourseFactory.create(course_image='before after.jpg')
self.verify_url(
six.text_type(course.id.make_asset_key('asset', course_image.replace(" ", "_"))),
str(course.id.make_asset_key('asset', course_image.replace(" ", "_"))),
course_image_url(course)
)
@@ -65,18 +64,18 @@ class CourseImageTestCase(ModuleStoreTestCase):
def test_get_banner_image_url(self):
"""Test banner image URL formatting."""
banner_image = u'banner_image.jpg'
banner_image = 'banner_image.jpg'
course = CourseFactory.create(banner_image=banner_image)
self.verify_url(
six.text_type(course.id.make_asset_key('asset', banner_image)),
str(course.id.make_asset_key('asset', banner_image)),
course_image_url(course, 'banner_image')
)
def test_get_video_thumbnail_image_url(self):
"""Test video thumbnail image URL formatting."""
thumbnail_image = u'thumbnail_image.jpg'
thumbnail_image = 'thumbnail_image.jpg'
course = CourseFactory.create(video_thumbnail_image=thumbnail_image)
self.verify_url(
six.text_type(course.id.make_asset_key('asset', thumbnail_image)),
str(course.id.make_asset_key('asset', thumbnail_image)),
course_image_url(course, 'video_thumbnail_image')
)

View File

@@ -13,7 +13,7 @@ class TestDerivedSettings(TestCase):
Test settings that are derived from other settings.
"""
def setUp(self):
super(TestDerivedSettings, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
clear_for_tests()
self.module = sys.modules[__name__]
self.module.SIMPLE_VALUE = 'paneer'

View File

@@ -2,9 +2,9 @@
# pylint: disable=missing-docstring
import json
from unittest import mock
import httpretty
import mock
from django.core.cache import cache
from openedx.core.djangoapps.catalog.models import CatalogIntegration
@@ -26,7 +26,7 @@ class TestGetEdxApiData(CatalogIntegrationMixin, CredentialsApiConfigMixin, Cach
ENABLED_CACHES = ['default']
def setUp(self):
super(TestGetEdxApiData, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory()

View File

@@ -6,8 +6,6 @@ Tests for graph traversal generator functions.
from collections import defaultdict
from unittest import TestCase
import six
from six.moves import range
from ..graph_traversals import traverse_post_order, traverse_pre_order, traverse_topologically
@@ -31,7 +29,7 @@ class TestGraphTraversals(TestCase):
# e1 e2
# |
# f1
super(TestGraphTraversals, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.parent_to_children_map = {
'a1': ['b1'],
'a2': ['b2'],
@@ -65,7 +63,7 @@ class TestGraphTraversals(TestCase):
will be [].
"""
result = defaultdict(list)
for parent, children in six.iteritems(parent_to_children_map):
for parent, children in parent_to_children_map.items():
for child in children:
result[child].append(parent)
return result

View File

@@ -28,12 +28,12 @@ class RequestUtilTestCase(unittest.TestCase):
Tests for request_utils module.
"""
def setUp(self):
super(RequestUtilTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.old_site_name = settings.SITE_NAME
self.old_allowed_hosts = settings.ALLOWED_HOSTS
def tearDown(self):
super(RequestUtilTestCase, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments
super().tearDown()
settings.SITE_NAME = self.old_site_name
settings.ALLOWED_HOSTS = self.old_allowed_hosts
@@ -43,7 +43,7 @@ class RequestUtilTestCase(unittest.TestCase):
that allows us to build an absolute URI.
"""
stub = get_request_or_stub()
expected_url = "http://{site_name}/foobar".format(site_name=settings.SITE_NAME)
expected_url = f"http://{settings.SITE_NAME}/foobar"
assert stub.build_absolute_uri('foobar') == expected_url
def test_safe_get_host(self):

View File

@@ -4,7 +4,6 @@ Tests for Course Teams configuration.
import ddt
import six
from django.test import TestCase
from ..teams_config import TeamsConfig, TeamsetConfig, MANAGED_TEAM_MAX_TEAM_SIZE, DEFAULT_COURSE_RUN_MAX_TEAM_SIZE
@@ -174,14 +173,14 @@ class TeamsConfigTests(TestCase):
Assert that teams configs can be reasonably stringified.
"""
config = TeamsConfig({})
assert six.text_type(config) == "Teams configuration for 0 team-sets"
assert str(config) == "Teams configuration for 0 team-sets"
def test_teamset_config_string(self):
"""
Assert that team-set configs can be reasonably stringified.
"""
config = TeamsetConfig({"id": "omlette-du-fromage"})
assert six.text_type(config) == "omlette-du-fromage"
assert str(config) == "omlette-du-fromage"
def test_teams_config_repr(self):
"""
@@ -189,7 +188,7 @@ class TeamsConfigTests(TestCase):
"""
config = TeamsConfig({"team_sets": [{"id": "hedgehogs"}], "max_team_size": 987})
config_repr = repr(config)
assert isinstance(config_repr, six.string_types)
assert isinstance(config_repr, str)
# When repr() fails, it doesn't always throw an exception.
# Instead, it puts error messages in the repr.

View File

@@ -17,7 +17,7 @@ class TestTimeZoneUtils(TestCase):
"""
Sets up user for testing with time zone utils.
"""
super(TestTimeZoneUtils, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory.build()
self.user.save()

View File

@@ -4,12 +4,11 @@ Tests for xblock_utils.py
import uuid
from unittest.mock import patch
import ddt
import six
from django.conf import settings
from django.test.client import RequestFactory
from mock import patch
from opaque_keys.edx.asides import AsideUsageKeyV1, AsideUsageKeyV2
from web_fragments.fragment import Fragment
from xblock.core import XBlockAside
@@ -41,7 +40,7 @@ class TestXblockUtils(SharedModuleStoreTestCase):
@classmethod
def setUpClass(cls):
super(TestXblockUtils, cls).setUpClass()
super().setUpClass()
cls.course_mongo = CourseFactory.create(
default_store=ModuleStoreEnum.Type.mongo,
org='TestX',
@@ -99,7 +98,7 @@ class TestXblockUtils(SharedModuleStoreTestCase):
"""
Verify that new content is added and the resources are the same.
"""
fragment = self.create_fragment(u"<h1>Test!</h1>")
fragment = self.create_fragment("<h1>Test!</h1>")
fragment.initialize_js('BlockMain') # wrap_block() sets some attributes only if there is JS.
course = getattr(self, course_id)
test_wrap_output = wrap_xblock(
@@ -108,7 +107,7 @@ class TestXblockUtils(SharedModuleStoreTestCase):
view='baseview',
frag=fragment,
context={"wrap_xblock_data": {"custom-attribute": "custom-value"}},
usage_id_serializer=lambda usage_id: quote_slashes(six.text_type(usage_id)),
usage_id_serializer=lambda usage_id: quote_slashes(str(usage_id)),
request_token=uuid.uuid1().hex
)
assert isinstance(test_wrap_output, Fragment)
@@ -117,7 +116,7 @@ class TestXblockUtils(SharedModuleStoreTestCase):
assert data_usage_id in test_wrap_output.content
assert '<h1>Test!</h1>' in test_wrap_output.content
assert 'data-custom-attribute="custom-value"' in test_wrap_output.content
assert test_wrap_output.resources[0].data == u'body {background-color:red;}'
assert test_wrap_output.resources[0].data == 'body {background-color:red;}'
assert test_wrap_output.resources[1].data == 'alert("Hi!");'
@ddt.data('course_mongo', 'course_split')
@@ -235,7 +234,7 @@ class TestXBlockAside(SharedModuleStoreTestCase):
@classmethod
def setUpClass(cls):
super(TestXBlockAside, cls).setUpClass()
super().setUpClass()
cls.course = CourseFactory.create()
cls.block = ItemFactory.create(category='aside', parent=cls.course)
cls.aside_v2 = AsideUsageKeyV2(cls.block.scope_ids.usage_id, "aside")
@@ -254,4 +253,4 @@ class TestXBlockAside(SharedModuleStoreTestCase):
@XBlockAside.register_temp_plugin(AsideTestType, 'test_aside')
def test_get_aside(self):
"""test get aside success"""
assert get_aside_from_xblock(self.block, six.text_type("test_aside")) is not None
assert get_aside_from_xblock(self.block, "test_aside") is not None

View File

@@ -6,10 +6,9 @@ import random
import string
from collections import namedtuple
from unittest import TestCase
from unittest import mock
import ddt
import mock
from six.moves import range
from xblock.field_data import DictFieldData
from xblock.fields import NO_CACHE_VALUE, UNIQUE_ID, ScopeIds
from xblock.runtime import Runtime
@@ -23,7 +22,7 @@ def attribute_pair_repr(self):
Custom string representation for the AttributePair namedtuple which is
consistent between test runs.
"""
return u'<AttributePair name={}>'.format(self.name)
return f'<AttributePair name={self.name}>'
AttributePair = namedtuple("AttributePair", ["name", "value"])
@@ -66,7 +65,7 @@ class DiscussionXBlockImportExportTests(TestCase):
"""
Set up method
"""
super(DiscussionXBlockImportExportTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.keys = ScopeIds("any_user", "discussion", "def_id", "usage_id")
self.runtime_mock = mock.Mock(spec=Runtime)
self.runtime_mock.construct_xblock_from_class = mock.Mock(side_effect=self._construct_xblock_mock)
@@ -88,7 +87,7 @@ class DiscussionXBlockImportExportTests(TestCase):
"""
Test that xblock export XML format can be parsed preserving field values
"""
xblock_xml = u"""
xblock_xml = """
<discussion
url_name="82bb87a2d22240b1adac2dfcc1e7e5e4" xblock-family="xblock.v1"
{id_attr}="{id_value}"
@@ -121,7 +120,7 @@ class DiscussionXBlockImportExportTests(TestCase):
Test that legacy export XML format can be parsed preserving field values
"""
xblock_xml = """<discussion url_name="82bb87a2d22240b1adac2dfcc1e7e5e4"/>"""
xblock_definition_xml = u"""
xblock_definition_xml = """
<discussion
{id_attr}="{id_value}"
{category_attr}="{category_value}"

View File

@@ -1,12 +1,9 @@
# -*- coding: utf-8 -*-
"""
Discussion XBlock
"""
import logging
import six
from six.moves import urllib
from six.moves.urllib.parse import urlparse # pylint: disable=import-error
import urllib
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from django.utils.translation import get_language_bidi
@@ -180,13 +177,13 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li
'enrollment_action': 'enroll',
'email_opt_in': False,
})
login_msg = Text(_(u"You are not signed in. To view the discussion content, {sign_in_link} or "
u"{register_link}, and enroll in this course.")).format(
sign_in_link=HTML(u'<a href="{url}">{sign_in_label}</a>').format(
login_msg = Text(_("You are not signed in. To view the discussion content, {sign_in_link} or "
"{register_link}, and enroll in this course.")).format(
sign_in_link=HTML('<a href="{url}">{sign_in_label}</a>').format(
sign_in_label=_('sign in'),
url='{}?{}'.format(reverse('signin_user'), qs),
),
register_link=HTML(u'<a href="/{url}">{register_label}</a>').format(
register_link=HTML('<a href="/{url}">{register_label}</a>').format(
register_label=_('register'),
url='{}?{}'.format(reverse('register_user'), qs),
),
@@ -241,7 +238,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li
XBlock.parse_xml. Otherwise this method parses file in "discussion" folder (known as definition_xml), applies
policy.json and updates fields accordingly.
"""
block = super(DiscussionXBlock, cls).parse_xml(node, runtime, keys, id_generator)
block = super().parse_xml(node, runtime, keys, id_generator)
cls._apply_translations_to_node_attributes(block, node)
cls._apply_metadata_and_policy(block, node, runtime)
@@ -253,7 +250,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li
"""
Applies metadata translations for attributes stored on an inlined XML element.
"""
for old_attr, target_attr in six.iteritems(cls.metadata_translations):
for old_attr, target_attr in cls.metadata_translations.items():
if old_attr in node.attrib and hasattr(block, target_attr):
setattr(block, target_attr, node.attrib[old_attr])
@@ -268,7 +265,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li
definition_xml, _ = cls.load_definition_xml(node, runtime, block.scope_ids.def_id)
except Exception as err: # pylint: disable=broad-except
log.info(
u"Exception %s when trying to load definition xml for block %s - assuming XBlock export format",
"Exception %s when trying to load definition xml for block %s - assuming XBlock export format",
err,
block
)
@@ -277,6 +274,6 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li
metadata = cls.load_metadata(definition_xml)
cls.apply_policy(metadata, runtime.get_policy(block.scope_ids.usage_id))
for field_name, value in six.iteritems(metadata):
for field_name, value in metadata.items():
if field_name in block.fields:
setattr(block, field_name, value)

View File

@@ -27,7 +27,7 @@ class XBlockPackageStorage(Storage):
"""
Returns a static file storage if available in the given app.
"""
super(XBlockPackageStorage, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(*args, **kwargs)
self.module = module
self.base_dir = base_dir
@@ -119,7 +119,7 @@ class XBlockPipelineFinder(BaseFinder): # lint-amnesty, pylint: disable=abstrac
initialization happens, we just proxy all list()/find() requests by
iterating through the XBlockPackageStorage objects.
"""
super(XBlockPipelineFinder, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(*args, **kwargs)
# xblock_resource_info holds (package_name, resources_dir) tuples. While
# it never happens in practice, the XBlock API does allow different

View File

@@ -11,7 +11,6 @@ import re
import uuid
import markupsafe
import six
import webpack_loader.utils
from contracts import contract
from django.conf import settings
@@ -23,7 +22,6 @@ from edx_django_utils.plugins import pluggable_override
from lxml import etree, html
from opaque_keys.edx.asides import AsideUsageKeyV1, AsideUsageKeyV2
from pytz import UTC
from six import text_type
from web_fragments.fragment import Fragment
from xblock.core import XBlock
from xblock.exceptions import InvalidScopeError
@@ -149,8 +147,8 @@ def wrap_xblock(
'content': block.display_name if display_name_only else frag.content,
'classes': css_classes,
'display_name': block.display_name_with_default_escaped, # xss-lint: disable=python-deprecated-display-name
'data_attributes': u' '.join(u'data-{}="{}"'.format(markupsafe.escape(key), markupsafe.escape(value))
for key, value in six.iteritems(data)),
'data_attributes': ' '.join('data-{}="{}"'.format(markupsafe.escape(key), markupsafe.escape(value))
for key, value in data.items()),
}
if hasattr(frag, 'json_init_args') and frag.json_init_args is not None:
@@ -222,8 +220,8 @@ def wrap_xblock_aside(
template_context = {
'content': frag.content,
'classes': css_classes,
'data_attributes': u' '.join(u'data-{}="{}"'.format(markupsafe.escape(key), markupsafe.escape(value))
for key, value in six.iteritems(data)),
'data_attributes': ' '.join('data-{}="{}"'.format(markupsafe.escape(key), markupsafe.escape(value))
for key, value in data.items()),
}
if hasattr(frag, 'json_init_args') and frag.json_init_args is not None:
@@ -287,14 +285,14 @@ def grade_histogram(module_id):
from django.db import connection
cursor = connection.cursor()
query = u"""\
query = """\
SELECT courseware_studentmodule.grade,
COUNT(courseware_studentmodule.student_id)
FROM courseware_studentmodule
WHERE courseware_studentmodule.module_id=%s
GROUP BY courseware_studentmodule.grade"""
# Passing module_id this way prevents sql-injection.
cursor.execute(query, [text_type(module_id)])
cursor.execute(query, [str(module_id)])
grades = list(cursor.fetchall())
grades.sort(key=lambda x: x[0]) # Add ORDER BY to sql query?
@@ -311,7 +309,7 @@ def sanitize_html_id(html_id):
return sanitized_html_id
@contract(user=User, block=XBlock, view=six.string_types[0], frag=Fragment, context="dict|None")
@contract(user=User, block=XBlock, view=(str,)[0], frag=Fragment, context="dict|None")
def add_staff_markup(user, disable_staff_debug_info, block, view, frag, context): # pylint: disable=unused-argument
"""
Updates the supplied module with a new get_html function that wraps
@@ -349,7 +347,7 @@ def add_staff_markup(user, disable_staff_debug_info, block, view, frag, context)
filepath = filename
data_dir = block.static_asset_path or osfs.root_path.rsplit('/')[-1]
giturl = block.giturl or 'https://github.com/MITx'
edit_link = "%s/%s/tree/master/%s" % (giturl, data_dir, filepath)
edit_link = f"{giturl}/{data_dir}/tree/master/{filepath}"
else:
edit_link = False
# Need to define all the variables that are about to be used
@@ -383,7 +381,7 @@ def add_staff_markup(user, disable_staff_debug_info, block, view, frag, context)
'location': block.location,
'xqa_key': block.xqa_key,
'source_file': source_file,
'source_url': '%s/%s/tree/master/%s' % (giturl, data_dir, source_file),
'source_url': f'{giturl}/{data_dir}/tree/master/{source_file}',
'category': str(block.__class__.__name__),
'element_id': sanitize_html_id(block.location.html_id()),
'edit_link': edit_link,
@@ -550,7 +548,7 @@ def hash_resource(resource):
for data in resource:
if isinstance(data, bytes):
md5.update(data)
elif isinstance(data, six.string_types):
elif isinstance(data, str):
md5.update(data.encode('utf-8'))
else:
md5.update(repr(data).encode('utf-8'))

View File

@@ -17,7 +17,7 @@ class TestAdminView(TestCase):
Tests of the admin view
"""
def setUp(self):
super(TestAdminView, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.client = Client()
def test_admin_view_loads_for_is_staff(self):