Merge branch 'master' into usamasadiq/bom-2327-pylint-amnesty

This commit is contained in:
Usama Sadiq
2021-02-08 18:24:53 +05:00
committed by GitHub
251 changed files with 1160 additions and 1074 deletions

View File

@@ -47,8 +47,8 @@ class ApiAccessRequestViewTests(TestCase):
Assert API response on `API Access Request` endpoint.
"""
json_content = json.loads(api_response.content.decode('utf-8'))
self.assertEqual(api_response.status_code, 200)
self.assertEqual(json_content['count'], expected_results_count)
assert api_response.status_code == 200
assert json_content['count'] == expected_results_count
def test_list_view_for_not_authenticated_user(self):
"""
@@ -66,7 +66,7 @@ class ApiAccessRequestViewTests(TestCase):
self.client.logout()
response = self.client.get(self.url)
self.assertEqual(response.status_code, 401)
assert response.status_code == 401
def test_list_view_for_staff_user(self):
"""
@@ -94,5 +94,5 @@ class ApiAccessRequestViewTests(TestCase):
self.update_user_and_re_login(is_staff=True)
response = self.client.get(self.url + '?user__username={}'.format('non-existing-user-name'))
self.assertEqual(response.status_code, 200)
assert response.status_code == 200
self._assert_api_access_request_response(api_response=response, expected_results_count=0)

View File

@@ -25,14 +25,8 @@ class TestCreateApiAccessRequest(TestCase):
cls.user = UserFactory()
def assert_models_exist(self, expect_request_exists, expect_config_exists):
self.assertEqual(
ApiAccessRequest.objects.filter(user=self.user).exists(),
expect_request_exists
)
self.assertEqual(
ApiAccessConfig.objects.filter(enabled=True).exists(),
expect_config_exists
)
assert ApiAccessRequest.objects.filter(user=self.user).exists() == expect_request_exists
assert ApiAccessConfig.objects.filter(enabled=True).exists() == expect_config_exists
@ddt.data(False, True)
def test_create_api_access_request(self, create_config):
@@ -45,14 +39,14 @@ class TestCreateApiAccessRequest(TestCase):
self.assert_models_exist(False, False)
call_command(self.command, self.user.username, create_config=True, disconnect_signals=True)
self.assert_models_exist(True, True)
self.assertFalse(mock_send_new_pending_email.called)
assert not mock_send_new_pending_email.called
@patch('openedx.core.djangoapps.api_admin.models._send_new_pending_email')
def test_create_api_access_request_signals_connected(self, mock_send_new_pending_email):
self.assert_models_exist(False, False)
call_command(self.command, self.user.username, create_config=True, disconnect_signals=False)
self.assert_models_exist(True, True)
self.assertTrue(mock_send_new_pending_email.called)
assert mock_send_new_pending_email.called
def test_config_already_exists(self):
ApiAccessConfig.objects.create(enabled=True)
@@ -125,12 +119,12 @@ class TestCreateApiAccessRequest(TestCase):
)
self.assert_models_exist(True, False)
request = ApiAccessRequest.objects.get(user=self.user)
self.assertEqual(request.status, 'approved')
self.assertEqual(request.reason, 'whatever')
self.assertEqual(request.website, 'test-site.edx.horse')
assert request.status == 'approved'
assert request.reason == 'whatever'
assert request.website == 'test-site.edx.horse'
def test_default_values(self):
call_command(self.command, self.user.username)
request = ApiAccessRequest.objects.get(user=self.user)
self.assertEqual(request.site, Site.objects.get_current())
self.assertEqual(request.status, ApiAccessRequest.APPROVED)
assert request.site == Site.objects.get_current()
assert request.status == ApiAccessRequest.APPROVED

View File

@@ -21,7 +21,7 @@ class ApiAccessFormTest(TestCase):
@ddt.unpack
def test_form_valid(self, data, is_valid):
form = ApiAccessRequestForm(data)
self.assertEqual(form.is_valid(), is_valid)
assert form.is_valid() == is_valid
@skip_unless_lms
@@ -43,8 +43,8 @@ class ViewersWidgetTest(TestCase):
extra_formating=extra_formating,
)
output = self.widget.render(name=input_field_name, value=dummy_string_value)
self.assertEqual(expected_widget_html, output)
assert expected_widget_html == output
dummy_list_value = ['staff', 'verified']
output = self.widget.render(name=input_field_name, value=dummy_list_value)
self.assertEqual(expected_widget_html, output)
assert expected_widget_html == output

View File

@@ -3,6 +3,7 @@
from smtplib import SMTPException
import pytest
import ddt
import mock
import six
@@ -27,21 +28,21 @@ class ApiAccessRequestTests(TestCase):
self.request = ApiAccessRequestFactory(user=self.user)
def test_default_status(self):
self.assertEqual(self.request.status, ApiAccessRequest.PENDING)
self.assertFalse(ApiAccessRequest.has_api_access(self.user))
assert self.request.status == ApiAccessRequest.PENDING
assert not ApiAccessRequest.has_api_access(self.user)
def test_approve(self):
self.request.approve()
self.assertEqual(self.request.status, ApiAccessRequest.APPROVED)
assert self.request.status == ApiAccessRequest.APPROVED
def test_deny(self):
self.request.deny()
self.assertEqual(self.request.status, ApiAccessRequest.DENIED)
assert self.request.status == ApiAccessRequest.DENIED
def test_nonexistent_request(self):
"""Test that users who have not requested API access do not get it."""
other_user = UserFactory()
self.assertFalse(ApiAccessRequest.has_api_access(other_user))
assert not ApiAccessRequest.has_api_access(other_user)
@ddt.data(
(ApiAccessRequest.PENDING, False),
@@ -52,46 +53,40 @@ class ApiAccessRequestTests(TestCase):
def test_has_access(self, status, should_have_access):
self.request.status = status
self.request.save()
self.assertEqual(ApiAccessRequest.has_api_access(self.user), should_have_access)
assert ApiAccessRequest.has_api_access(self.user) == should_have_access
def test_unique_per_user(self):
with self.assertRaises(IntegrityError):
with pytest.raises(IntegrityError):
ApiAccessRequestFactory(user=self.user)
def test_no_access(self):
self.request.delete()
self.assertIsNone(ApiAccessRequest.api_access_status(self.user))
assert ApiAccessRequest.api_access_status(self.user) is None
def test_unicode(self):
request_unicode = six.text_type(self.request)
self.assertIn(self.request.website, request_unicode)
self.assertIn(self.request.status, request_unicode)
assert self.request.website in request_unicode
assert self.request.status in request_unicode
def test_retire_user_success(self):
retire_result = self.request.retire_user(self.user)
self.assertTrue(retire_result)
self.assertEqual(self.request.company_address, '')
self.assertEqual(self.request.company_name, '')
self.assertEqual(self.request.website, '')
self.assertEqual(self.request.reason, '')
assert retire_result
assert self.request.company_address == ''
assert self.request.company_name == ''
assert self.request.website == ''
assert self.request.reason == ''
def test_retire_user_do_not_exist(self):
user2 = UserFactory()
retire_result = self.request.retire_user(user2)
self.assertFalse(retire_result)
assert not retire_result
class ApiAccessConfigTests(TestCase):
def test_unicode(self):
self.assertEqual(
six.text_type(ApiAccessConfig(enabled=True)),
u'ApiAccessConfig [enabled=True]'
)
self.assertEqual(
six.text_type(ApiAccessConfig(enabled=False)),
u'ApiAccessConfig [enabled=False]'
)
assert six.text_type(ApiAccessConfig(enabled=True)) == u'ApiAccessConfig [enabled=True]'
assert six.text_type(ApiAccessConfig(enabled=False)) == u'ApiAccessConfig [enabled=False]'
@skip_unless_lms
@@ -110,7 +105,7 @@ class ApiAccessRequestSignalTests(TestCase):
self.api_access_request.save()
mock_new_email.assert_called_once_with(self.api_access_request)
self.assertFalse(mock_decision_email.called)
assert not mock_decision_email.called
def test_save_signal_success_decision_email(self):
""" Verify that updating request status sends decision email and no new email. """
@@ -121,7 +116,7 @@ class ApiAccessRequestSignalTests(TestCase):
self.api_access_request.approve()
mock_decision_email.assert_called_once_with(self.api_access_request)
self.assertFalse(mock_new_email.called)
assert not mock_new_email.called
def test_save_signal_success_no_emails(self):
""" Verify that updating request status again sends no emails. """
@@ -132,12 +127,12 @@ class ApiAccessRequestSignalTests(TestCase):
with mock.patch(self.send_decision_email_function) as mock_decision_email:
self.api_access_request.deny()
self.assertFalse(mock_decision_email.called)
self.assertFalse(mock_new_email.called)
assert not mock_decision_email.called
assert not mock_new_email.called
def test_save_signal_failure_email(self):
""" Verify that saving still functions even on email errors. """
self.assertIsNone(self.api_access_request.id)
assert self.api_access_request.id is None
mail_function = 'openedx.core.djangoapps.api_admin.models.send_mail'
with mock.patch(mail_function, side_effect=SMTPException):
@@ -149,7 +144,7 @@ class ApiAccessRequestSignalTests(TestCase):
u'Error sending API user notification email for request [%s].', self.api_access_request.id
)
# Verify object saved
self.assertIsNotNone(self.api_access_request.id)
assert self.api_access_request.id is not None
with mock.patch(mail_function, side_effect=SMTPException):
with mock.patch.object(model_log, 'exception') as mock_model_log_exception:
@@ -159,4 +154,4 @@ class ApiAccessRequestSignalTests(TestCase):
u'Error sending API user notification email for request [%s].', self.api_access_request.id
)
# Verify object saved
self.assertEqual(self.api_access_request.status, ApiAccessRequest.APPROVED)
assert self.api_access_request.status == ApiAccessRequest.APPROVED

View File

@@ -48,13 +48,13 @@ class ApiRequestViewTest(ApiAdminTest):
def test_get(self):
"""Verify that a logged-in can see the API request form."""
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
assert response.status_code == 200
def test_get_anonymous(self):
"""Verify that users must be logged in to see the page."""
self.client.logout()
response = self.client.get(self.url)
self.assertEqual(response.status_code, 302)
assert response.status_code == 302
def test_get_with_existing_request(self):
"""
@@ -72,12 +72,12 @@ class ApiRequestViewTest(ApiAdminTest):
"""
self.assertRedirects(response, reverse('api_admin:api-status'))
api_request = ApiAccessRequest.objects.get(user=self.user)
self.assertEqual(api_request.status, ApiAccessRequest.PENDING)
assert api_request.status == ApiAccessRequest.PENDING
return api_request
def test_post_valid(self):
"""Verify that a logged-in user can create an API request."""
self.assertFalse(ApiAccessRequest.objects.all().exists())
assert not ApiAccessRequest.objects.all().exists()
response = self.client.post(self.url, VALID_DATA)
self._assert_post_success(response)
@@ -86,20 +86,20 @@ class ApiRequestViewTest(ApiAdminTest):
self.client.logout()
response = self.client.post(self.url, VALID_DATA)
self.assertEqual(response.status_code, 302)
self.assertFalse(ApiAccessRequest.objects.all().exists())
assert response.status_code == 302
assert not ApiAccessRequest.objects.all().exists()
def test_get_with_feature_disabled(self):
"""Verify that the view can be disabled via ApiAccessConfig."""
ApiAccessConfig(enabled=False).save()
response = self.client.get(self.url)
self.assertEqual(response.status_code, 404)
assert response.status_code == 404
def test_post_with_feature_disabled(self):
"""Verify that the view can be disabled via ApiAccessConfig."""
ApiAccessConfig(enabled=False).save()
response = self.client.post(self.url)
self.assertEqual(response.status_code, 404)
assert response.status_code == 404
@skip_unless_lms
@@ -155,13 +155,13 @@ class ApiRequestStatusViewTest(ApiAdminTest):
"""Verify that users must be logged in to see the page."""
self.client.logout()
response = self.client.get(self.url)
self.assertEqual(response.status_code, 302)
assert response.status_code == 302
def test_get_with_feature_disabled(self):
"""Verify that the view can be disabled via ApiAccessConfig."""
ApiAccessConfig(enabled=False).save()
response = self.client.get(self.url)
self.assertEqual(response.status_code, 404)
assert response.status_code == 404
@ddt.data(
(ApiAccessRequest.APPROVED, True, True),
@@ -188,15 +188,15 @@ class ApiRequestStatusViewTest(ApiAdminTest):
})
applications = Application.objects.filter(user=self.user)
if application_exists and new_application_created:
self.assertEqual(applications.count(), 1)
self.assertNotEqual(old_application, applications[0])
assert applications.count() == 1
assert old_application != applications[0]
elif application_exists:
self.assertEqual(applications.count(), 1)
self.assertEqual(old_application, applications[0])
assert applications.count() == 1
assert old_application == applications[0]
elif new_application_created:
self.assertEqual(applications.count(), 1)
assert applications.count() == 1
else:
self.assertEqual(applications.count(), 0)
assert applications.count() == 0
def test_post_with_errors(self):
ApiAccessRequestFactory(user=self.user, status=ApiAccessRequest.APPROVED)
@@ -233,7 +233,7 @@ class CatalogTest(ApiAdminTest):
def mock_catalog_endpoint(self, data, catalog_id=None, method=httpretty.GET, status_code=200):
""" Mock the Course Catalog API's catalog endpoint. """
self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Catalog API calls.')
assert httpretty.is_enabled(), 'httpretty must be enabled to mock Catalog API calls.'
url = '{root}/catalogs/'.format(root=settings.COURSE_CATALOG_API_URL.rstrip('/'))
if catalog_id:
@@ -259,7 +259,7 @@ class CatalogSearchViewTest(CatalogTest):
def test_get(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
assert response.status_code == 200
@httpretty.activate
def test_post(self):
@@ -295,7 +295,7 @@ class CatalogListViewTest(CatalogTest):
"""Verify that the view works when no catalogs are set up."""
self.mock_catalog_endpoint({}, status_code=404)
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
assert response.status_code == 200
@httpretty.activate
def test_post(self):
@@ -307,7 +307,7 @@ class CatalogListViewTest(CatalogTest):
catalog_id = 123
self.mock_catalog_endpoint(dict(catalog_data, id=catalog_id), method=httpretty.POST)
response = self.client.post(self.url, catalog_data)
self.assertEqual(httpretty.last_request().method, 'POST')
assert httpretty.last_request().method == 'POST'
self.mock_catalog_endpoint(CatalogFactory().attributes, catalog_id=catalog_id)
self.assertRedirects(response, reverse('api_admin:catalog-edit', kwargs={'catalog_id': catalog_id}))
@@ -320,9 +320,9 @@ class CatalogListViewTest(CatalogTest):
'query': '*',
'viewers': [self.catalog_user.username]
})
self.assertEqual(response.status_code, 400)
assert response.status_code == 400
# Assert that no POST was made to the catalog API
self.assertEqual(len([r for r in httpretty.httpretty.latest_requests if r.method == 'POST']), 0)
assert len([r for r in httpretty.httpretty.latest_requests if r.method == 'POST']) == 0
@skip_unless_lms
@@ -351,12 +351,10 @@ class CatalogEditViewTest(CatalogTest):
)
response = self.client.post(self.url, {'delete-catalog': 'on'})
self.assertRedirects(response, reverse('api_admin:catalog-search'))
self.assertEqual(httpretty.last_request().method, 'DELETE')
self.assertEqual(
httpretty.last_request().path, # lint-amnesty, pylint: disable=no-member
'/api/v1/catalogs/{}/'.format(self.catalog.id)
)
self.assertEqual(len(httpretty.httpretty.latest_requests), 1)
assert httpretty.last_request().method == 'DELETE' # lint-amnesty, pylint: disable=no-member
assert httpretty.last_request().path == \
'/api/v1/catalogs/{}/'.format(self.catalog.id) # lint-amnesty, pylint: disable=no-member
assert len(httpretty.httpretty.latest_requests) == 1
@httpretty.activate
def test_edit(self):
@@ -371,9 +369,9 @@ class CatalogEditViewTest(CatalogTest):
self.mock_catalog_endpoint(self.catalog.attributes, catalog_id=self.catalog.id)
new_attributes = dict(self.catalog.attributes, **{'delete-catalog': 'off', 'name': ''})
response = self.client.post(self.url, new_attributes)
self.assertEqual(response.status_code, 400)
assert response.status_code == 400
# Assert that no PATCH was made to the Catalog API
self.assertEqual(len([r for r in httpretty.httpretty.latest_requests if r.method == 'PATCH']), 0)
assert len([r for r in httpretty.httpretty.latest_requests if r.method == 'PATCH']) == 0
@skip_unless_lms
@@ -395,13 +393,10 @@ class CatalogPreviewViewTest(CatalogTest):
content_type='application/json'
)
response = self.client.get(self.url, {'q': '*'})
self.assertEqual(response.status_code, 200)
self.assertEqual(json.loads(response.content.decode('utf-8')), data)
assert response.status_code == 200
assert json.loads(response.content.decode('utf-8')) == data
def test_get_without_query(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(
json.loads(response.content.decode('utf-8')),
{'count': 0, 'results': [], 'next': None, 'prev': None}
)
assert response.status_code == 200
assert json.loads(response.content.decode('utf-8')) == {'count': 0, 'results': [], 'next': None, 'prev': None}

View File

@@ -6,7 +6,7 @@ Tasks for bookmarks.
import logging
import six
from celery.task import task
from celery import shared_task
from django.db import transaction
from edx_django_utils.monitoring import set_code_owner_attribute
from opaque_keys.edx.keys import CourseKey
@@ -145,7 +145,7 @@ def _update_xblocks_cache(course_key):
update_block_cache_if_needed(block_cache, block_data)
@task(name=u'openedx.core.djangoapps.bookmarks.tasks.update_xblocks_cache')
@shared_task(name=u'openedx.core.djangoapps.bookmarks.tasks.update_xblocks_cache')
@set_code_owner_attribute
def update_xblocks_cache(course_id):
"""

View File

@@ -3,7 +3,7 @@ This file contains celery tasks for ccxcon
"""
from celery.task import task
from celery import shared_task
from celery.utils.log import get_task_logger
from edx_django_utils.monitoring import set_code_owner_attribute
from opaque_keys.edx.keys import CourseKey
@@ -14,7 +14,7 @@ from openedx.core.djangoapps.ccxcon import api
log = get_task_logger(__name__)
@task(name='openedx.core.djangoapps.ccxcon.tasks.update_ccxcon')
@shared_task(name='openedx.core.djangoapps.ccxcon.tasks.update_ccxcon')
@set_code_owner_attribute
def update_ccxcon(course_id, cur_retry=0):
"""

View File

@@ -17,7 +17,7 @@ class BlockStructureAdmin(ConfigurationModelAdmin):
"""
Excludes unused 'enabled field from super's list.
"""
displayable_field_names = super(BlockStructureAdmin, self).get_displayable_field_names()
displayable_field_names = super(BlockStructureAdmin, self).get_displayable_field_names() # lint-amnesty, pylint: disable=super-with-arguments
displayable_field_names.remove('enabled')
return displayable_field_names

View File

@@ -21,4 +21,4 @@ class BlockStructureConfig(AppConfig):
These happen at import time. Hence the unused imports
"""
from . import signals, tasks # pylint: disable=unused-variable
from . import signals, tasks # lint-amnesty, pylint: disable=unused-import, unused-variable

View File

@@ -299,21 +299,21 @@ class FieldData(object):
def __getattr__(self, field_name):
if self._is_own_field(field_name):
return super(FieldData, self).__getattr__(field_name)
return super(FieldData, self).__getattr__(field_name) # lint-amnesty, pylint: disable=no-member, super-with-arguments
try:
return self.fields[field_name]
except KeyError:
raise AttributeError(u"Field {0} does not exist".format(field_name))
raise AttributeError(u"Field {0} does not exist".format(field_name)) # lint-amnesty, pylint: disable=raise-missing-from
def __setattr__(self, field_name, field_value):
if self._is_own_field(field_name):
return super(FieldData, self).__setattr__(field_name, field_value)
return super(FieldData, self).__setattr__(field_name, field_value) # lint-amnesty, pylint: disable=super-with-arguments
else:
self.fields[field_name] = field_value
def __delattr__(self, field_name):
if self._is_own_field(field_name):
return super(FieldData, self).__delattr__(field_name)
return super(FieldData, self).__delattr__(field_name) # lint-amnesty, pylint: disable=super-with-arguments
else:
del self.fields[field_name]
@@ -329,7 +329,7 @@ class TransformerData(FieldData):
"""
Data structure to encapsulate collected data for a transformer.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class TransformerDataMap(dict):
@@ -383,10 +383,10 @@ class BlockData(FieldData):
Data structure to encapsulate collected data for a single block.
"""
def class_field_names(self):
return super(BlockData, self).class_field_names() + ['location', 'transformer_data']
return super(BlockData, self).class_field_names() + ['location', 'transformer_data'] # lint-amnesty, pylint: disable=super-with-arguments
def __init__(self, usage_key):
super(BlockData, self).__init__()
super(BlockData, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments
# Location (or usage key) of the block.
self.location = usage_key
@@ -407,7 +407,7 @@ class BlockStructureBlockData(BlockStructure):
VERSION = 2
def __init__(self, root_block_usage_key):
super(BlockStructureBlockData, self).__init__(root_block_usage_key)
super(BlockStructureBlockData, self).__init__(root_block_usage_key) # lint-amnesty, pylint: disable=super-with-arguments
# Map of a block's usage key to its collected data, including
# its xBlock fields and block-specific transformer data.
@@ -750,7 +750,7 @@ class BlockStructureBlockData(BlockStructure):
its current version number.
"""
if transformer.WRITE_VERSION == 0:
raise TransformerException(u'Version attributes are not set on transformer {0}.', transformer.name())
raise TransformerException(u'Version attributes are not set on transformer {0}.', transformer.name()) # lint-amnesty, pylint: disable=raising-format-tuple
self.set_transformer_data(transformer, TRANSFORMER_VERSION_KEY, transformer.WRITE_VERSION)
def _get_or_create_block(self, usage_key):
@@ -778,7 +778,7 @@ class BlockStructureModulestoreData(BlockStructureBlockData):
interface and implementation of an xBlock.
"""
def __init__(self, root_block_usage_key):
super(BlockStructureModulestoreData, self).__init__(root_block_usage_key)
super(BlockStructureModulestoreData, self).__init__(root_block_usage_key) # lint-amnesty, pylint: disable=super-with-arguments
# Map of a block's usage key to its instantiated xBlock.
# dict {UsageKey: XBlock}

View File

@@ -7,21 +7,21 @@ class BlockStructureException(Exception):
"""
Base class for all Block Structure framework exceptions.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class TransformerException(BlockStructureException):
"""
Exception class for Transformer related errors.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class UsageKeyNotInBlockStructure(BlockStructureException):
"""
Exception for when a usage key is not found within a block structure.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class TransformerDataIncompatible(BlockStructureException):
@@ -29,7 +29,7 @@ class TransformerDataIncompatible(BlockStructureException):
Exception for when the version of a Transformer's data is not
compatible with the current version of the Transformer.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class BlockStructureNotFound(BlockStructureException):
@@ -37,6 +37,6 @@ class BlockStructureNotFound(BlockStructureException):
Exception for when a Block Structure is not found.
"""
def __init__(self, root_block_usage_key):
super(BlockStructureNotFound, self).__init__(
super(BlockStructureNotFound, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments
u'Block structure not found; data_usage_key: {}'.format(root_block_usage_key)
)

View File

@@ -32,7 +32,7 @@ class TestGenerateCourseBlocks(ModuleStoreTestCase):
"""
Create courses in modulestore.
"""
super(TestGenerateCourseBlocks, self).setUp()
super(TestGenerateCourseBlocks, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.courses = [CourseFactory.create() for _ in range(self.num_courses)]
self.course_keys = [course.id for course in self.courses]
self.command = generate_course_blocks.Command()

View File

@@ -71,7 +71,7 @@ class BlockStructureManager(object):
# requested location. The rest of the structure will be pruned
# as part of the transformation.
if starting_block_usage_key not in block_structure:
raise UsageKeyNotInBlockStructure(
raise UsageKeyNotInBlockStructure( # lint-amnesty, pylint: disable=raising-format-tuple
u"The requested usage_key '{0}' is not found in the block_structure with root '{1}'",
six.text_type(starting_block_usage_key),
six.text_type(self.root_block_usage_key),

View File

@@ -102,10 +102,10 @@ class CustomizableFileField(models.FileField):
storage=_bs_model_storage(),
max_length=500, # allocate enough for base path + prefix + usage_key + timestamp in filepath
))
super(CustomizableFileField, self).__init__(*args, **kwargs)
super(CustomizableFileField, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
def deconstruct(self):
name, path, args, kwargs = super(CustomizableFileField, self).deconstruct()
def deconstruct(self): # lint-amnesty, pylint: disable=missing-function-docstring
name, path, args, kwargs = super(CustomizableFileField, self).deconstruct() # lint-amnesty, pylint: disable=super-with-arguments
del kwargs['upload_to']
del kwargs['storage']
del kwargs['max_length']
@@ -136,13 +136,13 @@ def _storage_error_handling(bs_model, operation, is_read_operation=False):
yield
except Exception as error: # pylint: disable=broad-except
log.exception(u'BlockStructure: Exception %s on store %s; %s.', error.__class__, operation, bs_model)
if isinstance(error, OSError) and error.errno in (errno.EACCES, errno.EPERM): # pylint: disable=no-member
if isinstance(error, OSError) and error.errno in (errno.EACCES, errno.EPERM): # lint-amnesty, pylint: disable=no-else-raise, no-member
raise
elif is_read_operation and isinstance(error, (IOError, SuspiciousOperation)):
# May have been caused by one of the possible error
# situations listed above. Raise BlockStructureNotFound
# so the block structure can be regenerated and restored.
raise BlockStructureNotFound(bs_model.data_usage_key)
raise BlockStructureNotFound(bs_model.data_usage_key) # lint-amnesty, pylint: disable=raise-missing-from
else:
raise
@@ -216,7 +216,7 @@ class BlockStructureModel(TimeStampedModel):
return cls.objects.get(data_usage_key=data_usage_key)
except cls.DoesNotExist:
log.info(u'BlockStructure: Not found in table; %s.', data_usage_key)
raise BlockStructureNotFound(data_usage_key)
raise BlockStructureNotFound(data_usage_key) # lint-amnesty, pylint: disable=raise-missing-from
@classmethod
def update_or_create(cls, serialized_data, data_usage_key, **kwargs):
@@ -263,7 +263,7 @@ class BlockStructureModel(TimeStampedModel):
try:
all_files_by_date = sorted(cls._get_all_files(data_usage_key))
files_to_delete = all_files_by_date[:-num_to_keep] if num_to_keep > 0 else all_files_by_date
files_to_delete = all_files_by_date[:-num_to_keep] if num_to_keep > 0 else all_files_by_date # lint-amnesty, pylint: disable=invalid-unary-operand-type
cls._delete_files(files_to_delete)
log.info(
u'BlockStructure: Deleted %d out of total %d files in store; data_usage_key: %s, num_to_keep: %d.',

View File

@@ -39,7 +39,7 @@ class StubModel(object):
"""
Noop delete method.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class BlockStructureStore(object):
@@ -216,7 +216,7 @@ class BlockStructureStore(object):
# Somehow failed to de-serialized the data, assume it's corrupt.
bs_model = self._get_model(root_block_usage_key)
logger.exception(u"BlockStructure: Failed to load data from cache for %s", bs_model)
raise BlockStructureNotFound(bs_model.data_usage_key)
raise BlockStructureNotFound(bs_model.data_usage_key) # lint-amnesty, pylint: disable=raise-missing-from
return BlockStructureFactory.create_new(
root_block_usage_key,

View File

@@ -5,7 +5,7 @@ Asynchronous tasks related to the Course Blocks sub-application.
import logging
from celery.task import task
from celery import shared_task
from django.conf import settings
from edx_django_utils.monitoring import set_code_owner_attribute
from edxval.api import ValInternalError
@@ -28,7 +28,7 @@ def block_structure_task(**kwargs):
"""
Decorator for block structure tasks.
"""
return task(
return shared_task(
default_retry_delay=settings.BLOCK_STRUCTURES_SETTINGS['TASK_DEFAULT_RETRY_DELAY'],
max_retries=settings.BLOCK_STRUCTURES_SETTINGS['TASK_MAX_RETRIES'],
bind=True,

View File

@@ -63,7 +63,7 @@ class MockXBlock(object):
try:
return self.field_map[attr]
except KeyError:
raise AttributeError
raise AttributeError # lint-amnesty, pylint: disable=raise-missing-from
def get_children(self):
"""
@@ -211,7 +211,7 @@ def clear_registered_transformers_cache():
"""
Test helper to clear out any cached values of registered transformers.
"""
TransformerRegistry.get_write_version_hash.cache.clear()
TransformerRegistry.get_write_version_hash.cache.clear() # lint-amnesty, pylint: disable=no-member
@contextmanager
@@ -224,7 +224,7 @@ def mock_registered_transformers(transformers):
'openedx.core.djangoapps.content.block_structure.transformer_registry.'
'TransformerRegistry.get_registered_transformers'
) as mock_available_transforms:
mock_available_transforms.return_value = {transformer for transformer in transformers}
mock_available_transforms.return_value = {transformer for transformer in transformers} # lint-amnesty, pylint: disable=unnecessary-comprehension
yield
@@ -336,7 +336,7 @@ class UsageKeyFactoryMixin(object):
ChildrenMapTestMixin use integers for block_ids.
"""
def setUp(self):
super(UsageKeyFactoryMixin, self).setUp()
super(UsageKeyFactoryMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.course_key = CourseLocator('org', 'course', six.text_type(uuid4()))
def block_key_factory(self, block_id):

View File

@@ -19,7 +19,7 @@ class TestBlockStructureFactory(TestCase, ChildrenMapTestMixin):
"""
def setUp(self):
super(TestBlockStructureFactory, self).setUp()
super(TestBlockStructureFactory, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.children_map = self.SIMPLE_CHILDREN_MAP
self.modulestore = MockModulestoreFactory.create(self.children_map, self.block_key_factory)

View File

@@ -102,7 +102,7 @@ class TestBlockStructureManager(UsageKeyFactoryMixin, ChildrenMapTestMixin, Test
"""
def setUp(self):
super(TestBlockStructureManager, self).setUp()
super(TestBlockStructureManager, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
TestTransformer1.collect_call_count = 0
self.registered_transformers = [TestTransformer1()]

View File

@@ -28,7 +28,7 @@ class BlockStructureModelTestCase(TestCase):
Tests for BlockStructureModel.
"""
def setUp(self):
super(BlockStructureModelTestCase, self).setUp()
super(BlockStructureModelTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.course_key = CourseLocator('org', 'course', six.text_type(uuid4()))
self.usage_key = BlockUsageLocator(course_key=self.course_key, block_type='course', block_id='course')
@@ -36,7 +36,7 @@ class BlockStructureModelTestCase(TestCase):
def tearDown(self):
BlockStructureModel._prune_files(self.usage_key, num_to_keep=0)
super(BlockStructureModelTestCase, self).tearDown()
super(BlockStructureModelTestCase, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments
def _assert_bsm_fields(self, bsm, expected_serialized_data):
"""
@@ -161,7 +161,7 @@ class BlockStructureModelTestCase(TestCase):
bs_model, _ = BlockStructureModel.update_or_create('test data', **self.params)
with self.assertRaises(expected_error_raised):
with _storage_error_handling(bs_model, 'operation', is_read_operation):
if errno_raised is not None:
if errno_raised is not None: # lint-amnesty, pylint: disable=no-else-raise
raise error_raised_in_operation(errno_raised, message_raised)
else:
raise error_raised_in_operation

View File

@@ -25,7 +25,7 @@ class CourseBlocksSignalTest(ModuleStoreTestCase):
ENABLED_SIGNALS = ['course_deleted', 'course_published']
def setUp(self):
super(CourseBlocksSignalTest, self).setUp()
super(CourseBlocksSignalTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.course = CourseFactory.create()
self.course_usage_key = self.store.make_course_usage_key(self.course.id)

View File

@@ -23,7 +23,7 @@ class TestBlockStructureStore(UsageKeyFactoryMixin, ChildrenMapTestMixin, CacheI
ENABLED_CACHES = ['default']
def setUp(self):
super(TestBlockStructureStore, self).setUp()
super(TestBlockStructureStore, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.children_map = self.SIMPLE_CHILDREN_MAP
self.block_structure = self.create_block_structure(self.children_map)

View File

@@ -15,21 +15,21 @@ class TestTransformer1(MockTransformer):
"""
1st test instance of the MockTransformer that is registered.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class TestTransformer2(MockTransformer):
"""
2nd test instance of the MockTransformer that is registered.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
class UnregisteredTestTransformer3(MockTransformer):
"""
3rd test instance of the MockTransformer that is not registered.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
@ddt.ddt
@@ -39,7 +39,7 @@ class TransformerRegistryTestCase(TestCase):
"""
def tearDown(self):
super(TransformerRegistryTestCase, self).tearDown()
super(TransformerRegistryTestCase, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments
clear_registered_transformers_cache()
@ddt.data(

View File

@@ -22,10 +22,10 @@ class TestBlockStructureTransformers(ChildrenMapTestMixin, TestCase):
"""
Mock transformer that is not registered.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
def setUp(self):
super(TestBlockStructureTransformers, self).setUp()
super(TestBlockStructureTransformers, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.transformers = BlockStructureTransformers(usage_info=MagicMock())
self.registered_transformers = [MockTransformer(), MockFilteringTransformer()]

View File

@@ -106,7 +106,7 @@ class BlockStructureTransformer(object):
block structure that is to be modified with collected
data to be cached for the transformer.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
@abstractmethod
def transform(self, usage_info, block_structure):

View File

@@ -3,7 +3,7 @@ Module for a collection of BlockStructureTransformers.
"""
import functools
import functools # lint-amnesty, pylint: disable=unused-import
from logging import getLogger
from .exceptions import TransformerDataIncompatible, TransformerException
@@ -100,7 +100,7 @@ class BlockStructureTransformers(object):
outdated_transformers.append(transformer)
if outdated_transformers:
raise TransformerDataIncompatible(
raise TransformerDataIncompatible( # lint-amnesty, pylint: disable=raising-format-tuple
u"Collected Block Structure data for the following transformers is outdated: '%s'.",
[(transformer.name(), transformer.READ_VERSION) for transformer in outdated_transformers],
)

View File

@@ -16,4 +16,4 @@ class CourseOverviewsConfig(AppConfig):
def ready(self):
# Import signals to activate signal handler which invalidates
# the CourseOverview cache every time a course is published.
from . import signals # pylint: disable=unused-variable
from . import signals # lint-amnesty, pylint: disable=unused-import, unused-variable

View File

@@ -73,4 +73,4 @@ class Command(BaseCommand):
**kwargs
)
except InvalidKeyError as exc:
raise CommandError(u'Invalid Course Key: ' + six.text_type(exc))
raise CommandError(u'Invalid Course Key: ' + six.text_type(exc)) # lint-amnesty, pylint: disable=raise-missing-from

View File

@@ -86,7 +86,7 @@ class Command(BaseCommand):
dest='show_receivers',
action='store_true',
help=(u'Display the list of possible receiver functions and exit.')
),
), # lint-amnesty, pylint: disable=trailing-comma-tuple
parser.add_argument(
'--dry-run',
dest='dry_run',
@@ -96,7 +96,7 @@ class Command(BaseCommand):
u"expensive modulestore query to find courses, but it will "
u"not emit any signals."
)
),
), # lint-amnesty, pylint: disable=trailing-comma-tuple
parser.add_argument(
'--receivers',
dest='receivers',
@@ -142,7 +142,7 @@ class Command(BaseCommand):
u"process. However, if you know what you're doing and need to "
u"override that behavior, use this flag."
)
),
), # lint-amnesty, pylint: disable=trailing-comma-tuple
parser.add_argument(
'--skip-ccx',
dest='skip_ccx',
@@ -156,12 +156,12 @@ class Command(BaseCommand):
u"if you know what you're doing, you can disable this behavior "
u"with this flag, so that CCX receivers are omitted."
)
),
), # lint-amnesty, pylint: disable=trailing-comma-tuple
parser.add_argument(
'--args-from-database',
action='store_true',
help='Use arguments from the SimulateCoursePublishConfig model instead of the command line.',
),
), # lint-amnesty, pylint: disable=trailing-comma-tuple
def get_args_from_database(self):
""" Returns an options dictionary from the current SimulateCoursePublishConfig model. """
@@ -194,7 +194,7 @@ class Command(BaseCommand):
if options['force_lms']:
log.info("Forcing simulate_publish to run in LMS process.")
else:
log.fatal(
log.fatal( # lint-amnesty, pylint: disable=logging-not-lazy
u"simulate_publish should be run as a CMS (Studio) " +
u"command, not %s (override with --force-lms).",
os.environ.get('SERVICE_VARIANT')
@@ -245,7 +245,7 @@ class Command(BaseCommand):
log.info(u"%d receivers specified: %s", len(receiver_names), ", ".join(receiver_names))
receiver_names_set = set(receiver_names)
for receiver_fn in get_receiver_fns():
if receiver_fn == ccx_receiver_fn and not skip_ccx:
if receiver_fn == ccx_receiver_fn and not skip_ccx: # lint-amnesty, pylint: disable=comparison-with-callable
continue
fn_name = name_from_fn(receiver_fn)
if fn_name not in receiver_names_set:

View File

@@ -22,7 +22,7 @@ class TestGenerateCourseOverview(ModuleStoreTestCase):
"""
Create courses in modulestore.
"""
super(TestGenerateCourseOverview, self).setUp()
super(TestGenerateCourseOverview, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.course_key_1 = CourseFactory.create().id
self.course_key_2 = CourseFactory.create().id
self.command = generate_course_overview.Command()

View File

@@ -47,7 +47,7 @@ class TestSimulatePublish(SharedModuleStoreTestCase):
might look like you can move this to setUpClass, but be very careful if
doing so, to make sure side-effects don't leak out between tests.
"""
super(TestSimulatePublish, self).setUp()
super(TestSimulatePublish, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
# Instead of using the process global SignalHandler.course_published, we
# create our own SwitchedSignal to manually send to.
@@ -79,7 +79,7 @@ class TestSimulatePublish(SharedModuleStoreTestCase):
)
Command.course_published_signal.disconnect(self.sample_receiver_1)
Command.course_published_signal.disconnect(self.sample_receiver_2)
super(TestSimulatePublish, self).tearDown()
super(TestSimulatePublish, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments
def options(self, **kwargs):
"""

View File

@@ -131,7 +131,7 @@ class CourseOverview(TimeStampedModel):
history = HistoricalRecords()
@classmethod
def _create_or_update(cls, course):
def _create_or_update(cls, course): # lint-amnesty, pylint: disable=too-many-statements
"""
Creates or updates a CourseOverview object from a CourseDescriptor.
@@ -184,7 +184,7 @@ class CourseOverview(TimeStampedModel):
course_overview.version = cls.VERSION
course_overview.id = course.id
course_overview._location = course.location
course_overview._location = course.location # lint-amnesty, pylint: disable=protected-access
course_overview.org = course.location.org
course_overview.display_name = display_name
course_overview.display_number_with_default = course.display_number_with_default
@@ -215,7 +215,7 @@ class CourseOverview(TimeStampedModel):
course_overview.days_early_for_beta = course.days_early_for_beta
course_overview.mobile_available = course.mobile_available
course_overview.visible_to_staff_only = course.visible_to_staff_only
course_overview._pre_requisite_courses_json = json.dumps(course.pre_requisite_courses)
course_overview._pre_requisite_courses_json = json.dumps(course.pre_requisite_courses) # lint-amnesty, pylint: disable=protected-access
course_overview.enrollment_start = course.enrollment_start
course_overview.enrollment_end = course.enrollment_end
@@ -306,7 +306,7 @@ class CourseOverview(TimeStampedModel):
return course_overview
elif course is not None:
raise IOError(
raise IOError( # lint-amnesty, pylint: disable=raising-format-tuple
"Error while loading CourseOverview for course {} "
"from the module store: {}",
six.text_type(course_id),
@@ -372,8 +372,14 @@ class CourseOverview(TimeStampedModel):
# Regenerate the thumbnail images if they're missing (either because
# they were never generated, or because they were flushed out after
# a change to CourseOverviewImageConfig.
if course_overview and not hasattr(course_overview, 'image_set'):
CourseOverviewImageSet.create(course_overview)
if course_overview:
if hasattr(course_overview, 'image_set'):
image_set = course_overview.image_set
if not image_set.small_url or not image_set.large_url:
CourseOverviewImageSet.objects.filter(course_overview=course_overview).delete()
CourseOverviewImageSet.create(course_overview)
else:
CourseOverviewImageSet.create(course_overview)
return course_overview or cls.load_from_module_store(course_id)
@@ -586,7 +592,7 @@ class CourseOverview(TimeStampedModel):
cause a lot of issues. These should not be mutable after
construction, so for now we just eat this.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
@classmethod
def update_select_courses(cls, course_keys, force_update=False):

View File

@@ -17,7 +17,7 @@ class CourseOverviewBaseSerializer(serializers.ModelSerializer):
fields = '__all__'
def to_representation(self, instance):
representation = super(CourseOverviewBaseSerializer, self).to_representation(instance)
representation = super(CourseOverviewBaseSerializer, self).to_representation(instance) # lint-amnesty, pylint: disable=super-with-arguments
representation['display_name_with_default'] = instance.display_name_with_default
representation['has_started'] = instance.has_started()
representation['has_ended'] = instance.has_ended()

View File

@@ -62,7 +62,7 @@ def _check_for_course_date_changes(previous_course_overview, updated_course_over
)
def _log_start_date_change(previous_course_overview, updated_course_overview):
def _log_start_date_change(previous_course_overview, updated_course_overview): # lint-amnesty, pylint: disable=missing-function-docstring
previous_start_str = 'None'
if previous_course_overview.start is not None:
previous_start_str = previous_course_overview.start.isoformat()

View File

@@ -1,9 +1,9 @@
# lint-amnesty, pylint: disable=missing-module-docstring
import logging
import six
from celery import task
from celery import shared_task
from celery_utils.persist_on_failure import LoggedPersistOnFailureTask
from django.conf import settings
from edx_django_utils.monitoring import set_code_owner_attribute
@@ -27,7 +27,7 @@ def chunks(sequence, chunk_size):
return (sequence[index: index + chunk_size] for index in range(0, len(sequence), chunk_size))
def _task_options(routing_key):
def _task_options(routing_key): # lint-amnesty, pylint: disable=missing-function-docstring
task_options = {}
if getattr(settings, 'HIGH_MEM_QUEUE', None):
task_options['routing_key'] = settings.HIGH_MEM_QUEUE
@@ -36,7 +36,7 @@ def _task_options(routing_key):
return task_options
def enqueue_async_course_overview_update_tasks(
def enqueue_async_course_overview_update_tasks( # lint-amnesty, pylint: disable=missing-function-docstring
course_ids,
all_courses=False,
force_update=False,
@@ -59,7 +59,7 @@ def enqueue_async_course_overview_update_tasks(
)
@task(base=LoggedPersistOnFailureTask)
@shared_task(base=LoggedPersistOnFailureTask)
@set_code_owner_attribute
def async_course_overview_update(*args, **kwargs):
course_keys = [CourseKey.from_string(arg) for arg in args]

View File

@@ -1,4 +1,4 @@
# lint-amnesty, pylint: disable=missing-module-docstring
from datetime import timedelta
import json
@@ -11,7 +11,7 @@ from opaque_keys.edx.locator import CourseLocator
from ..models import CourseOverview
class CourseOverviewFactory(DjangoModelFactory):
class CourseOverviewFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring
class Meta(object):
model = CourseOverview
django_get_or_create = ('id', )

View File

@@ -16,7 +16,7 @@ class TestCourseOverviewsApi(TestCase):
"""
def setUp(self):
super(TestCourseOverviewsApi, self).setUp()
super(TestCourseOverviewsApi, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
for _ in range(3):
CourseOverviewFactory.create()

View File

@@ -605,7 +605,7 @@ class CourseOverviewImageSetTestCase(ModuleStoreTestCase):
def setUp(self):
"""Create an active CourseOverviewImageConfig with non-default values."""
self.set_config(True)
super(CourseOverviewImageSetTestCase, self).setUp()
super(CourseOverviewImageSetTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
def _create_course_image(self, course, image_name):
"""

View File

@@ -16,7 +16,7 @@ class TestCourseOverviewSerializer(TestCase):
"""
def setUp(self):
super(TestCourseOverviewSerializer, self).setUp()
super(TestCourseOverviewSerializer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
CourseOverviewFactory.create()
def test_get_course_overview_serializer(self):

View File

@@ -1,4 +1,4 @@
# lint-amnesty, pylint: disable=missing-module-docstring
import datetime
@@ -70,7 +70,7 @@ class CourseOverviewSignalsTestCase(ModuleStoreTestCase):
self.store.delete_course(course.id, ModuleStoreEnum.UserID.test)
CourseOverview.get_from_id(course.id)
def assert_changed_signal_sent(self, field_name, initial_value, changed_value, mock_signal):
def assert_changed_signal_sent(self, field_name, initial_value, changed_value, mock_signal): # lint-amnesty, pylint: disable=missing-function-docstring
course = CourseFactory.create(emit_signals=True, **{field_name: initial_value})
# changing display name doesn't fire the signal

View File

@@ -1,4 +1,4 @@
# lint-amnesty, pylint: disable=missing-module-docstring
import mock
import six
@@ -10,9 +10,9 @@ from xmodule.modulestore.tests.factories import CourseFactory
from ..tasks import enqueue_async_course_overview_update_tasks
class BatchedAsyncCourseOverviewUpdateTests(ModuleStoreTestCase):
class BatchedAsyncCourseOverviewUpdateTests(ModuleStoreTestCase): # lint-amnesty, pylint: disable=missing-class-docstring
def setUp(self):
super(BatchedAsyncCourseOverviewUpdateTests, self).setUp()
super(BatchedAsyncCourseOverviewUpdateTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.course_1 = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo)
self.course_2 = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo)
self.course_3 = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo)

View File

@@ -1,3 +1,4 @@
# lint-amnesty, pylint: disable=missing-module-docstring
from .outlines import (
get_course_outline,
get_user_course_outline,

View File

@@ -6,14 +6,14 @@ __init__.py imports from here, and is a more stable place to import from.
import logging
from collections import defaultdict
from datetime import datetime
from typing import Optional
from typing import Optional # lint-amnesty, pylint: disable=unused-import
import attr
import attr # lint-amnesty, pylint: disable=unused-import
from django.contrib.auth import get_user_model
from django.db import transaction
from edx_django_utils.cache import TieredCache, get_cache_key
from edx_django_utils.cache import TieredCache, get_cache_key # lint-amnesty, pylint: disable=unused-import
from edx_django_utils.monitoring import function_trace
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys.edx.keys import CourseKey, UsageKey # lint-amnesty, pylint: disable=unused-import
from ..data import (
CourseLearningSequenceData,
@@ -153,7 +153,7 @@ def _get_course_context_for_outline(course_key: CourseKey) -> CourseContext:
)
except LearningContext.DoesNotExist:
# Could happen if it hasn't been published.
raise CourseOutlineData.DoesNotExist(
raise CourseOutlineData.DoesNotExist( # lint-amnesty, pylint: disable=raise-missing-from
"No CourseOutlineData for {}".format(course_key)
)
return course_context
@@ -197,7 +197,7 @@ def get_user_course_outline_details(course_key: CourseKey,
)
def _get_user_course_outline_and_processors(course_key: CourseKey,
def _get_user_course_outline_and_processors(course_key: CourseKey, # lint-amnesty, pylint: disable=missing-function-docstring
user: User,
at_time: datetime):
full_course_outline = get_course_outline(course_key)

View File

@@ -6,7 +6,7 @@ import logging
from datetime import datetime
from django.contrib.auth import get_user_model
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys.edx.keys import CourseKey, UsageKey # lint-amnesty, pylint: disable=unused-import
User = get_user_model()
log = logging.getLogger(__name__)
@@ -57,9 +57,9 @@ class OutlineProcessor:
tens of milliseconds, even on courses with hundreds of learning
sequences.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
def inaccessible_sequences(self, full_course_outline):
def inaccessible_sequences(self, full_course_outline): # lint-amnesty, pylint: disable=unused-argument
"""
Return a set/frozenset of Sequence UsageKeys that are not accessible.
@@ -68,7 +68,7 @@ class OutlineProcessor:
"""
return frozenset()
def usage_keys_to_remove(self, full_course_outline):
def usage_keys_to_remove(self, full_course_outline): # lint-amnesty, pylint: disable=unused-argument
"""
Return a set/frozenset of UsageKeys to remove altogether.

View File

@@ -1,3 +1,4 @@
# lint-amnesty, pylint: disable=missing-module-docstring
import logging
from datetime import datetime

View File

@@ -1,7 +1,8 @@
# lint-amnesty, pylint: disable=missing-module-docstring
import logging
from django.contrib.auth import get_user_model
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.keys import CourseKey # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.util import milestones_helpers
from .base import OutlineProcessor

View File

@@ -1,10 +1,11 @@
# lint-amnesty, pylint: disable=missing-module-docstring
import logging
from collections import defaultdict, OrderedDict
from collections import defaultdict, OrderedDict # lint-amnesty, pylint: disable=unused-import
from datetime import datetime, timedelta
from django.contrib.auth import get_user_model
from edx_when.api import get_dates_for_course
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys.edx.keys import CourseKey, UsageKey # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.student.auth import user_has_role
from common.djangoapps.student.roles import CourseBetaTesterRole
@@ -119,7 +120,7 @@ class ScheduleOutlineProcessor(OutlineProcessor):
specified_dates = [date for date in dates if date is not None]
return max(specified_dates) if specified_dates else None
pruned_section_keys = {section.usage_key for section in pruned_course_outline.sections}
pruned_section_keys = {section.usage_key for section in pruned_course_outline.sections} # lint-amnesty, pylint: disable=unused-variable
course_usage_key = self.course_key.make_usage_key('course', 'course')
course_start = self.keys_to_schedule_fields[course_usage_key].get('start')
course_end = self.keys_to_schedule_fields[course_usage_key].get('end')

View File

@@ -32,7 +32,7 @@ class SpecialExamsOutlineProcessor(OutlineProcessor):
"""
Check if special exams are enabled
"""
self.special_exams_enabled = settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False)
self.special_exams_enabled = settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) # lint-amnesty, pylint: disable=attribute-defined-outside-init
def exam_data(self, pruned_course_outline: UserCourseOutlineData) -> SpecialExamAttemptData:
"""

View File

@@ -1,3 +1,4 @@
# lint-amnesty, pylint: disable=missing-module-docstring
from datetime import datetime, timezone
from unittest import TestCase
@@ -22,7 +23,7 @@ class TestCourseOutlineData(TestCase):
test as needed.
"""
super().setUpClass()
normal_visibility = VisibilityData(
normal_visibility = VisibilityData( # lint-amnesty, pylint: disable=unused-variable
hide_from_toc=False,
visible_to_staff_only=False
)

View File

@@ -7,18 +7,18 @@ from mock import patch
import attr
from django.conf import settings
from django.contrib.auth.models import AnonymousUser, User
from django.contrib.auth.models import AnonymousUser, User # lint-amnesty, pylint: disable=imported-auth-user
from edx_proctoring.exceptions import ProctoredExamNotFoundException
from edx_when.api import set_dates_for_course
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys.edx.locator import BlockUsageLocator
from opaque_keys.edx.keys import CourseKey, UsageKey # lint-amnesty, pylint: disable=unused-import
from opaque_keys.edx.locator import BlockUsageLocator # lint-amnesty, pylint: disable=unused-import
from edx_toggles.toggles.testutils import override_waffle_flag
from lms.djangoapps.courseware.tests.factories import BetaTesterFactory
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from openedx.features.course_experience import COURSE_ENABLE_UNENROLLED_ACCESS_FLAG
from common.djangoapps.student.auth import user_has_role
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.models import CourseEnrollment # lint-amnesty, pylint: disable=unused-import
from common.djangoapps.student.roles import CourseBetaTesterRole
from ...data import (
@@ -43,9 +43,9 @@ class CourseOutlineTestCase(CacheIsolationTestCase):
Simple tests around reading and writing CourseOutlineData. No user info.
"""
@classmethod
def setUpTestData(cls):
def setUpTestData(cls): # lint-amnesty, pylint: disable=super-method-not-called
cls.course_key = CourseKey.from_string("course-v1:OpenEdX+Learn+Roundtrip")
normal_visibility = VisibilityData(
normal_visibility = VisibilityData( # lint-amnesty, pylint: disable=unused-variable
hide_from_toc=False,
visible_to_staff_only=False
)
@@ -65,12 +65,12 @@ class CourseOutlineTestCase(CacheIsolationTestCase):
"""Don't allow Old Mongo Courses at all."""
old_course_key = CourseKey.from_string("Org/Course/Run")
with self.assertRaises(ValueError):
outline = get_course_outline(old_course_key)
outline = get_course_outline(old_course_key) # lint-amnesty, pylint: disable=unused-variable
def test_simple_roundtrip(self):
"""Happy path for writing/reading-back a course outline."""
with self.assertRaises(CourseOutlineData.DoesNotExist):
course_outline = get_course_outline(self.course_key)
course_outline = get_course_outline(self.course_key) # lint-amnesty, pylint: disable=unused-variable
replace_course_outline(self.course_outline)
outline = get_course_outline(self.course_key)
@@ -120,8 +120,8 @@ class CourseOutlineTestCase(CacheIsolationTestCase):
# Make sure this new outline is returned instead of the previously
# cached one.
with self.assertNumQueries(3):
uncached_new_version_outline = get_course_outline(self.course_key)
assert new_version_outline == new_version_outline
uncached_new_version_outline = get_course_outline(self.course_key) # lint-amnesty, pylint: disable=unused-variable
assert new_version_outline == new_version_outline # lint-amnesty, pylint: disable=comparison-with-itself
class UserCourseOutlineTestCase(CacheIsolationTestCase):
@@ -130,7 +130,7 @@ class UserCourseOutlineTestCase(CacheIsolationTestCase):
"""
@classmethod
def setUpTestData(cls):
def setUpTestData(cls): # lint-amnesty, pylint: disable=super-method-not-called
course_key = CourseKey.from_string("course-v1:OpenEdX+Outline+T1")
# Users...
cls.global_staff = User.objects.create_user(
@@ -194,9 +194,9 @@ class UserCourseOutlineTestCase(CacheIsolationTestCase):
assert global_staff_outline_details.outline == global_staff_outline
class OutlineProcessorTestCase(CacheIsolationTestCase):
class OutlineProcessorTestCase(CacheIsolationTestCase): # lint-amnesty, pylint: disable=missing-class-docstring
@classmethod
def setUpTestData(cls):
def setUpTestData(cls): # lint-amnesty, pylint: disable=super-method-not-called
cls.course_key = CourseKey.from_string("course-v1:OpenEdX+Outline+T1")
# Users...
@@ -221,7 +221,7 @@ class OutlineProcessorTestCase(CacheIsolationTestCase):
def set_sequence_keys(cls, keys):
cls.all_seq_keys = keys
def get_sequence_keys(self, exclude=None):
def get_sequence_keys(self, exclude=None): # lint-amnesty, pylint: disable=missing-function-docstring
if exclude is None:
exclude = []
if not isinstance(exclude, list):
@@ -346,10 +346,10 @@ class ContentGatingTestCase(OutlineProcessorTestCase):
"""
Currently returns all, and only, sequences in required content, not just the first.
This logic matches the existing transformer. Is this right?
"""
""" # lint-amnesty, pylint: disable=pointless-string-statement
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.EntranceExamConfiguration.user_can_skip_entrance_exam')
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.milestones_helpers.get_required_content')
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.EntranceExamConfiguration.user_can_skip_entrance_exam') # lint-amnesty, pylint: disable=line-too-long
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.milestones_helpers.get_required_content') # lint-amnesty, pylint: disable=line-too-long
def test_user_can_skip_entrance_exam(self, required_content_mock, user_can_skip_entrance_exam_mock):
required_content_mock.return_value = [str(self.entrance_exam_section_key)]
user_can_skip_entrance_exam_mock.return_value = True
@@ -363,8 +363,8 @@ class ContentGatingTestCase(OutlineProcessorTestCase):
# Student can access all sequences
assert len(student_details.outline.accessible_sequences) == 3
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.EntranceExamConfiguration.user_can_skip_entrance_exam')
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.milestones_helpers.get_required_content')
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.EntranceExamConfiguration.user_can_skip_entrance_exam') # lint-amnesty, pylint: disable=line-too-long
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.content_gating.milestones_helpers.get_required_content') # lint-amnesty, pylint: disable=line-too-long
def test_user_can_not_skip_entrance_exam(self, required_content_mock, user_can_skip_entrance_exam_mock):
required_content_mock.return_value = [str(self.entrance_exam_section_key)]
user_can_skip_entrance_exam_mock.return_value = False
@@ -460,7 +460,7 @@ class MilestonesTestCase(OutlineProcessorTestCase):
# Enroll student in the course
cls.student.courseenrollment_set.create(course_id=cls.course_key, is_active=True, mode="audit")
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.milestones.milestones_helpers.get_course_content_milestones')
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.milestones.milestones_helpers.get_course_content_milestones') # lint-amnesty, pylint: disable=line-too-long
def test_user_can_skip_entrance_exam(self, get_course_content_milestones_mock):
# Only return that there are milestones required for the
# milestones_required_seq_key usage key
@@ -763,7 +763,7 @@ class ScheduleTestCase(OutlineProcessorTestCase):
assert len(beta_tester_details.outline.accessible_sequences) == 4
class SelfPacedTestCase(OutlineProcessorTestCase):
class SelfPacedTestCase(OutlineProcessorTestCase): # lint-amnesty, pylint: disable=missing-class-docstring
@classmethod
def setUpTestData(cls):
@@ -844,7 +844,7 @@ class SelfPacedTestCase(OutlineProcessorTestCase):
cls.student.courseenrollment_set.create(course_id=cls.course_key, is_active=True, mode="audit")
def test_sequences_accessible_after_due(self):
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc)
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc) # lint-amnesty, pylint: disable=unused-variable
staff_details, student_details, _ = self.get_details(
datetime(2020, 5, 25, tzinfo=timezone.utc)
@@ -859,7 +859,7 @@ class SelfPacedTestCase(OutlineProcessorTestCase):
assert len(student_details.outline.accessible_sequences) == 2
class SpecialExamsTestCase(OutlineProcessorTestCase):
class SpecialExamsTestCase(OutlineProcessorTestCase): # lint-amnesty, pylint: disable=missing-class-docstring
@classmethod
def setUpTestData(cls):
@@ -964,7 +964,7 @@ class SpecialExamsTestCase(OutlineProcessorTestCase):
@patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': True})
def test_special_exams_enabled_all_sequences_visible(self):
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc)
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc) # lint-amnesty, pylint: disable=unused-variable
staff_details, student_details, _ = self.get_details(
datetime(2020, 5, 25, tzinfo=timezone.utc)
@@ -980,7 +980,7 @@ class SpecialExamsTestCase(OutlineProcessorTestCase):
@patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': False})
def test_special_exams_disabled_preserves_exam_sequences(self):
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc)
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc) # lint-amnesty, pylint: disable=unused-variable
staff_details, student_details, _ = self.get_details(
datetime(2020, 5, 25, tzinfo=timezone.utc)
@@ -1000,7 +1000,7 @@ class SpecialExamsTestCase(OutlineProcessorTestCase):
@patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': True})
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.special_exams.get_attempt_status_summary')
def test_special_exam_attempt_data_in_details(self, mock_get_attempt_status_summary):
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc)
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc) # lint-amnesty, pylint: disable=unused-variable
def get_attempt_status_side_effect(user_id, _course_key, usage_key):
"""
@@ -1011,7 +1011,7 @@ class SpecialExamsTestCase(OutlineProcessorTestCase):
for sequence_key in self.get_sequence_keys(exclude=[self.seq_normal_key]):
if usage_key == str(sequence_key):
num_fake_attempts = mock_get_attempt_status_summary.call_count % len(self.all_seq_keys)
num_fake_attempts = mock_get_attempt_status_summary.call_count % len(self.all_seq_keys) # lint-amnesty, pylint: disable=unused-variable
return {
"summary": {
"usage_key": usage_key
@@ -1028,13 +1028,13 @@ class SpecialExamsTestCase(OutlineProcessorTestCase):
for sequence_key in self.get_sequence_keys(exclude=[self.seq_normal_key]):
assert sequence_key in student_details.special_exam_attempts.sequences
attempt_summary = student_details.special_exam_attempts.sequences[sequence_key]
assert type(attempt_summary) == dict
assert type(attempt_summary) == dict # lint-amnesty, pylint: disable=unidiomatic-typecheck
assert attempt_summary["summary"]["usage_key"] == str(sequence_key)
@patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': False})
@patch('openedx.core.djangoapps.content.learning_sequences.api.processors.special_exams.get_attempt_status_summary')
def test_special_exam_attempt_data_empty_when_disabled(self, mock_get_attempt_status_summary):
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc)
at_time = datetime(2020, 5, 22, tzinfo=timezone.utc) # lint-amnesty, pylint: disable=unused-variable
_, student_details, _ = self.get_details(
datetime(2020, 5, 25, tzinfo=timezone.utc)
@@ -1130,7 +1130,7 @@ class VisbilityTestCase(OutlineProcessorTestCase):
cls.student.courseenrollment_set.create(course_id=cls.course_key, is_active=True, mode="audit")
def test_visibility(self):
at_time = datetime(2020, 5, 21, tzinfo=timezone.utc) # Exact value doesn't matter
at_time = datetime(2020, 5, 21, tzinfo=timezone.utc) # Exact value doesn't matter # lint-amnesty, pylint: disable=unused-variable
staff_details, student_details, _ = self.get_details(
datetime(2020, 5, 25, tzinfo=timezone.utc)

View File

@@ -1,8 +1,9 @@
# lint-amnesty, pylint: disable=missing-module-docstring
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class LearningSequencesConfig(AppConfig):
class LearningSequencesConfig(AppConfig): # lint-amnesty, pylint: disable=missing-class-docstring
name = 'openedx.core.djangoapps.content.learning_sequences'
verbose_name = _('Learning Sequences')

View File

@@ -24,7 +24,7 @@ Note: we're using old-style syntax for attrs because we need to support Python
TODO: Validate all datetimes to be UTC.
"""
import logging
from datetime import datetime, timezone
from datetime import datetime, timezone # lint-amnesty, pylint: disable=unused-import
from enum import Enum
from typing import Dict, List, Optional, Set
@@ -47,7 +47,7 @@ class ObjectDoesNotExist(Exception):
Imitating Django model conventions, we put a subclass of this in some of our
data classes to indicate when something is not found.
"""
pass
pass # lint-amnesty, pylint: disable=unnecessary-pass
@attr.s(frozen=True)
@@ -168,7 +168,7 @@ class CourseOutlineData:
sequences = {}
for section in self.sections:
for seq in section.sequences:
if seq.usage_key in sequences:
if seq.usage_key in sequences: # lint-amnesty, pylint: disable=no-else-raise
raise ValueError(
"Sequence {} appears in more than one Section."
.format(seq.usage_key)
@@ -220,7 +220,7 @@ class CourseOutlineData:
)
@days_early_for_beta.validator
def validate_days_early_for_beta(self, attribute, value):
def validate_days_early_for_beta(self, attribute, value): # lint-amnesty, pylint: disable=unused-argument
"""
Ensure that days_early_for_beta isn't negative.
"""

View File

@@ -40,7 +40,7 @@ not guaranteed to stick around, and values may be deleted unexpectedly.
from django.db import models
from model_utils.models import TimeStampedModel
from opaque_keys.edx.django.models import (
from opaque_keys.edx.django.models import ( # lint-amnesty, pylint: disable=unused-import
CourseKeyField, LearningContextKeyField, UsageKeyField
)
from .data import CourseVisibility

View File

@@ -15,8 +15,8 @@ from this app, edx-when's set_dates_for_course).
"""
from datetime import datetime, timezone
from django.contrib.auth.models import User
from opaque_keys.edx.keys import CourseKey, UsageKey
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user, unused-import
from opaque_keys.edx.keys import CourseKey, UsageKey # lint-amnesty, pylint: disable=unused-import
from rest_framework.test import APITestCase, APIClient
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
@@ -27,10 +27,10 @@ from ..data import CourseOutlineData, CourseVisibility
from ..api.tests.test_data import generate_sections
class CourseOutlineViewTest(CacheIsolationTestCase, APITestCase):
class CourseOutlineViewTest(CacheIsolationTestCase, APITestCase): # lint-amnesty, pylint: disable=missing-class-docstring
@classmethod
def setUpTestData(cls):
def setUpTestData(cls): # lint-amnesty, pylint: disable=super-method-not-called
cls.staff = UserFactory.create(
username='staff', email='staff@example.com', is_staff=True, password='staff_pass'
)

View File

@@ -1,3 +1,4 @@
# lint-amnesty, pylint: disable=missing-module-docstring
from django.conf.urls import url
from .views import CourseOutlineView

View File

@@ -3,7 +3,7 @@ The views.py for this app is intentionally thin, and only exists to translate
user input/output to and from the business logic in the `api` package.
"""
from datetime import datetime, timezone
import json
import json # lint-amnesty, pylint: disable=unused-import
import logging
from django.conf import settings
@@ -15,7 +15,7 @@ from opaque_keys.edx.keys import CourseKey
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
import attr
import attr # lint-amnesty, pylint: disable=unused-import
from openedx.core.lib.api.permissions import IsStaff
from .api import get_user_course_outline_details
@@ -34,7 +34,7 @@ class CourseOutlineView(APIView):
# For early testing, restrict this to only global staff...
permission_classes = (IsStaff,)
class UserCourseOutlineDataSerializer(serializers.BaseSerializer):
class UserCourseOutlineDataSerializer(serializers.BaseSerializer): # lint-amnesty, pylint: disable=abstract-method
"""
Read-only serializer for CourseOutlineData for this endpoint.
@@ -54,7 +54,7 @@ class CourseOutlineView(APIView):
are a critical part of the internals of edx-platform, so the in-process
API uses them, but we translate them to "ids" for REST API clients.
"""
def to_representation(self, user_course_outline_details):
def to_representation(self, user_course_outline_details): # lint-amnesty, pylint: disable=arguments-differ
"""
Convert to something DRF knows how to serialize (so no custom types)
@@ -150,7 +150,7 @@ class CourseOutlineView(APIView):
**schedule_item_dict,
}
def get(self, request, course_key_str, format=None):
def get(self, request, course_key_str, format=None): # lint-amnesty, pylint: disable=redefined-builtin, unused-argument
"""
The CourseOutline, customized for a given user.
@@ -169,11 +169,11 @@ class CourseOutlineView(APIView):
serializer = self.UserCourseOutlineDataSerializer(user_course_outline_details)
return Response(serializer.data)
def _validate_course_key(self, course_key_str):
def _validate_course_key(self, course_key_str): # lint-amnesty, pylint: disable=missing-function-docstring
try:
course_key = CourseKey.from_string(course_key_str)
except InvalidKeyError:
raise serializers.ValidationError(
raise serializers.ValidationError( # lint-amnesty, pylint: disable=raise-missing-from
"{} is not a valid CourseKey".format(course_key_str)
)
if course_key.deprecated:

View File

@@ -222,7 +222,7 @@ class LibraryBundleLink:
opaque_key = attr.ib(type=LearningContextKey, default=None)
class AccessLevel:
class AccessLevel: # lint-amnesty, pylint: disable=function-redefined
""" Enum defining library access levels/permissions """
ADMIN_LEVEL = ContentLibraryPermission.ADMIN_LEVEL
AUTHOR_LEVEL = ContentLibraryPermission.AUTHOR_LEVEL
@@ -407,7 +407,7 @@ def create_library(
)
except IntegrityError:
delete_bundle(bundle.uuid)
raise LibraryAlreadyExists(slug)
raise LibraryAlreadyExists(slug) # lint-amnesty, pylint: disable=raise-missing-from
CONTENT_LIBRARY_CREATED.send(sender=None, library_key=ref.library_key)
return ContentLibraryMetadata(
key=ref.library_key,
@@ -1015,7 +1015,7 @@ def update_bundle_link(library_key, link_id, version=None, delete=False):
try:
link = links[link_id]
except KeyError:
raise InvalidNameError("That link does not exist.")
raise InvalidNameError("That link does not exist.") # lint-amnesty, pylint: disable=raise-missing-from
if version is None:
version = get_bundle(link.bundle_uuid).latest_version
set_draft_link(draft.uuid, link_id, link.bundle_uuid, version)

View File

@@ -3,7 +3,7 @@ Helper code for working with Blockstore bundles that contain OLX
"""
import dateutil.parser
import logging
import logging # lint-amnesty, pylint: disable=wrong-import-order
from django.utils.lru_cache import lru_cache
from opaque_keys.edx.locator import BundleDefinitionLocator, LibraryUsageLocatorV2

View File

@@ -27,7 +27,7 @@ class LibraryContextImpl(LearningContext):
"""
def __init__(self, **kwargs):
super(LibraryContextImpl, self).__init__(**kwargs)
super(LibraryContextImpl, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
self.use_draft = kwargs.get('use_draft', None)
def can_edit_block(self, user, usage_key):
@@ -88,7 +88,7 @@ class LibraryContextImpl(LearningContext):
bundle_uuid = bundle_uuid_for_library_key(library_key)
except ContentLibrary.DoesNotExist:
return None
if 'force_draft' in kwargs:
if 'force_draft' in kwargs: # lint-amnesty, pylint: disable=consider-using-get
use_draft = kwargs['force_draft']
else:
use_draft = self.use_draft

View File

@@ -1,4 +1,4 @@
""" Management command to update content libraries' search index """
""" Management command to update content libraries' search index """ # lint-amnesty, pylint: disable=cyclic-import
import logging

View File

@@ -11,8 +11,8 @@ from openedx.core.djangoapps.content_libraries.constants import (
LIBRARY_TYPES, COMPLEX, LICENSE_OPTIONS,
ALL_RIGHTS_RESERVED,
)
from organizations.models import Organization
import six
from organizations.models import Organization # lint-amnesty, pylint: disable=wrong-import-order
import six # lint-amnesty, pylint: disable=wrong-import-order
User = get_user_model()
@@ -113,7 +113,7 @@ class ContentLibraryPermission(models.Model):
('library', 'group'),
]
def save(self, *args, **kwargs): # pylint: disable=arguments-differ
def save(self, *args, **kwargs): # lint-amnesty, pylint: disable=arguments-differ, signature-differs
"""
Validate any constraints on the model.

View File

@@ -3,7 +3,7 @@ Permissions for Content Libraries (v2, Blockstore-based)
"""
from bridgekeeper import perms, rules
from bridgekeeper.rules import Attribute, ManyRelation, Relation, in_current_groups
from django.contrib.auth.models import Group
from django.contrib.auth.models import Group # lint-amnesty, pylint: disable=unused-import
from openedx.core.djangoapps.content_libraries.models import ContentLibraryPermission

View File

@@ -176,7 +176,7 @@ class LibraryXBlockStaticFileSerializer(serializers.Serializer):
"""
Generate the serialized representation of this static asset file.
"""
result = super(LibraryXBlockStaticFileSerializer, self).to_representation(instance)
result = super(LibraryXBlockStaticFileSerializer, self).to_representation(instance) # lint-amnesty, pylint: disable=super-with-arguments
# Make sure the URL is one that will work from the user's browser,
# not one that only works from within a docker container:
result['url'] = blockstore_api.force_browser_url(result['url'])

View File

@@ -728,7 +728,7 @@ class ContentLibrariesTest(ContentLibrariesRestApiTest):
Test that libraries don't allow more than specified blocks
"""
with self.settings(MAX_BLOCKS_PER_CONTENT_LIBRARY=1):
lib = self._create_library(slug="test_lib_limits", title="Limits Test Library", description="Testing XBlocks limits in a library")
lib = self._create_library(slug="test_lib_limits", title="Limits Test Library", description="Testing XBlocks limits in a library") # lint-amnesty, pylint: disable=line-too-long
lib_id = lib["id"]
block_data = self._add_block_to_library(lib_id, "unit", "unit1")
# Second block should throw error

View File

@@ -184,7 +184,7 @@ class ContentLibraryXBlockUserStateTest(ContentLibraryContentTestMixin, TestCase
if the library allows direct learning.
"""
databases = {alias for alias in connections}
databases = {alias for alias in connections} # lint-amnesty, pylint: disable=unnecessary-comprehension
@XBlock.register_temp_plugin(UserStateTestBlock, UserStateTestBlock.BLOCK_TYPE)
def test_default_values(self):
@@ -488,7 +488,7 @@ class ContentLibraryXBlockCompletionTest(ContentLibraryContentTestMixin, Complet
"""
def setUp(self):
super(ContentLibraryXBlockCompletionTest, self).setUp()
super(ContentLibraryXBlockCompletionTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
# Enable the completion waffle flag for these tests
self.override_waffle_switch(True)

View File

@@ -55,19 +55,19 @@ def convert_exceptions(fn):
return fn(*args, **kwargs)
except api.ContentLibraryNotFound:
log.exception("Content library not found")
raise NotFound
raise NotFound # lint-amnesty, pylint: disable=raise-missing-from
except api.ContentLibraryBlockNotFound:
log.exception("XBlock not found in content library")
raise NotFound
raise NotFound # lint-amnesty, pylint: disable=raise-missing-from
except api.LibraryBlockAlreadyExists as exc:
log.exception(str(exc))
raise ValidationError(str(exc))
raise ValidationError(str(exc)) # lint-amnesty, pylint: disable=raise-missing-from
except api.InvalidNameError as exc:
log.exception(str(exc))
raise ValidationError(str(exc))
raise ValidationError(str(exc)) # lint-amnesty, pylint: disable=raise-missing-from
except api.BlockLimitReachedError as exc:
log.exception(str(exc))
raise ValidationError(str(exc))
raise ValidationError(str(exc)) # lint-amnesty, pylint: disable=raise-missing-from
return wrapped_fn
@@ -166,14 +166,14 @@ class LibraryRootView(APIView):
try:
ensure_organization(org_name)
except InvalidOrganizationException:
raise ValidationError(
raise ValidationError( # lint-amnesty, pylint: disable=raise-missing-from
detail={"org": "No such organization '{}' found.".format(org_name)}
)
org = Organization.objects.get(short_name=org_name)
try:
result = api.create_library(org=org, **data)
except api.LibraryAlreadyExists:
raise ValidationError(detail={"slug": "A library with that ID already exists."})
raise ValidationError(detail={"slug": "A library with that ID already exists."}) # lint-amnesty, pylint: disable=raise-missing-from
# Grant the current user admin permissions on the library:
api.set_library_user_permissions(result.key, request.user, api.AccessLevel.ADMIN_LEVEL)
return Response(ContentLibraryMetadataSerializer(result).data)
@@ -212,7 +212,7 @@ class LibraryDetailsView(APIView):
try:
api.update_library(key, **data)
except api.IncompatibleTypesError as err:
raise ValidationError({'type': str(err)})
raise ValidationError({'type': str(err)}) # lint-amnesty, pylint: disable=raise-missing-from
result = api.get_library(key)
return Response(ContentLibraryMetadataSerializer(result).data)
@@ -249,7 +249,7 @@ class LibraryTeamView(APIView):
try:
user = User.objects.get(email=serializer.validated_data.get('email'))
except User.DoesNotExist:
raise ValidationError({'email': _('We could not find a user with that email address.')})
raise ValidationError({'email': _('We could not find a user with that email address.')}) # lint-amnesty, pylint: disable=raise-missing-from
grant = api.get_library_user_permissions(key, user)
if grant:
return Response(
@@ -259,7 +259,7 @@ class LibraryTeamView(APIView):
try:
api.set_library_user_permissions(key, user, access_level=serializer.validated_data["access_level"])
except api.LibraryPermissionIntegrityError as err:
raise ValidationError(detail=str(err))
raise ValidationError(detail=str(err)) # lint-amnesty, pylint: disable=raise-missing-from
grant = api.get_library_user_permissions(key, user)
return Response(ContentLibraryPermissionSerializer(grant).data)
@@ -295,7 +295,7 @@ class LibraryTeamUserView(APIView):
try:
api.set_library_user_permissions(key, user, access_level=serializer.validated_data["access_level"])
except api.LibraryPermissionIntegrityError as err:
raise ValidationError(detail=str(err))
raise ValidationError(detail=str(err)) # lint-amnesty, pylint: disable=raise-missing-from
grant = api.get_library_user_permissions(key, user)
return Response(ContentLibraryPermissionSerializer(grant).data)
@@ -324,7 +324,7 @@ class LibraryTeamUserView(APIView):
try:
api.set_library_user_permissions(key, user, access_level=None)
except api.LibraryPermissionIntegrityError as err:
raise ValidationError(detail=str(err))
raise ValidationError(detail=str(err)) # lint-amnesty, pylint: disable=raise-missing-from
return Response({})
@@ -542,7 +542,7 @@ class LibraryBlocksView(APIView):
try:
result = api.create_library_block(library_key, **serializer.validated_data)
except api.IncompatibleTypesError as err:
raise ValidationError(
raise ValidationError( # lint-amnesty, pylint: disable=raise-missing-from
detail={'block_type': str(err)},
)
return Response(LibraryXBlockMetadataSerializer(result).data)
@@ -613,7 +613,7 @@ class LibraryBlockOlxView(APIView):
try:
api.set_library_block_olx(key, new_olx_str)
except ValueError as err:
raise ValidationError(detail=str(err))
raise ValidationError(detail=str(err)) # lint-amnesty, pylint: disable=raise-missing-from
return Response(LibraryXBlockOlxSerializer({"olx": new_olx_str}).data)
@@ -672,7 +672,7 @@ class LibraryBlockAssetView(APIView):
try:
result = api.add_library_block_static_asset_file(usage_key, file_path, file_content)
except ValueError:
raise ValidationError("Invalid file path")
raise ValidationError("Invalid file path") # lint-amnesty, pylint: disable=raise-missing-from
return Response(LibraryXBlockStaticFileSerializer(result).data)
@convert_exceptions
@@ -687,5 +687,5 @@ class LibraryBlockAssetView(APIView):
try:
api.delete_library_block_static_asset_file(usage_key, file_path)
except ValueError:
raise ValidationError("Invalid file path")
raise ValidationError("Invalid file path") # lint-amnesty, pylint: disable=raise-missing-from
return Response(status=status.HTTP_204_NO_CONTENT)

View File

@@ -1,3 +1,3 @@
"""
""" # lint-amnesty, pylint: disable=django-not-configured
Serves course assets to end users.
"""

View File

@@ -63,7 +63,7 @@ class StaticContentServer(MiddlewareMixin):
"""Process the given request"""
asset_path = request.path
if self.is_asset_request(request):
if self.is_asset_request(request): # lint-amnesty, pylint: disable=too-many-nested-blocks
# Make sure we can convert this request into a location.
if AssetLocator.CANONICAL_NAMESPACE in asset_path:
asset_path = asset_path.replace('block/', 'block@', 1)
@@ -292,7 +292,7 @@ class StaticContentServer(MiddlewareMixin):
# Not in cache, so just try and load it from the asset manager.
try:
content = AssetManager.find(location, as_stream=True)
except (ItemNotFoundError, NotFoundError):
except (ItemNotFoundError, NotFoundError): # lint-amnesty, pylint: disable=try-except-raise
raise
# Now that we fetched it, let's go ahead and try to cache it. We cap this at 1MB
@@ -324,7 +324,7 @@ def parse_range_header(header_value, content_length):
for byte_range_string in byte_ranges_string.split(','):
byte_range_string = byte_range_string.strip()
# Case 0:
if '-' not in byte_range_string: # Invalid syntax of header value.
if '-' not in byte_range_string: # Invalid syntax of header value. # lint-amnesty, pylint: disable=no-else-raise
raise ValueError('Invalid syntax.')
# Case 1: -500
elif byte_range_string.startswith('-'):

View File

@@ -7,10 +7,10 @@ import copy
import datetime
import ddt
import logging
import logging # lint-amnesty, pylint: disable=wrong-import-order
import six
import unittest
from uuid import uuid4
import unittest # lint-amnesty, pylint: disable=wrong-import-order
from uuid import uuid4 # lint-amnesty, pylint: disable=wrong-import-order
from django.conf import settings
from django.test import RequestFactory
@@ -24,7 +24,7 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.xml_importer import import_course_from_xml
from xmodule.assetstore.assetmgr import AssetManager
from opaque_keys import InvalidKeyError
from opaque_keys import InvalidKeyError # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.exceptions import ItemNotFoundError
from common.djangoapps.student.models import CourseEnrollment
@@ -108,7 +108,7 @@ class ContentStoreToyCourseTest(SharedModuleStoreTestCase):
"""
Create user and login.
"""
super(ContentStoreToyCourseTest, self).setUp()
super(ContentStoreToyCourseTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.staff_usr = AdminFactory.create()
self.non_staff_usr = UserFactory.create()
@@ -244,7 +244,7 @@ class ContentStoreToyCourseTest(SharedModuleStoreTestCase):
"""
first_byte = self.length_unlocked / 4
last_byte = self.length_unlocked / 2
# pylint: disable=unicode-format-string
# lint-amnesty, pylint: disable=bad-option-value, unicode-format-string
resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes={first}-{last}, -100'.format(
first=first_byte, last=last_byte))
@@ -409,7 +409,7 @@ class ParseRangeHeaderTestCase(unittest.TestCase):
"""
def setUp(self):
super(ParseRangeHeaderTestCase, self).setUp()
super(ParseRangeHeaderTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.content_length = 10000
def test_bytes_unit(self):

View File

@@ -27,7 +27,7 @@ class SessionAuthenticationCrossDomainCsrf(authentication.SessionAuthentication)
"""
def _process_enforce_csrf(self, request):
CsrfViewMiddleware().process_request(request)
return super(SessionAuthenticationCrossDomainCsrf, self).enforce_csrf(request)
return super(SessionAuthenticationCrossDomainCsrf, self).enforce_csrf(request) # lint-amnesty, pylint: disable=super-with-arguments
def enforce_csrf(self, request):
"""

View File

@@ -65,7 +65,7 @@ class CorsCSRFMiddleware(CsrfViewMiddleware, MiddlewareMixin):
"""Disable the middleware if the feature flag is disabled. """
if not settings.FEATURES.get('ENABLE_CORS_HEADERS'):
raise MiddlewareNotUsed()
super(CorsCSRFMiddleware, self).__init__(*args, **kwargs)
super(CorsCSRFMiddleware, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
def process_view(self, request, callback, callback_args, callback_kwargs):
"""Skip the usual CSRF referer check if this is an allowed cross-domain request. """
@@ -74,7 +74,7 @@ class CorsCSRFMiddleware(CsrfViewMiddleware, MiddlewareMixin):
return
with skip_cross_domain_referer_check(request):
return super(CorsCSRFMiddleware, self).process_view(request, callback, callback_args, callback_kwargs)
return super(CorsCSRFMiddleware, self).process_view(request, callback, callback_args, callback_kwargs) # lint-amnesty, pylint: disable=super-with-arguments
class CsrfCrossDomainCookieMiddleware(MiddlewareMixin):
@@ -110,7 +110,7 @@ class CsrfCrossDomainCookieMiddleware(MiddlewareMixin):
"You must set `CROSS_DOMAIN_CSRF_COOKIE_DOMAIN` when "
"`FEATURES['ENABLE_CROSS_DOMAIN_CSRF_COOKIE']` is True."
)
super(CsrfCrossDomainCookieMiddleware, self).__init__(*args, **kwargs)
super(CsrfCrossDomainCookieMiddleware, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
def process_response(self, request, response):
"""Set the cross-domain CSRF cookie. """

View File

@@ -26,7 +26,7 @@ class CrossDomainAuthTest(TestCase):
REFERER = "https://www.edx.org"
def setUp(self):
super(CrossDomainAuthTest, self).setUp()
super(CrossDomainAuthTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.auth = SessionAuthenticationCrossDomainCsrf()
self.csrf_token = get_token(FakeRequest())

View File

@@ -11,7 +11,7 @@ from ..decorators import ensure_csrf_cookie_cross_domain
def fake_view(request):
"""Fake view that returns the request META as a JSON-encoded string. """
return HttpResponse(json.dumps(request.META))
return HttpResponse(json.dumps(request.META)) # lint-amnesty, pylint: disable=http-response-with-json-dumps
class TestEnsureCsrfCookieCrossDomain(TestCase):

View File

@@ -34,7 +34,7 @@ class TestCorsMiddlewareProcessRequest(TestCase):
@override_settings(FEATURES={'ENABLE_CORS_HEADERS': True})
def setUp(self):
super(TestCorsMiddlewareProcessRequest, self).setUp()
super(TestCorsMiddlewareProcessRequest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.middleware = CorsCSRFMiddleware()
def check_not_enabled(self, request):
@@ -114,7 +114,7 @@ class TestCsrfCrossDomainCookieMiddleware(TestCase):
CROSS_DOMAIN_CSRF_COOKIE_DOMAIN=COOKIE_DOMAIN
)
def setUp(self):
super(TestCsrfCrossDomainCookieMiddleware, self).setUp()
super(TestCsrfCrossDomainCookieMiddleware, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.middleware = CsrfCrossDomainCookieMiddleware()
@override_settings(FEATURES={'ENABLE_CROSS_DOMAIN_CSRF_COOKIE': False})
@@ -264,7 +264,7 @@ class TestCsrfCrossDomainCookieMiddleware(TestCase):
if is_set:
self.assertIn(self.COOKIE_NAME, response.cookies)
cookie_header = six.text_type(response.cookies[self.COOKIE_NAME])
# pylint: disable=unicode-format-string
# lint-amnesty, pylint: disable=bad-option-value, unicode-format-string
expected = six.u('Set-Cookie: {name}={value}; Domain={domain};').format(
name=self.COOKIE_NAME,
value=self.COOKIE_VALUE,

View File

@@ -23,7 +23,7 @@ class XDomainProxyTest(TestCase):
def setUp(self):
"""Clear model-based config cache. """
super(XDomainProxyTest, self).setUp()
super(XDomainProxyTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
try:
self.url = reverse('xdomain_proxy')
except NoReverseMatch:

View File

@@ -6,7 +6,7 @@ neo4j, a graph database.
import logging
from celery import task
from celery import shared_task
from django.conf import settings # lint-amnesty, pylint: disable=unused-import
from django.utils import six, timezone
from edx_django_utils.cache import RequestCache
@@ -247,7 +247,7 @@ def should_dump_course(course_key, graph):
return last_this_command_was_run < course_last_published_date
@task
@shared_task
@set_code_owner_attribute
def dump_course_to_neo4j(course_key_string, credentials):
"""

View File

@@ -479,6 +479,13 @@ class SequenceMetadata(DeveloperErrorViewMixin, APIView):
except InvalidKeyError:
raise NotFound("Invalid usage key: '{}'.".format(usage_key_string)) # lint-amnesty, pylint: disable=raise-missing-from
_, request.user = setup_masquerade(
request,
usage_key.course_key,
staff_access=has_access(request.user, 'staff', usage_key.course_key),
reset_masquerade_data=True,
)
sequence, _ = get_module_by_usage_id(
self.request,
str(usage_key.course_key),

View File

@@ -3,7 +3,7 @@ This file contains celery tasks for credentials-related functionality.
"""
from celery import task
from celery import shared_task
from celery.utils.log import get_task_logger
from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
@@ -21,7 +21,7 @@ logger = get_task_logger(__name__)
MAX_RETRIES = 11
@task(bind=True, ignore_result=True)
@shared_task(bind=True, ignore_result=True)
@set_code_owner_attribute
def send_grade_to_credentials(self, username, course_run_key, verified, letter_grade, percent_grade):
""" Celery task to notify the Credentials IDA of a grade change via POST. """

View File

@@ -4,7 +4,7 @@ This file contains celery tasks for credit course views.
import six
from celery import task
from celery import shared_task
from celery.utils.log import get_task_logger
from django.conf import settings
from edx_django_utils.monitoring import set_code_owner_attribute
@@ -20,7 +20,7 @@ from xmodule.modulestore.exceptions import ItemNotFoundError
LOGGER = get_task_logger(__name__)
@task(default_retry_delay=settings.CREDIT_TASK_DEFAULT_RETRY_DELAY, max_retries=settings.CREDIT_TASK_MAX_RETRIES)
@shared_task(default_retry_delay=settings.CREDIT_TASK_DEFAULT_RETRY_DELAY, max_retries=settings.CREDIT_TASK_MAX_RETRIES)
@set_code_owner_attribute
def update_credit_course_requirements(course_id):
"""

View File

@@ -3,11 +3,11 @@ A trivial task for health checks
"""
from celery.task import task
from celery import shared_task
from edx_django_utils.monitoring import set_code_owner_attribute
@task
@shared_task
@set_code_owner_attribute
def sample_task():
return True

View File

@@ -1,4 +1,3 @@
# lint-amnesty, pylint: disable=bad-option-value, unicode-format-string
"""
Defines the URL routes for this app.

View File

@@ -3,7 +3,7 @@ This file contains celery tasks for programs-related functionality.
"""
from celery import task
from celery import shared_task
from celery.exceptions import MaxRetriesExceededError
from celery.utils.log import get_task_logger
from django.conf import settings
@@ -121,7 +121,7 @@ def award_program_certificate(client, username, program_uuid, visible_date):
})
@task(bind=True, ignore_result=True)
@shared_task(bind=True, ignore_result=True)
@set_code_owner_attribute
def award_program_certificates(self, username): # lint-amnesty, pylint: disable=too-many-statements
"""
@@ -284,7 +284,7 @@ def post_course_certificate(client, username, certificate, visible_date):
})
@task(bind=True, ignore_result=True)
@shared_task(bind=True, ignore_result=True)
@set_code_owner_attribute
def award_course_certificate(self, username, course_run_key):
"""
@@ -399,7 +399,7 @@ def revoke_program_certificate(client, username, program_uuid):
})
@task(bind=True, ignore_result=True)
@shared_task(bind=True, ignore_result=True)
@set_code_owner_attribute
def revoke_program_certificates(self, username, course_key):
"""
@@ -523,7 +523,7 @@ def revoke_program_certificates(self, username, course_key):
LOGGER.info(u'Successfully completed the task revoke_program_certificates for username %s', username)
@task(bind=True, ignore_result=True)
@shared_task(bind=True, ignore_result=True)
@set_code_owner_attribute
def update_certificate_visible_date_on_course_update(self, course_key):
"""

View File

@@ -5,7 +5,7 @@ import logging
import six
from six.moves import range
from celery import task, current_app
from celery import shared_task, current_app
from celery_utils.logged_task import LoggedTask
from celery_utils.persist_on_failure import LoggedPersistOnFailureTask
from django.conf import settings
@@ -46,7 +46,7 @@ COURSE_UPDATE_LOG_PREFIX = 'Course Update'
COURSE_NEXT_SECTION_UPDATE_LOG_PREFIX = 'Course Next Section Update'
@task(base=LoggedPersistOnFailureTask, bind=True, default_retry_delay=30)
@shared_task(base=LoggedPersistOnFailureTask, bind=True, default_retry_delay=30)
@set_code_owner_attribute
def update_course_schedules(self, **kwargs): # lint-amnesty, pylint: disable=missing-function-docstring
course_key = CourseKey.from_string(kwargs['course_id'])
@@ -150,7 +150,7 @@ class BinnedScheduleMessageBaseTask(ScheduleMessageBaseTask):
raise NotImplementedError
@task(base=LoggedTask, ignore_result=True)
@shared_task(base=LoggedTask, ignore_result=True)
@set_code_owner_attribute
def _recurring_nudge_schedule_send(site_id, msg_str):
_schedule_send(
@@ -161,7 +161,7 @@ def _recurring_nudge_schedule_send(site_id, msg_str):
)
@task(base=LoggedTask, ignore_result=True)
@shared_task(base=LoggedTask, ignore_result=True)
@set_code_owner_attribute
def _upgrade_reminder_schedule_send(site_id, msg_str):
_schedule_send(
@@ -172,7 +172,7 @@ def _upgrade_reminder_schedule_send(site_id, msg_str):
)
@task(base=LoggedTask, ignore_result=True)
@shared_task(base=LoggedTask, ignore_result=True)
@set_code_owner_attribute
def _course_update_schedule_send(site_id, msg_str):
_schedule_send(

View File

@@ -1,4 +1,4 @@
"""
""" # lint-amnesty, pylint: disable=django-not-configured
Helpers methods for site configuration.
"""

View File

@@ -10,7 +10,7 @@ from django.utils import http
from oauth2_provider.models import Application
from six.moves.urllib.parse import urlparse # pylint: disable=import-error
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # lint-amnesty, pylint: disable=unused-import
def is_safe_login_or_logout_redirect(redirect_to, request_host, dot_client_id, require_https):

View File

@@ -125,24 +125,22 @@ def _generate_locked_out_error_message():
"""
locked_out_period_in_sec = settings.MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS
if not should_redirect_to_authn_microfrontend(): # pylint: disable=no-else-raise
raise AuthFailedError(Text(_('To protect your account, its been temporarily '
'locked. Try again in {locked_out_period} minutes.'
'{li_start}To be on the safe side, you can reset your '
'password {link_start}here{link_end} before you try again.')).format(
link_start=HTML('<a http="#login" class="form-toggle" data-type="password-reset">'),
link_end=HTML('</a>'),
li_start=HTML('<li>'),
li_end=HTML('</li>'),
locked_out_period=int(locked_out_period_in_sec / 60)))
else:
raise AuthFailedError(Text(_('To protect your account, its been temporarily '
'locked. Try again in {locked_out_period} minutes.\n'
'To be on the safe side, you can reset your '
'password {link_start}here{link_end} before you try again.\n')).format(
link_start=HTML('<a href="/reset" >'),
link_end=HTML('</a>'),
locked_out_period=int(locked_out_period_in_sec / 60)))
error_message = Text(_('To protect your account, its been temporarily '
'locked. Try again in {locked_out_period} minutes.'
'{li_start}To be on the safe side, you can reset your '
'password {link_start}here{link_end} before you try again.')).format(
link_start=HTML('<a http="#login" class="form-toggle" data-type="password-reset">'),
link_end=HTML('</a>'),
li_start=HTML('<li>'),
li_end=HTML('</li>'),
locked_out_period=int(locked_out_period_in_sec / 60))
raise AuthFailedError(
error_message,
error_code='account-locked-out',
context={
'locked_out_period': int(locked_out_period_in_sec / 60)
}
)
def _enforce_password_policy_compliance(request, user): # lint-amnesty, pylint: disable=missing-function-docstring
@@ -238,35 +236,29 @@ def _handle_failed_authentication(user, authenticated_user):
if not LoginFailures.is_user_locked_out(user):
max_failures_allowed = settings.MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED
remaining_attempts = max_failures_allowed - failure_count
if not should_redirect_to_authn_microfrontend(): # pylint: disable=no-else-raise
raise AuthFailedError(Text(_('Email or password is incorrect.'
'{li_start}You have {remaining_attempts} more sign-in '
'attempts before your account is temporarily locked.{li_end}'
'{li_start}If you\'ve forgotten your password, click '
'{link_start}here{link_end} to reset.{li_end}'
))
.format(
link_start=HTML('<a http="#login" class="form-toggle" data-type="password-reset">'),
link_end=HTML('</a>'),
li_start=HTML('<li>'),
li_end=HTML('</li>'),
remaining_attempts=remaining_attempts))
else:
raise AuthFailedError(Text(_('Email or password is incorrect.\n'
'You have {remaining_attempts} more sign-in '
'attempts before your account is temporarily locked.\n'
'If you{quote}ve forgotten your password, click '
'{link_start}here{link_end} to reset.\n'
))
.format(
quote=HTML("'"),
link_start=HTML('<a href="/reset" >'),
link_end=HTML('</a>'),
remaining_attempts=remaining_attempts))
else:
_generate_locked_out_error_message()
error_message = Text(_('Email or password is incorrect.'
'{li_start}You have {remaining_attempts} more sign-in '
'attempts before your account is temporarily locked.{li_end}'
'{li_start}If you\'ve forgotten your password, click '
'{link_start}here{link_end} to reset.{li_end}')).format(
link_start=HTML(
'<a http="#login" class="form-toggle" data-type="password-reset">'
),
link_end=HTML('</a>'),
li_start=HTML('<li>'),
li_end=HTML('</li>'),
remaining_attempts=remaining_attempts)
raise AuthFailedError(
error_message,
error_code='failed-login-attempt',
context={
'remaining_attempts': remaining_attempts,
}
)
raise AuthFailedError(_('Email or password is incorrect.'))
_generate_locked_out_error_message()
raise AuthFailedError(_('Email or password is incorrect.'), error_code='incorrect-email-or-password')
def _handle_successful_authentication_and_login(user, request):

View File

@@ -715,10 +715,10 @@ class LogistrationPasswordResetView(APIView): # lint-amnesty, pylint: disable=m
}
)
user.save()
send_password_reset_success_email(user, request)
except ObjectDoesNotExist:
err = 'Account recovery process initiated without AccountRecovery instance for user {username}'
log.error(err.format(username=user.username))
send_password_reset_success_email(user, request)
except ValidationError as err:
AUDIT_LOG.exception("Password validation failed")
error_status = {

View File

@@ -824,12 +824,13 @@ class ResetPasswordAPITests(EventTestMixin, CacheIsolationTestCase):
new=updated_user.email
)
def test_password_reset_email_sent_on_account_recovery_email(self):
@ddt.data(True, False)
def test_password_reset_email_successfully_sent(self, is_account_recovery):
"""
Test that with is_account_recovery query param available, password
reset email is sent to newly updated email address.
"""
post_request = self.create_reset_request(self.uidb36, self.token, True)
post_request = self.create_reset_request(self.uidb36, self.token, is_account_recovery)
post_request.user = AnonymousUser()
post_request.site = Mock(domain='example.com')
reset_view = LogistrationPasswordResetView.as_view()

View File

@@ -4,7 +4,7 @@
from unittest import TestCase
from pytest import mark
from celery.task import task
from celery import shared_task
from django.test.utils import override_settings
from edx_django_utils.cache import RequestCache
@@ -17,7 +17,7 @@ class TestClearRequestCache(TestCase):
def _get_cache(self):
return RequestCache("TestClearRequestCache")
@task
@shared_task
def _dummy_task(self):
""" A task that adds stuff to the request cache. """
self._get_cache().set("cache_key", "blah blah")

View File

@@ -5,7 +5,7 @@ Celery task for Automatic Verifed Track Cohorting MVP feature.
import six
from celery.task import task
from celery import shared_task
from celery.utils.log import get_task_logger
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from edx_django_utils.monitoring import set_code_owner_attribute
@@ -17,7 +17,7 @@ from common.djangoapps.student.models import CourseEnrollment, CourseMode
LOGGER = get_task_logger(__name__)
@task(bind=True, default_retry_delay=60, max_retries=2)
@shared_task(bind=True, default_retry_delay=60, max_retries=2)
@set_code_owner_attribute
def sync_cohort_with_mode(self, course_id, user_id, verified_cohort_name, default_cohort_name):
"""