From adae7e3e25390deb859913694f794b2814e5fb42 Mon Sep 17 00:00:00 2001 From: Deborah Kaplan Date: Tue, 30 Jan 2024 17:39:57 +0000 Subject: [PATCH] feat: relinting Trying with new autoformat settings. FIXES: APER-3146 --- openedx/core/djangoapps/programs/tasks.py | 186 ++++------- .../djangoapps/programs/tests/test_tasks.py | 300 +++++------------- 2 files changed, 128 insertions(+), 358 deletions(-) diff --git a/openedx/core/djangoapps/programs/tasks.py b/openedx/core/djangoapps/programs/tasks.py index 6717ef3298..c8f1e6f97f 100644 --- a/openedx/core/djangoapps/programs/tasks.py +++ b/openedx/core/djangoapps/programs/tasks.py @@ -128,9 +128,7 @@ def award_program_certificate(client, user, program_uuid, visible_date): "username": user.username, "lms_user_id": user.id, "credential": {"type": PROGRAM_CERTIFICATE, "program_uuid": program_uuid}, - "attributes": [ - {"name": "visible_date", "value": visible_date.strftime(DATE_FORMAT)} - ], + "attributes": [{"name": "visible_date", "value": visible_date.strftime(DATE_FORMAT)}], }, ) response.raise_for_status() @@ -138,9 +136,7 @@ def award_program_certificate(client, user, program_uuid, visible_date): @shared_task(bind=True, ignore_result=True) @set_code_owner_attribute -def award_program_certificates( - self, username -): # lint-amnesty, pylint: disable=too-many-statements +def award_program_certificates(self, username): # lint-amnesty, pylint: disable=too-many-statements """ This task is designed to be called whenever a student's completion status changes with respect to one or more courses (primarily, when a course @@ -172,9 +168,7 @@ def award_program_certificates( return self.retry(exc=exception, countdown=countdown, max_retries=MAX_RETRIES) LOGGER.info(f"Running task award_program_certificates for username {username}") - programs_without_certificates = configuration_helpers.get_value( - "programs_without_certificates", [] - ) + programs_without_certificates = configuration_helpers.get_value("programs_without_certificates", []) if programs_without_certificates: if str(programs_without_certificates[0]).lower() == "all": # this check will prevent unnecessary logging for partners without program certificates @@ -187,19 +181,17 @@ def award_program_certificates( # mark this task for retry instead of failing it altogether. if not CredentialsApiConfig.current().is_learner_issuance_enabled: - error_msg = "Task award_program_certificates cannot be executed when credentials issuance is disabled in API config" - LOGGER.warning(error_msg) - raise _retry_with_custom_exception( - username=username, reason=error_msg, countdown=countdown + error_msg = ( + "Task award_program_certificates cannot be executed when credentials issuance is disabled in API config" ) + LOGGER.warning(error_msg) + raise _retry_with_custom_exception(username=username, reason=error_msg, countdown=countdown) try: try: student = User.objects.get(username=username) except User.DoesNotExist: - LOGGER.exception( - f"Task award_program_certificates was called with invalid username {username}" - ) + LOGGER.exception(f"Task award_program_certificates was called with invalid username {username}") # Don't retry for this case - just conclude the task. return completed_programs = {} @@ -208,9 +200,7 @@ def award_program_certificates( if not completed_programs: # No reason to continue beyond this point unless/until this # task gets updated to support revocation of program certs. - LOGGER.info( - f"Task award_program_certificates was called for user {username} with no completed programs" - ) + LOGGER.info(f"Task award_program_certificates was called for user {username} with no completed programs") return # Determine which program certificates the user has already been awarded, if any. @@ -218,16 +208,12 @@ def award_program_certificates( # we will skip all the programs which have already been awarded and we want to skip the programs # which are exit in site configuration in 'programs_without_certificates' list. - awarded_and_skipped_program_uuids = list( - set(existing_program_uuids + list(programs_without_certificates)) - ) + awarded_and_skipped_program_uuids = list(set(existing_program_uuids + list(programs_without_certificates))) except Exception as exc: error_msg = f"Failed to determine program certificates to be awarded for user {username}. {exc}" LOGGER.exception(error_msg) - raise _retry_with_custom_exception( - username=username, reason=error_msg, countdown=countdown - ) from exc + raise _retry_with_custom_exception(username=username, reason=error_msg, countdown=countdown) from exc # For each completed program for which the student doesn't already have a # certificate, award one now. @@ -235,9 +221,7 @@ def award_program_certificates( # This logic is important, because we will retry the whole task if awarding any particular program cert fails. # # N.B. the list is sorted to facilitate deterministic ordering, e.g. for tests. - new_program_uuids = sorted( - list(set(completed_programs.keys()) - set(awarded_and_skipped_program_uuids)) - ) + new_program_uuids = sorted(list(set(completed_programs.keys()) - set(awarded_and_skipped_program_uuids))) if new_program_uuids: try: credentials_client = get_credentials_api_client( @@ -247,23 +231,15 @@ def award_program_certificates( error_msg = "Failed to create a credentials API client to award program certificates" LOGGER.exception(error_msg) # Retry because a misconfiguration could be fixed - raise _retry_with_custom_exception( - username=username, reason=error_msg, countdown=countdown - ) from exc + raise _retry_with_custom_exception(username=username, reason=error_msg, countdown=countdown) from exc failed_program_certificate_award_attempts = [] for program_uuid in new_program_uuids: visible_date = completed_programs[program_uuid] try: - LOGGER.info( - f"Visible date for user {username} : program {program_uuid} is {visible_date}" - ) - award_program_certificate( - credentials_client, student, program_uuid, visible_date - ) - LOGGER.info( - f"Awarded certificate for program {program_uuid} to user {username}" - ) + LOGGER.info(f"Visible date for user {username} : program {program_uuid} is {visible_date}") + award_program_certificate(credentials_client, student, program_uuid, visible_date) + LOGGER.info(f"Awarded certificate for program {program_uuid} to user {username}") except HTTPError as exc: if exc.response.status_code == 404: LOGGER.exception( @@ -290,16 +266,12 @@ def award_program_certificates( ) except Exception: # pylint: disable=broad-except # keep trying to award other certs, but retry the whole task to fix any missing entries - LOGGER.exception( - f"Failed to award certificate for program {program_uuid} to user {username}." - ) + LOGGER.exception(f"Failed to award certificate for program {program_uuid} to user {username}.") failed_program_certificate_award_attempts.append(program_uuid) if failed_program_certificate_award_attempts: # N.B. This logic assumes that this task is idempotent - LOGGER.info( - f"Retrying task to award failed certificates to user {username}" - ) + LOGGER.info(f"Retrying task to award failed certificates to user {username}") # The error message may change on each reattempt but will never be raised until # the max number of retries have been exceeded. It is unlikely that this list # will change by the time it reaches its maximimum number of attempts. @@ -307,20 +279,14 @@ def award_program_certificates( f"Failed to award certificate for user {username} " f"for programs {failed_program_certificate_award_attempts}" ) - raise _retry_with_custom_exception( - username=username, reason=error_msg, countdown=countdown - ) + raise _retry_with_custom_exception(username=username, reason=error_msg, countdown=countdown) else: LOGGER.info(f"User {username} is not eligible for any new program certificates") - LOGGER.info( - f"Successfully completed the task award_program_certificates for username {username}" - ) + LOGGER.info(f"Successfully completed the task award_program_certificates for username {username}") -def post_course_certificate_configuration( - client, cert_config, certificate_available_date=None -): +def post_course_certificate_configuration(client, cert_config, certificate_available_date=None): """ Make a POST request to the Credentials IDA's `course_certificates` endpoint (/api/v2/course_certificates/). This endpoint manages the course certificate configurations within the Credentials IDA. @@ -333,9 +299,7 @@ def post_course_certificate_configuration( in the form of an ISO 8601 DateTime String. """ credentials_api_base_url = get_credentials_api_base_url() - credentials_api_url = urljoin( - f"{credentials_api_base_url}/", "course_certificates/" - ) + credentials_api_url = urljoin(f"{credentials_api_base_url}/", "course_certificates/") response = client.post( credentials_api_url, @@ -360,9 +324,7 @@ def post_course_certificate_configuration( response.raise_for_status() -def post_course_certificate( - client, username, certificate, visible_date, date_override=None, org=None -): +def post_course_certificate(client, username, certificate, visible_date, date_override=None, org=None): """ POST a certificate that has been updated to Credentials """ @@ -373,20 +335,14 @@ def post_course_certificate( api_url, json={ "username": username, - "status": "awarded" - if certificate.is_valid() - else "revoked", # Only need the two options at this time + "status": "awarded" if certificate.is_valid() else "revoked", # Only need the two options at this time "credential": { "course_run_key": str(certificate.course_id), "mode": certificate.mode, "type": COURSE_CERTIFICATE, }, - "date_override": {"date": date_override.strftime(DATE_FORMAT)} - if date_override - else None, - "attributes": [ - {"name": "visible_date", "value": visible_date.strftime(DATE_FORMAT)} - ], + "date_override": {"date": date_override.strftime(DATE_FORMAT)} if date_override else None, + "attributes": [{"name": "visible_date", "value": visible_date.strftime(DATE_FORMAT)}], }, ) response.raise_for_status() @@ -417,15 +373,9 @@ def update_credentials_course_certificate_configuration_available_date( course_key = str(course_key) course_modes = CourseMode.objects.filter(course_id=course_key) # There should only ever be one certificate relevant mode per course run - modes = [ - mode.slug - for mode in course_modes - if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES - ] + modes = [mode.slug for mode in course_modes if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES] if len(modes) != 1: - LOGGER.exception( - f"Either course {course_key} has no certificate mode or multiple modes. Task failed." - ) + LOGGER.exception(f"Either course {course_key} has no certificate mode or multiple modes. Task failed.") return credentials_client = get_credentials_api_client( @@ -474,7 +424,9 @@ def award_course_certificate(self, username, course_run_key): # has been temporarily disabled. Since this is a recoverable situation, # mark this task for retry instead of failing it altogether. if not CredentialsApiConfig.current().is_learner_issuance_enabled: - error_msg = "Task award_course_certificate cannot be executed when credentials issuance is disabled in API config" + error_msg = ( + "Task award_course_certificate cannot be executed when credentials issuance is disabled in API " "config" + ) LOGGER.warning(error_msg) raise _retry_with_custom_exception( username=username, @@ -487,9 +439,7 @@ def award_course_certificate(self, username, course_run_key): try: user = User.objects.get(username=username) except User.DoesNotExist: - LOGGER.exception( - f"Task award_course_certificate was called with invalid username {username}" - ) + LOGGER.exception(f"Task award_course_certificate was called with invalid username {username}") # Don't retry for this case - just conclude the task. return # Get the cert for the course key and username if it's both passing and available in professional/verified @@ -546,9 +496,7 @@ def award_course_certificate(self, username, course_run_key): org=course_key.org, ) - LOGGER.info( - f"Awarded certificate for course {course_key} to user {username}" - ) + LOGGER.info(f"Awarded certificate for course {course_key} to user {username}") except Exception as exc: error_msg = f"Failed to determine course certificates to be awarded for user {username}." LOGGER.exception(error_msg) @@ -560,9 +508,7 @@ def award_course_certificate(self, username, course_run_key): ) from exc -def get_revokable_program_uuids( - course_specific_programs: List[Dict], student: User -) -> List[str]: +def get_revokable_program_uuids(course_specific_programs: List[Dict], student: User) -> List[str]: """ Get program uuids for which certificate to be revoked. @@ -618,9 +564,7 @@ def revoke_program_certificate(client, username, program_uuid): @shared_task(bind=True, ignore_result=True) @set_code_owner_attribute -def revoke_program_certificates( - self, username, course_key -): # lint-amnesty, pylint: disable=too-many-statements +def revoke_program_certificates(self, username, course_key): # lint-amnesty, pylint: disable=too-many-statements """ This task is designed to be called whenever a student's course certificate is revoked. @@ -654,7 +598,9 @@ def revoke_program_certificates( # mark this task for retry instead of failing it altogether. if not CredentialsApiConfig.current().is_learner_issuance_enabled: - error_msg = "Task revoke_program_certificates cannot be executed when credentials issuance is disabled in API config" + error_msg = ( + "Task revoke_program_certificates cannot be executed when credentials issuance is disabled in API config" + ) LOGGER.warning(error_msg) raise _retry_with_custom_exception( username=username, @@ -685,13 +631,10 @@ def revoke_program_certificates( return # Determine which program certificates the user has already been awarded, if any. - program_uuids_to_revoke = get_revokable_program_uuids( - course_specific_programs, student - ) + program_uuids_to_revoke = get_revokable_program_uuids(course_specific_programs, student) except Exception as exc: error_msg = ( - f"Failed to determine program certificates to be revoked for user {username} " - f"with course {course_key}" + f"Failed to determine program certificates to be revoked for user {username} " f"with course {course_key}" ) LOGGER.exception(error_msg) raise _retry_with_custom_exception( @@ -710,17 +653,13 @@ def revoke_program_certificates( error_msg = "Failed to create a credentials API client to revoke program certificates" LOGGER.exception(error_msg) # Retry because a misconfiguration could be fixed - raise _retry_with_custom_exception( - username, course_key, reason=exc, countdown=countdown - ) from exc + raise _retry_with_custom_exception(username, course_key, reason=exc, countdown=countdown) from exc failed_program_certificate_revoke_attempts = [] for program_uuid in program_uuids_to_revoke: try: revoke_program_certificate(credentials_client, username, program_uuid) - LOGGER.info( - f"Revoked certificate for program {program_uuid} for user {username}" - ) + LOGGER.info(f"Revoked certificate for program {program_uuid} for user {username}") except HTTPError as exc: if exc.response.status_code == 404: LOGGER.exception( @@ -742,21 +681,15 @@ def revoke_program_certificates( countdown=rate_limit_countdown, ) from exc else: - LOGGER.exception( - f"Unable to revoke certificate for user {username} for program {program_uuid}." - ) + LOGGER.exception(f"Unable to revoke certificate for user {username} for program {program_uuid}.") except Exception: # pylint: disable=broad-except # keep trying to revoke other certs, but retry the whole task to fix any missing entries - LOGGER.warning( - f"Failed to revoke certificate for program {program_uuid} of user {username}." - ) + LOGGER.warning(f"Failed to revoke certificate for program {program_uuid} of user {username}.") failed_program_certificate_revoke_attempts.append(program_uuid) if failed_program_certificate_revoke_attempts: # N.B. This logic assumes that this task is idempotent - LOGGER.info( - f"Retrying task to revoke failed certificates to user {username}" - ) + LOGGER.info(f"Retrying task to revoke failed certificates to user {username}") # The error message may change on each reattempt but will never be raised until # the max number of retries have been exceeded. It is unlikely that this list # will change by the time it reaches its maximimum number of attempts. @@ -764,15 +697,11 @@ def revoke_program_certificates( f"Failed to revoke certificate for user {username} " f"for programs {failed_program_certificate_revoke_attempts}" ) - raise _retry_with_custom_exception( - username, course_key, reason=error_msg, countdown=countdown - ) + raise _retry_with_custom_exception(username, course_key, reason=error_msg, countdown=countdown) else: LOGGER.info(f"There is no program certificates for user {username} to revoke") - LOGGER.info( - f"Successfully completed the task revoke_program_certificates for username {username}" - ) + LOGGER.info(f"Successfully completed the task revoke_program_certificates for username {username}") @shared_task(bind=True, ignore_result=True) @@ -810,11 +739,9 @@ def update_certificate_visible_date_on_course_update(self, course_key): # Retrieve a list of all usernames of learners who have a certificate record in this course-run. The # Credentials IDA REST API still requires a username as the main identifier for the learner. - users_with_certificates_in_course = ( - GeneratedCertificate.eligible_available_certificates.filter( - course_id=course_key - ).values_list("user__username", flat=True) - ) + users_with_certificates_in_course = GeneratedCertificate.eligible_available_certificates.filter( + course_id=course_key + ).values_list("user__username", flat=True) LOGGER.info( f"Resending course certificates for learners in course {course_key} to the Credentials service. Queueing " @@ -862,8 +789,7 @@ def update_certificate_available_date_on_course_update(self, course_key): if ( course_overview and course_overview.self_paced is False - and course_overview.certificates_display_behavior - == CertificatesDisplayBehaviors.END_WITH_DATE + and course_overview.certificates_display_behavior == CertificatesDisplayBehaviors.END_WITH_DATE ): LOGGER.info( f"Queueing task to update the `certificate_available_date` of course-run {course_key} to " @@ -880,18 +806,12 @@ def update_certificate_available_date_on_course_update(self, course_key): # associated with a `certificate_available_date`. This ends up causing learners' certificate to be incorrectly # hidden. This is due to the Credentials IDA not understanding the concept of course pacing. Thus, we need a way # to remove this value from self-paced courses in Credentials. - elif ( - course_overview - and course_overview.self_paced is True - and course_overview.certificate_available_date is None - ): + elif course_overview and course_overview.self_paced is True and course_overview.certificate_available_date is None: LOGGER.info( "Queueing task to remove the `certificate_available_date` in the Credentials service for course-run " f"{course_key}" ) - update_credentials_course_certificate_configuration_available_date.delay( - str(course_key), None - ) + update_credentials_course_certificate_configuration_available_date.delay(str(course_key), None) # ELSE, we don't meet the criteria to update the course cert config in the Credentials IDA else: LOGGER.warning( diff --git a/openedx/core/djangoapps/programs/tests/test_tasks.py b/openedx/core/djangoapps/programs/tests/test_tasks.py index 5a2518af78..ca97580132 100644 --- a/openedx/core/djangoapps/programs/tests/test_tasks.py +++ b/openedx/core/djangoapps/programs/tests/test_tasks.py @@ -77,16 +77,12 @@ class GetAwardedCertificateProgramsTestCase(TestCase): """ student = UserFactory(username="test-username") mock_get_credentials.return_value = [ - self.make_credential_result( - status="awarded", credential={"program_uuid": 1} - ), + self.make_credential_result(status="awarded", credential={"program_uuid": 1}), ] result = tasks.get_certified_programs(student) assert mock_get_credentials.call_args[0] == (student,) - assert ( - mock_get_credentials.call_args[1].get("credential_type", None) == "program" - ) + assert mock_get_credentials.call_args[1].get("credential_type", None) == "program" assert result == [1] @@ -113,9 +109,7 @@ class AwardProgramCertificateTestCase(TestCase): "http://test-server/credentials/", ) - tasks.award_program_certificate( - test_client, student, 123, datetime(2010, 5, 30) - ) + tasks.award_program_certificate(test_client, student, 123, datetime(2010, 5, 30)) expected_body = { "username": student.username, @@ -141,9 +135,7 @@ class AwardProgramCertificateTestCase(TestCase): @mock.patch(TASKS_MODULE + ".get_certified_programs") @mock.patch(TASKS_MODULE + ".get_completed_programs") @override_settings(CREDENTIALS_SERVICE_USERNAME="test-service-username") -class AwardProgramCertificatesTestCase( - CatalogIntegrationMixin, CredentialsApiConfigMixin, TestCase -): +class AwardProgramCertificatesTestCase(CatalogIntegrationMixin, CredentialsApiConfigMixin, TestCase): """ Tests for the 'award_program_certificates' celery task. """ @@ -194,20 +186,14 @@ class AwardProgramCertificatesTestCase( tasks.award_program_certificates.delay(self.student.username).get() - actual_program_uuids = [ - call[0][2] for call in mock_award_program_certificate.call_args_list - ] + actual_program_uuids = [call[0][2] for call in mock_award_program_certificate.call_args_list] assert actual_program_uuids == expected_awarded_program_uuids - actual_visible_dates = [ - call[0][3] for call in mock_award_program_certificate.call_args_list - ] + actual_visible_dates = [call[0][3] for call in mock_award_program_certificate.call_args_list] assert actual_visible_dates == expected_awarded_program_uuids # program uuids are same as mock dates - @mock.patch( - "openedx.core.djangoapps.site_configuration.helpers.get_current_site_configuration" - ) + @mock.patch("openedx.core.djangoapps.site_configuration.helpers.get_current_site_configuration") def test_awarding_certs_with_skip_program_certificate( self, mocked_get_current_site_configuration, @@ -236,13 +222,9 @@ class AwardProgramCertificatesTestCase( expected_awarded_program_uuids = [3, 4] tasks.award_program_certificates.delay(self.student.username).get() - actual_program_uuids = [ - call[0][2] for call in mock_award_program_certificate.call_args_list - ] + actual_program_uuids = [call[0][2] for call in mock_award_program_certificate.call_args_list] assert actual_program_uuids == expected_awarded_program_uuids - actual_visible_dates = [ - call[0][3] for call in mock_award_program_certificate.call_args_list - ] + actual_visible_dates = [call[0][3] for call in mock_award_program_certificate.call_args_list] assert actual_visible_dates == expected_awarded_program_uuids # program uuids are same as mock dates @@ -250,16 +232,12 @@ class AwardProgramCertificatesTestCase( ("credentials", "enable_learner_issuance"), ) @ddt.unpack - def test_retry_if_config_disabled( - self, disabled_config_type, disabled_config_attribute, *mock_helpers - ): + def test_retry_if_config_disabled(self, disabled_config_type, disabled_config_attribute, *mock_helpers): """ Checks that the task is aborted if any relevant api configs are disabled. """ - getattr(self, f"create_{disabled_config_type}_config")( - **{disabled_config_attribute: False} - ) + getattr(self, f"create_{disabled_config_type}_config")(**{disabled_config_attribute: False}) with mock.patch(TASKS_MODULE + ".LOGGER.warning") as mock_warning: with pytest.raises(MaxRetriesExceededError): tasks.award_program_certificates.delay(self.student.username).get() @@ -371,9 +349,7 @@ class AwardProgramCertificatesTestCase( """ mock_get_completed_programs.return_value = {1: 1, 2: 2} mock_get_certified_programs.side_effect = [[], [2]] - mock_award_program_certificate.side_effect = self._make_side_effect( - [Exception("boom"), None] - ) + mock_award_program_certificate.side_effect = self._make_side_effect([Exception("boom"), None]) with mock.patch(TASKS_MODULE + ".LOGGER.info") as mock_info, mock.patch( TASKS_MODULE + ".LOGGER.exception" @@ -386,25 +362,17 @@ class AwardProgramCertificatesTestCase( uuid=1, username=self.student.username ) ) - mock_info.assert_any_call( - f"Awarded certificate for program {1} to user {self.student.username}" - ) - mock_info.assert_any_call( - f"Awarded certificate for program {2} to user {self.student.username}" - ) + mock_info.assert_any_call(f"Awarded certificate for program {1} to user {self.student.username}") + mock_info.assert_any_call(f"Awarded certificate for program {2} to user {self.student.username}") - def test_retry_on_programs_api_errors( - self, mock_get_completed_programs, *_mock_helpers - ): + def test_retry_on_programs_api_errors(self, mock_get_completed_programs, *_mock_helpers): """ Ensures that any otherwise-unhandled errors that arise while trying to get completed programs (e.g. network issues or other transient API errors) will cause the task to be failed and queued for retry. """ - mock_get_completed_programs.side_effect = self._make_side_effect( - [Exception("boom"), None] - ) + mock_get_completed_programs.side_effect = self._make_side_effect([Exception("boom"), None]) tasks.award_program_certificates.delay(self.student.username).get() assert mock_get_completed_programs.call_count == 3 @@ -422,9 +390,7 @@ class AwardProgramCertificatesTestCase( """ mock_get_completed_programs.return_value = {1: 1, 2: 2} mock_get_certified_programs.return_value = [1] - mock_get_certified_programs.side_effect = self._make_side_effect( - [Exception("boom"), None] - ) + mock_get_certified_programs.side_effect = self._make_side_effect([Exception("boom"), None]) tasks.award_program_certificates.delay(self.student.username).get() assert mock_get_certified_programs.call_count == 2 assert mock_award_program_certificate.call_count == 1 @@ -441,9 +407,7 @@ class AwardProgramCertificatesTestCase( exception = HTTPError() exception.response = mock.Mock(status_code=429) mock_get_completed_programs.return_value = {1: 1, 2: 2} - mock_award_program_certificate.side_effect = self._make_side_effect( - [exception, None] - ) + mock_award_program_certificate.side_effect = self._make_side_effect([exception, None]) tasks.award_program_certificates.delay(self.student.username).get() @@ -461,9 +425,7 @@ class AwardProgramCertificatesTestCase( exception = HTTPError() exception.response = mock.Mock(status_code=404) mock_get_completed_programs.return_value = {1: 1, 2: 2} - mock_award_program_certificate.side_effect = self._make_side_effect( - [exception, None] - ) + mock_award_program_certificate.side_effect = self._make_side_effect([exception, None]) tasks.award_program_certificates.delay(self.student.username).get() @@ -481,9 +443,7 @@ class AwardProgramCertificatesTestCase( exception = HTTPError() exception.response = mock.Mock(status_code=418) mock_get_completed_programs.return_value = {1: 1, 2: 2} - mock_award_program_certificate.side_effect = self._make_side_effect( - [exception, None] - ) + mock_award_program_certificate.side_effect = self._make_side_effect([exception, None]) tasks.award_program_certificates.delay(self.student.username).get() @@ -525,9 +485,7 @@ class PostCourseCertificateTestCase(TestCase): visible_date = datetime.now() - tasks.post_course_certificate( - test_client, self.student.username, self.certificate, visible_date - ) + tasks.post_course_certificate(test_client, self.student.username, self.certificate, visible_date) expected_body = { "username": self.student.username, @@ -541,9 +499,7 @@ class PostCourseCertificateTestCase(TestCase): "attributes": [ { "name": "visible_date", - "value": visible_date.strftime( - "%Y-%m-%dT%H:%M:%SZ" - ), # text representation of date + "value": visible_date.strftime("%Y-%m-%dT%H:%M:%SZ"), # text representation of date } ], } @@ -607,107 +563,79 @@ class AwardCourseCertificatesTestCase(CredentialsApiConfigMixin, TestCase): """ self.certificate.mode = mode self.certificate.save() - tasks.award_course_certificate.delay( - self.student.username, str(self.course.id) - ).get() + tasks.award_course_certificate.delay(self.student.username, str(self.course.id)).get() call_args, _ = mock_post_course_certificate.call_args assert call_args[1] == self.student.username assert call_args[2] == self.certificate assert call_args[3] == self.certificate.modified_date - def test_award_course_certificates_available_date( - self, mock_post_course_certificate - ): + def test_award_course_certificates_available_date(self, mock_post_course_certificate): """ Tests the API POST method is called with available date when the course is not self paced """ self.course.self_paced = False self.course.save() - tasks.award_course_certificate.delay( - self.student.username, str(self.course.id) - ).get() + tasks.award_course_certificate.delay(self.student.username, str(self.course.id)).get() call_args, _ = mock_post_course_certificate.call_args assert call_args[1] == self.student.username assert call_args[2] == self.certificate assert call_args[3] == self.available_date - def test_award_course_certificates_override_date( - self, mock_post_course_certificate - ): + def test_award_course_certificates_override_date(self, mock_post_course_certificate): """ Tests the API POST method is called with date override when present """ self._add_certificate_date_override() - tasks.award_course_certificate.delay( - self.student.username, str(self.course.id) - ).get() + tasks.award_course_certificate.delay(self.student.username, str(self.course.id)).get() call_args, _ = mock_post_course_certificate.call_args assert call_args[1] == self.student.username assert call_args[2] == self.certificate assert call_args[3] == self.certificate.modified_date assert call_args[4] == self.certificate.date_override.date - def test_award_course_cert_not_called_if_disabled( - self, mock_post_course_certificate - ): + def test_award_course_cert_not_called_if_disabled(self, mock_post_course_certificate): """ Test that the post method is never called if the config is disabled """ self.create_credentials_config(enabled=False) with mock.patch(TASKS_MODULE + ".LOGGER.warning") as mock_warning: with pytest.raises(MaxRetriesExceededError): - tasks.award_course_certificate.delay( - self.student.username, str(self.course.id) - ).get() + tasks.award_course_certificate.delay(self.student.username, str(self.course.id)).get() assert mock_warning.called assert not mock_post_course_certificate.called - def test_award_course_cert_not_called_if_user_not_found( - self, mock_post_course_certificate - ): + def test_award_course_cert_not_called_if_user_not_found(self, mock_post_course_certificate): """ Test that the post method is never called if the user isn't found by username """ with mock.patch(TASKS_MODULE + ".LOGGER.exception") as mock_exception: # Use a random username here since this user won't be found in the DB - tasks.award_course_certificate.delay( - "random_username", str(self.course.id) - ).get() + tasks.award_course_certificate.delay("random_username", str(self.course.id)).get() assert mock_exception.called assert not mock_post_course_certificate.called - def test_award_course_cert_not_called_if_certificate_not_found( - self, mock_post_course_certificate - ): + def test_award_course_cert_not_called_if_certificate_not_found(self, mock_post_course_certificate): """ Test that the post method is never called if the certificate doesn't exist for the user and course """ self.certificate.delete() with mock.patch(TASKS_MODULE + ".LOGGER.exception") as mock_exception: - tasks.award_course_certificate.delay( - self.student.username, str(self.course.id) - ).get() + tasks.award_course_certificate.delay(self.student.username, str(self.course.id)).get() assert mock_exception.called assert not mock_post_course_certificate.called - def test_award_course_cert_not_called_if_course_overview_not_found( - self, mock_post_course_certificate - ): + def test_award_course_cert_not_called_if_course_overview_not_found(self, mock_post_course_certificate): """ Test that the post method is never called if the CourseOverview isn't found """ self.course.delete() with mock.patch(TASKS_MODULE + ".LOGGER.exception") as mock_exception: # Use the certificate course id here since the course will be deleted - tasks.award_course_certificate.delay( - self.student.username, str(self.certificate.course_id) - ).get() + tasks.award_course_certificate.delay(self.student.username, str(self.certificate.course_id)).get() assert mock_exception.called assert not mock_post_course_certificate.called - def test_award_course_cert_not_called_if_certificated_not_verified_mode( - self, mock_post_course_certificate - ): + def test_award_course_cert_not_called_if_certificated_not_verified_mode(self, mock_post_course_certificate): """ Test that the post method is never called if the GeneratedCertificate is an 'audit' cert """ @@ -717,9 +645,7 @@ class AwardCourseCertificatesTestCase(CredentialsApiConfigMixin, TestCase): self.certificate.save() self.create_credentials_config() - tasks.award_course_certificate.delay( - self.student.username, str(self.certificate.course_id) - ).get() + tasks.award_course_certificate.delay(self.student.username, str(self.certificate.course_id)).get() assert not mock_post_course_certificate.called @@ -765,9 +691,7 @@ class RevokeProgramCertificateTestCase(TestCase): @mock.patch(TASKS_MODULE + ".get_certified_programs") @mock.patch(TASKS_MODULE + ".get_inverted_programs") @override_settings(CREDENTIALS_SERVICE_USERNAME="test-service-username") -class RevokeProgramCertificatesTestCase( - CatalogIntegrationMixin, CredentialsApiConfigMixin, TestCase -): +class RevokeProgramCertificatesTestCase(CatalogIntegrationMixin, CredentialsApiConfigMixin, TestCase): """ Tests for the 'revoke_program_certificates' celery task. """ @@ -811,9 +735,7 @@ class RevokeProgramCertificatesTestCase( Checks that the Programs API is used correctly to determine completed programs. """ - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() mock_get_inverted_programs.assert_any_call(self.student) def test_revoke_program_certificate( @@ -827,14 +749,10 @@ class RevokeProgramCertificatesTestCase( the proper programs. """ expected_program_uuid = 1 - mock_get_inverted_programs.return_value = { - self.course_key: [{"uuid": expected_program_uuid}] - } + mock_get_inverted_programs.return_value = {self.course_key: [{"uuid": expected_program_uuid}]} mock_get_certified_programs.return_value = [expected_program_uuid] - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() call_args, _ = mock_revoke_program_certificate.call_args assert call_args[1] == self.student.username @@ -844,21 +762,15 @@ class RevokeProgramCertificatesTestCase( ("credentials", "enable_learner_issuance"), ) @ddt.unpack - def test_retry_if_config_disabled( - self, disabled_config_type, disabled_config_attribute, *mock_helpers - ): + def test_retry_if_config_disabled(self, disabled_config_type, disabled_config_attribute, *mock_helpers): """ Checks that the task is aborted if any relevant api configs are disabled. """ - getattr(self, f"create_{disabled_config_type}_config")( - **{disabled_config_attribute: False} - ) + getattr(self, f"create_{disabled_config_type}_config")(**{disabled_config_attribute: False}) with mock.patch(TASKS_MODULE + ".LOGGER.warning") as mock_warning: with pytest.raises(MaxRetriesExceededError): - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_warning.called for mock_helper in mock_helpers: assert not mock_helper.called @@ -869,9 +781,7 @@ class RevokeProgramCertificatesTestCase( passed was not found, and that an exception is logged. """ with mock.patch(TASKS_MODULE + ".LOGGER.exception") as mock_exception: - tasks.revoke_program_certificates.delay( - "nonexistent-username", self.course_key - ).get() + tasks.revoke_program_certificates.delay("nonexistent-username", self.course_key).get() assert mock_exception.called for mock_helper in mock_helpers: assert not mock_helper.called @@ -887,9 +797,7 @@ class RevokeProgramCertificatesTestCase( not part of any program. """ mock_get_inverted_programs.return_value = {} - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_get_inverted_programs.called assert not mock_get_certified_programs.called assert not mock_revoke_program_certificate.called @@ -908,16 +816,12 @@ class RevokeProgramCertificatesTestCase( """ mock_get_inverted_programs.return_value = self.inverted_programs mock_get_certified_programs.side_effect = [[1], [1, 2]] - mock_revoke_program_certificate.side_effect = self._make_side_effect( - [Exception("boom"), None] - ) + mock_revoke_program_certificate.side_effect = self._make_side_effect([Exception("boom"), None]) with mock.patch(TASKS_MODULE + ".LOGGER.info") as mock_info, mock.patch( TASKS_MODULE + ".LOGGER.warning" ) as mock_warning: - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_revoke_program_certificate.call_count == 3 mock_warning.assert_called_once_with( @@ -925,12 +829,8 @@ class RevokeProgramCertificatesTestCase( uuid=1, username=self.student.username ) ) - mock_info.assert_any_call( - f"Revoked certificate for program {1} for user {self.student.username}" - ) - mock_info.assert_any_call( - f"Revoked certificate for program {2} for user {self.student.username}" - ) + mock_info.assert_any_call(f"Revoked certificate for program {1} for user {self.student.username}") + mock_info.assert_any_call(f"Revoked certificate for program {2} for user {self.student.username}") def test_retry_on_credentials_api_errors( self, @@ -946,12 +846,8 @@ class RevokeProgramCertificatesTestCase( """ mock_get_inverted_programs.return_value = self.inverted_programs mock_get_certified_programs.return_value = [1] - mock_get_certified_programs.side_effect = self._make_side_effect( - [Exception("boom"), None] - ) - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + mock_get_certified_programs.side_effect = self._make_side_effect([Exception("boom"), None]) + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_get_certified_programs.call_count == 2 assert mock_revoke_program_certificate.call_count == 1 @@ -968,13 +864,9 @@ class RevokeProgramCertificatesTestCase( exception.response = mock.Mock(status_code=429) mock_get_inverted_programs.return_value = self.inverted_programs mock_get_certified_programs.return_value = [1, 2] - mock_revoke_program_certificate.side_effect = self._make_side_effect( - [exception, None] - ) + mock_revoke_program_certificate.side_effect = self._make_side_effect([exception, None]) - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_revoke_program_certificate.call_count == 3 @@ -991,13 +883,9 @@ class RevokeProgramCertificatesTestCase( exception.response = mock.Mock(status_code=404) mock_get_inverted_programs.return_value = self.inverted_programs mock_get_certified_programs.return_value = [1, 2] - mock_revoke_program_certificate.side_effect = self._make_side_effect( - [exception, None] - ) + mock_revoke_program_certificate.side_effect = self._make_side_effect([exception, None]) - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_revoke_program_certificate.call_count == 2 @@ -1014,13 +902,9 @@ class RevokeProgramCertificatesTestCase( exception.response = mock.Mock(status_code=418) mock_get_inverted_programs.return_value = self.inverted_programs mock_get_certified_programs.return_value = [1, 2] - mock_revoke_program_certificate.side_effect = self._make_side_effect( - [exception, None] - ) + mock_revoke_program_certificate.side_effect = self._make_side_effect([exception, None]) - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_revoke_program_certificate.call_count == 2 @@ -1036,16 +920,12 @@ class RevokeProgramCertificatesTestCase( mock_get_inverted_programs.return_value = self.inverted_programs mock_get_certified_programs.return_value = [1, 2] - with mock.patch( - TASKS_MODULE + ".get_credentials_api_client" - ) as mock_get_api_client, mock.patch( + with mock.patch(TASKS_MODULE + ".get_credentials_api_client") as mock_get_api_client, mock.patch( TASKS_MODULE + ".LOGGER.exception" ) as mock_exception: mock_get_api_client.side_effect = Exception("boom") with pytest.raises(MaxRetriesExceededError): - tasks.revoke_program_certificates.delay( - self.student.username, self.course_key - ).get() + tasks.revoke_program_certificates.delay(self.student.username, self.course_key).get() assert mock_exception.called assert mock_get_api_client.call_count == (tasks.MAX_RETRIES + 1) assert not mock_revoke_program_certificate.called @@ -1070,9 +950,7 @@ class UpdateCredentialsCourseCertificateConfigurationAvailableDateTestCase(TestC self.credentials_worker = UserFactory(username="test-service-username") def test_update_course_cert_available_date(self): - with mock.patch( - TASKS_MODULE + ".post_course_certificate_configuration" - ) as update_posted: + with mock.patch(TASKS_MODULE + ".post_course_certificate_configuration") as update_posted: tasks.update_credentials_course_certificate_configuration_available_date( self.course_id, self.available_date ) @@ -1080,9 +958,7 @@ class UpdateCredentialsCourseCertificateConfigurationAvailableDateTestCase(TestC def test_course_with_two_paid_modes(self): CourseModeFactory.create(course_id=self.course.id, mode_slug="professional") - with mock.patch( - TASKS_MODULE + ".post_course_certificate_configuration" - ) as update_posted: + with mock.patch(TASKS_MODULE + ".post_course_certificate_configuration") as update_posted: tasks.update_credentials_course_certificate_configuration_available_date( self.course_id, self.available_date ) @@ -1119,9 +995,7 @@ class PostCourseCertificateConfigurationTestCase(TestCase): available_date = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ") - tasks.post_course_certificate_configuration( - test_client, self.certificate, available_date - ) + tasks.post_course_certificate_configuration(test_client, self.certificate, available_date) expected_body = { "course_id": "testCourse", @@ -1134,9 +1008,7 @@ class PostCourseCertificateConfigurationTestCase(TestCase): @skip_unless_lms -class UpdateCertificateVisibleDatesOnCourseUpdateTestCase( - CredentialsApiConfigMixin, TestCase -): +class UpdateCertificateVisibleDatesOnCourseUpdateTestCase(CredentialsApiConfigMixin, TestCase): """ Tests for the `update_certificate_visible_date_on_course_update` task. """ @@ -1183,9 +1055,7 @@ class UpdateCertificateVisibleDatesOnCourseUpdateTestCase( exception when the max number of retries has reached. """ with pytest.raises(MaxRetriesExceededError): - tasks.update_certificate_visible_date_on_course_update( - self.course.id - ) # pylint: disable=no-value-for-parameter + tasks.update_certificate_visible_date_on_course_update(self.course.id) # pylint: disable=no-value-for-parameter def test_update_visible_dates(self): """ @@ -1199,20 +1069,14 @@ class UpdateCertificateVisibleDatesOnCourseUpdateTestCase( self.credentials_api_config.enabled = True self.credentials_api_config.enable_learner_issuance = True - with mock.patch( - f"{TASKS_MODULE}.award_course_certificate.delay" - ) as award_course_cert: - tasks.update_certificate_visible_date_on_course_update( - self.course.id - ) # pylint: disable=no-value-for-parameter + with mock.patch(f"{TASKS_MODULE}.award_course_certificate.delay") as award_course_cert: + tasks.update_certificate_visible_date_on_course_update(self.course.id) # pylint: disable=no-value-for-parameter assert award_course_cert.call_count == 3 @skip_unless_lms -class UpdateCertificateAvailableDateOnCourseUpdateTestCase( - CredentialsApiConfigMixin, TestCase -): +class UpdateCertificateAvailableDateOnCourseUpdateTestCase(CredentialsApiConfigMixin, TestCase): """ Tests for the `update_certificate_available_date_on_course_update` task. """ @@ -1236,9 +1100,7 @@ class UpdateCertificateAvailableDateOnCourseUpdateTestCase( course = CourseOverviewFactory.create() with pytest.raises(MaxRetriesExceededError): - tasks.update_certificate_available_date_on_course_update( - course.id - ) # pylint: disable=no-value-for-parameter + tasks.update_certificate_available_date_on_course_update(course.id) # pylint: disable=no-value-for-parameter def test_update_certificate_available_date_with_self_paced_course(self): """ @@ -1251,20 +1113,14 @@ class UpdateCertificateAvailableDateOnCourseUpdateTestCase( self.credentials_api_config.enabled = True self.credentials_api_config.enable_learner_issuance = True - course = CourseOverviewFactory.create( - self_paced=True, certificate_available_date=None - ) + course = CourseOverviewFactory.create(self_paced=True, certificate_available_date=None) with mock.patch( f"{TASKS_MODULE}.update_credentials_course_certificate_configuration_available_date.delay" ) as update_credentials_course_cert_config: - tasks.update_certificate_available_date_on_course_update( - course.id - ) # pylint: disable=no-value-for-parameter + tasks.update_certificate_available_date_on_course_update(course.id) # pylint: disable=no-value-for-parameter - update_credentials_course_cert_config.assert_called_once_with( - str(course.id), None - ) + update_credentials_course_cert_config.assert_called_once_with(str(course.id), None) def test_update_certificate_available_date_with_instructor_paced_course(self): """ @@ -1288,13 +1144,9 @@ class UpdateCertificateAvailableDateOnCourseUpdateTestCase( with mock.patch( f"{TASKS_MODULE}.update_credentials_course_certificate_configuration_available_date.delay" ) as update_credentials_course_cert_config: - tasks.update_certificate_available_date_on_course_update( - course.id - ) # pylint: disable=no-value-for-parameter + tasks.update_certificate_available_date_on_course_update(course.id) # pylint: disable=no-value-for-parameter - update_credentials_course_cert_config.assert_called_once_with( - str(course.id), str(available_date) - ) + update_credentials_course_cert_config.assert_called_once_with(str(course.id), str(available_date)) def test_update_certificate_available_date_with_expect_no_update(self): """ @@ -1318,9 +1170,7 @@ class UpdateCertificateAvailableDateOnCourseUpdateTestCase( ) with LogCapture(level=logging.WARNING) as log_capture: - tasks.update_certificate_available_date_on_course_update( - course.id - ) # pylint: disable=no-value-for-parameter + tasks.update_certificate_available_date_on_course_update(course.id) # pylint: disable=no-value-for-parameter assert len(log_capture.records) == 1 assert log_capture.records[0].getMessage() == expected_message