Commit 08dfe5e9 by Giovanni Di Milia

Fixed pylint violation for files in lms/djangoapps/bulk_email

parent 2b5810db
......@@ -54,7 +54,9 @@ unsupported tags will cause email sending to fail.
return True
def has_delete_permission(self, request, obj=None):
"""Disables the ability to remove existing templates, as we'd like to make sure we don't have dangling references."""
"""
Disables the ability to remove existing templates, as we'd like to make sure we don't have dangling references.
"""
return False
......
......@@ -75,7 +75,9 @@ class CourseEmail(Email):
return self.subject
@classmethod
def create(cls, course_id, sender, to_option, subject, html_message, text_message=None, template_name=None, from_addr=None):
def create(
cls, course_id, sender, to_option, subject, html_message,
text_message=None, template_name=None, from_addr=None):
"""
Create an instance of CourseEmail.
......
......@@ -25,9 +25,9 @@ from boto.ses.exceptions import (
)
from boto.exception import AWSConnectionError
from celery import task, current_task
from celery.states import SUCCESS, FAILURE, RETRY
from celery.exceptions import RetryTaskError
from celery import task, current_task # pylint: disable=no-name-in-module
from celery.states import SUCCESS, FAILURE, RETRY # pylint: disable=no-name-in-module, import-error
from celery.exceptions import RetryTaskError # pylint: disable=no-name-in-module, import-error
from django.conf import settings
from django.contrib.auth.models import User
......@@ -310,7 +310,8 @@ def send_course_email(entry_id, email_id, to_list, global_email_context, subtask
subtask_status = SubtaskStatus.from_dict(subtask_status_dict)
current_task_id = subtask_status.task_id
num_to_send = len(to_list)
log.info(u"Preparing to send email %s to %d recipients as subtask %s for instructor task %d: context = %s, status=%s",
log.info((u"Preparing to send email %s to %d recipients as subtask %s "
u"for instructor task %d: context = %s, status=%s"),
email_id, num_to_send, current_task_id, entry_id, global_email_context, subtask_status)
# Check that the requested subtask is actually known to the current InstructorTask entry.
......@@ -663,20 +664,22 @@ def _send_course_email(entry_id, email_id, to_list, global_email_context, subtas
except BULK_EMAIL_FAILURE_ERRORS as exc:
dog_stats_api.increment('course_email.error', tags=[_statsd_tag(course_title)])
num_pending = len(to_list)
log.exception('Task %s: email with id %d caused send_course_email task to fail with "fatal" exception. %d emails unsent.',
log.exception(('Task %s: email with id %d caused send_course_email task to fail '
'with "fatal" exception. %d emails unsent.'),
task_id, email_id, num_pending)
# Update counters with progress to date, counting unsent emails as failures,
# and set the state to FAILURE:
subtask_status.increment(failed=num_pending, state=FAILURE)
return subtask_status, exc
except Exception as exc:
except Exception as exc: # pylint: disable=broad-except
# Errors caught here cause the email to be retried. The entire task is actually retried
# without popping the current recipient off of the existing list.
# These are unexpected errors. Since they might be due to a temporary condition that might
# succeed on retry, we give them a retry.
dog_stats_api.increment('course_email.limited_retry', tags=[_statsd_tag(course_title)])
log.exception('Task %s: email with id %d caused send_course_email task to fail with unexpected exception. Generating retry.',
log.exception(('Task %s: email with id %d caused send_course_email task to fail '
'with unexpected exception. Generating retry.'),
task_id, email_id)
# Increment the "retried_withmax" counter, update other counters with progress to date,
# and set the state to RETRY:
......@@ -709,7 +712,8 @@ def _get_current_task():
return current_task
def _submit_for_retry(entry_id, email_id, to_list, global_email_context, current_exception, subtask_status, skip_retry_max=False):
def _submit_for_retry(entry_id, email_id, to_list, global_email_context,
current_exception, subtask_status, skip_retry_max=False):
"""
Helper function to requeue a task for retry, using the new version of arguments provided.
......@@ -762,7 +766,8 @@ def _submit_for_retry(entry_id, email_id, to_list, global_email_context, current
# retries are deferred by the same amount.
countdown = ((2 ** retry_index) * base_delay) * random.uniform(.75, 1.25)
log.warning('Task %s: email with id %d not delivered due to %s error %s, retrying send to %d recipients in %s seconds (with max_retry=%s)',
log.warning(('Task %s: email with id %d not delivered due to %s error %s, '
'retrying send to %d recipients in %s seconds (with max_retry=%s)'),
task_id, email_id, exception_type, current_exception, len(to_list), countdown, max_retries)
# we make sure that we update the InstructorTask with the current subtask status
......@@ -793,7 +798,7 @@ def _submit_for_retry(entry_id, email_id, to_list, global_email_context, current
log.exception(u'Task %s: email with id %d caused send_course_email task to retry.',
task_id, email_id)
return subtask_status, retry_error
except Exception as retry_exc:
except Exception as retry_exc: # pylint: disable=broad-except
# If there are no more retries, because the maximum has been reached,
# we expect the original exception to be raised. We catch it here
# (and put it in retry_exc just in case it's different, but it shouldn't be),
......
......@@ -4,7 +4,7 @@ Unit tests for handling email sending errors
"""
from itertools import cycle
from celery.states import SUCCESS, RETRY
from celery.states import SUCCESS, RETRY # pylint: disable=no-name-in-module, import-error
from django.conf import settings
from django.core.management import call_command
from django.core.urlresolvers import reverse
......
......@@ -60,7 +60,10 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
"Course authorization with this Course id already exists.",
form._errors['course_id'][0] # pylint: disable=protected-access
)
with self.assertRaisesRegexp(ValueError, "The CourseAuthorization could not be created because the data didn't validate."):
with self.assertRaisesRegexp(
ValueError,
"The CourseAuthorization could not be created because the data didn't validate."
):
form.save()
# Course should still be authorized (invalid attempt had no effect)
......@@ -81,7 +84,10 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
msg += 'Please recheck that you have supplied a valid course id.'
self.assertEquals(msg, form._errors['course_id'][0]) # pylint: disable=protected-access
with self.assertRaisesRegexp(ValueError, "The CourseAuthorization could not be created because the data didn't validate."):
with self.assertRaisesRegexp(
ValueError,
"The CourseAuthorization could not be created because the data didn't validate."
):
form.save()
@patch.dict(settings.FEATURES, {'ENABLE_INSTRUCTOR_EMAIL': True, 'REQUIRE_COURSE_EMAIL_AUTH': True})
......@@ -96,7 +102,10 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
msg += 'Please recheck that you have supplied a valid course id.'
self.assertEquals(msg, form._errors['course_id'][0]) # pylint: disable=protected-access
with self.assertRaisesRegexp(ValueError, "The CourseAuthorization could not be created because the data didn't validate."):
with self.assertRaisesRegexp(
ValueError,
"The CourseAuthorization could not be created because the data didn't validate."
):
form.save()
@patch.dict(settings.FEATURES, {'ENABLE_INSTRUCTOR_EMAIL': True, 'REQUIRE_COURSE_EMAIL_AUTH': True})
......@@ -107,11 +116,14 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
# Validation shouldn't work
self.assertFalse(form.is_valid())
error_msg = form._errors['course_id'][0]
error_msg = form._errors['course_id'][0] # pylint: disable=protected-access
self.assertIn(u'--- Entered course id was: "{0}". '.format(self.course.id.run), error_msg)
self.assertIn(u'Please recheck that you have supplied a valid course id.', error_msg)
with self.assertRaisesRegexp(ValueError, "The CourseAuthorization could not be created because the data didn't validate."):
with self.assertRaisesRegexp(
ValueError,
"The CourseAuthorization could not be created because the data didn't validate."
):
form.save()
......@@ -134,7 +146,10 @@ class CourseAuthorizationXMLFormTest(ModuleStoreTestCase):
msg += u'"{0}" appears to be an XML backed course.'.format(course_id.to_deprecated_string())
self.assertEquals(msg, form._errors['course_id'][0]) # pylint: disable=protected-access
with self.assertRaisesRegexp(ValueError, "The CourseAuthorization could not be created because the data didn't validate."):
with self.assertRaisesRegexp(
ValueError,
"The CourseAuthorization could not be created because the data didn't validate."
):
form.save()
......
......@@ -40,7 +40,9 @@ class CourseEmailTest(TestCase):
html_message = "<html>dummy message</html>"
template_name = "branded_template"
from_addr = "branded@branding.com"
email = CourseEmail.create(course_id, sender, to_option, subject, html_message, template_name=template_name, from_addr=from_addr)
email = CourseEmail.create(
course_id, sender, to_option, subject, html_message, template_name=template_name, from_addr=from_addr
)
self.assertEquals(email.course_id, course_id)
self.assertEquals(email.to_option, SEND_TO_STAFF)
self.assertEquals(email.subject, subject)
......
......@@ -25,7 +25,7 @@ from boto.ses.exceptions import (
)
from boto.exception import AWSConnectionError
from celery.states import SUCCESS, FAILURE
from celery.states import SUCCESS, FAILURE # pylint: disable=no-name-in-module, import-error
from django.conf import settings
from django.core.management import call_command
......@@ -96,7 +96,9 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
"""
to_option = SEND_TO_ALL
course_id = course_id or self.course.id
course_email = CourseEmail.create(course_id, self.instructor, to_option, "Test Subject", "<p>This is a test message</p>")
course_email = CourseEmail.create(
course_id, self.instructor, to_option, "Test Subject", "<p>This is a test message</p>"
)
task_input = {'email_id': course_email.id} # pylint: disable=no-member
task_id = str(uuid4())
instructor_task = InstructorTaskFactory.create(
......@@ -153,7 +155,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
self.assertEquals(len(task_id_list), 1)
task_id = task_id_list[0]
subtask_status = subtask_status_info.get(task_id)
print("Testing subtask status: {}".format(subtask_status))
print "Testing subtask status: {}".format(subtask_status)
self.assertEquals(subtask_status.get('task_id'), task_id)
self.assertEquals(subtask_status.get('attempted'), succeeded + failed)
self.assertEquals(subtask_status.get('succeeded'), succeeded)
......@@ -163,7 +165,9 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
self.assertEquals(subtask_status.get('retried_withmax'), retried_withmax)
self.assertEquals(subtask_status.get('state'), SUCCESS if succeeded > 0 else FAILURE)
def _test_run_with_task(self, task_class, action_name, total, succeeded, failed=0, skipped=0, retried_nomax=0, retried_withmax=0):
def _test_run_with_task(
self, task_class, action_name, total, succeeded,
failed=0, skipped=0, retried_nomax=0, retried_withmax=0):
"""Run a task and check the number of emails processed."""
task_entry = self._create_input_entry()
parent_status = self._run_task_with_mock_celery(task_class, task_entry.id, task_entry.task_id)
......@@ -238,7 +242,9 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
# mark some students as opting out
with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn:
get_conn.return_value.send_messages.side_effect = cycle([None])
self._test_run_with_task(send_bulk_course_email, 'emailed', num_emails, expected_succeeds, skipped=expected_skipped)
self._test_run_with_task(
send_bulk_course_email, 'emailed', num_emails, expected_succeeds, skipped=expected_skipped
)
def _test_email_address_failures(self, exception):
"""Test that celery handles bad address errors by failing and not retrying."""
......@@ -251,7 +257,9 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn:
# have every fourth email fail due to some address failure:
get_conn.return_value.send_messages.side_effect = cycle([exception, None, None, None])
self._test_run_with_task(send_bulk_course_email, 'emailed', num_emails, expected_succeeds, failed=expected_fails)
self._test_run_with_task(
send_bulk_course_email, 'emailed', num_emails, expected_succeeds, failed=expected_fails
)
def test_smtp_blacklisted_user(self):
# Test that celery handles permanent SMTPDataErrors by failing and not retrying.
......@@ -329,10 +337,14 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
self._test_max_retry_limit_causes_failure(SMTPConnectError(424, "Bad Connection"))
def test_retry_after_aws_connect_error(self):
self._test_retry_after_limited_retry_error(AWSConnectionError("Unable to provide secure connection through proxy"))
self._test_retry_after_limited_retry_error(
AWSConnectionError("Unable to provide secure connection through proxy")
)
def test_max_retry_after_aws_connect_error(self):
self._test_max_retry_limit_causes_failure(AWSConnectionError("Unable to provide secure connection through proxy"))
self._test_max_retry_limit_causes_failure(
AWSConnectionError("Unable to provide secure connection through proxy")
)
def test_retry_after_general_error(self):
self._test_retry_after_limited_retry_error(Exception("This is some random exception."))
......@@ -371,7 +383,9 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
self._test_retry_after_unlimited_retry_error(SMTPDataError(455, "Throttling: Sending rate exceeded"))
def test_retry_after_ses_throttling_error(self):
self._test_retry_after_unlimited_retry_error(SESMaxSendingRateExceededError(455, "Throttling: Sending rate exceeded"))
self._test_retry_after_unlimited_retry_error(
SESMaxSendingRateExceededError(455, "Throttling: Sending rate exceeded")
)
def _test_immediate_failure(self, exception):
"""Test that celery can hit a maximum number of retries."""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment