Merge branch 'master' into usamasadiq/bom-2327-pylint-amnesty
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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.',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()]
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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],
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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', )
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# lint-amnesty, pylint: disable=missing-module-docstring
|
||||
from .outlines import (
|
||||
get_course_outline,
|
||||
get_user_course_outline,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# lint-amnesty, pylint: disable=missing-module-docstring
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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:
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# lint-amnesty, pylint: disable=missing-module-docstring
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import CourseOutlineView
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""
|
||||
""" # lint-amnesty, pylint: disable=django-not-configured
|
||||
Serves course assets to end users.
|
||||
"""
|
||||
|
||||
@@ -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('-'):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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. """
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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. """
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# lint-amnesty, pylint: disable=bad-option-value, unicode-format-string
|
||||
"""
|
||||
Defines the URL routes for this app.
|
||||
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""
|
||||
""" # lint-amnesty, pylint: disable=django-not-configured
|
||||
Helpers methods for site configuration.
|
||||
"""
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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, it’s 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, it’s 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, it’s 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):
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user