diff --git a/openedx/core/djangoapps/ccxcon/api.py b/openedx/core/djangoapps/ccxcon/api.py index 8c99b86423..7be3b56751 100644 --- a/openedx/core/djangoapps/ccxcon/api.py +++ b/openedx/core/djangoapps/ccxcon/api.py @@ -4,9 +4,8 @@ Module containing API functions for the CCXCon import logging +from urllib import parse -import six -import six.moves.urllib.parse # lint-amnesty, pylint: disable=import-error, wrong-import-order from django.core.exceptions import ValidationError from django.core.validators import URLValidator from django.http import Http404 @@ -92,31 +91,31 @@ def course_info_to_ccxcon(course_key): try: course = get_course_by_id(course_key) except Http404: - log.error(u'Master Course with key "%s" not found', six.text_type(course_key)) + log.error('Master Course with key "%s" not found', str(course_key)) return if not course.enable_ccx: - log.debug(u'ccx not enabled for course key "%s"', six.text_type(course_key)) + log.debug('ccx not enabled for course key "%s"', str(course_key)) return if not course.ccx_connector: - log.debug(u'ccx connector not defined for course key "%s"', six.text_type(course_key)) + log.debug('ccx connector not defined for course key "%s"', str(course_key)) return if not is_valid_url(course.ccx_connector): log.error( - u'ccx connector URL "%s" for course key "%s" is not a valid URL.', - course.ccx_connector, six.text_type(course_key) + 'ccx connector URL "%s" for course key "%s" is not a valid URL.', + course.ccx_connector, str(course_key) ) return # get the oauth credential for this URL try: ccxcon = CCXCon.objects.get(url=course.ccx_connector) except CCXCon.DoesNotExist: - log.error(u'ccx connector Oauth credentials not configured for URL "%s".', course.ccx_connector) + log.error('ccx connector Oauth credentials not configured for URL "%s".', course.ccx_connector) return # get an oauth client with a valid token oauth_ccxcon = get_oauth_client( - server_token_url=six.moves.urllib.parse.urljoin(course.ccx_connector, CCXCON_TOKEN_URL), + server_token_url=parse.urljoin(course.ccx_connector, CCXCON_TOKEN_URL), client_id=ccxcon.oauth_client_id, client_secret=ccxcon.oauth_client_secret ) @@ -129,7 +128,7 @@ def course_info_to_ccxcon(course_key): course_details = CourseDetails.fetch(course_key) payload = { - 'course_id': six.text_type(course_key), + 'course_id': str(course_key), 'title': course.display_name, 'author_name': None, 'overview': course_details.overview, @@ -140,7 +139,7 @@ def course_info_to_ccxcon(course_key): headers = {'content-type': 'application/json'} # make the POST request - add_course_url = six.moves.urllib.parse.urljoin(course.ccx_connector, CCXCON_COURSEXS_URL) + add_course_url = parse.urljoin(course.ccx_connector, CCXCON_COURSEXS_URL) resp = oauth_ccxcon.post( url=add_course_url, json=payload, @@ -149,11 +148,11 @@ def course_info_to_ccxcon(course_key): ) if resp.status_code >= 500: - raise CCXConnServerError(u'Server returned error Status: %s, Content: %s', resp.status_code, resp.content) # lint-amnesty, pylint: disable=raising-format-tuple + raise CCXConnServerError('Server returned error Status: %s, Content: %s', resp.status_code, resp.content) # lint-amnesty, pylint: disable=raising-format-tuple if resp.status_code >= 400: - log.error(u"Error creating course on ccxcon. Status: %s, Content: %s", resp.status_code, resp.content) + log.error("Error creating course on ccxcon. Status: %s, Content: %s", resp.status_code, resp.content) # this API performs a POST request both for POST and PATCH, but the POST returns 201 and the PATCH returns 200 elif resp.status_code != HTTP_200_OK and resp.status_code != HTTP_201_CREATED: - log.error(u'Server returned unexpected status code %s', resp.status_code) + log.error('Server returned unexpected status code %s', resp.status_code) else: - log.debug(u'Request successful. Status: %s, Content: %s', resp.status_code, resp.content) + log.debug('Request successful. Status: %s, Content: %s', resp.status_code, resp.content) diff --git a/openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py b/openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py index deb4906fa3..5d8062832a 100644 --- a/openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py +++ b/openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models diff --git a/openedx/core/djangoapps/ccxcon/models.py b/openedx/core/djangoapps/ccxcon/models.py index 20b52dc2dc..1454bb2919 100644 --- a/openedx/core/djangoapps/ccxcon/models.py +++ b/openedx/core/djangoapps/ccxcon/models.py @@ -20,13 +20,13 @@ class CCXCon(models.Model): oauth_client_secret = models.CharField(max_length=255) title = models.CharField(max_length=255) - class Meta(object): + class Meta: app_label = 'ccxcon' verbose_name = 'CCX Connector' verbose_name_plural = 'CCX Connectors' def __repr__(self): - return ''.format(self.title) + return f'' def __str__(self): return self.title diff --git a/openedx/core/djangoapps/ccxcon/signals.py b/openedx/core/djangoapps/ccxcon/signals.py index b4baa55685..35664665f6 100644 --- a/openedx/core/djangoapps/ccxcon/signals.py +++ b/openedx/core/djangoapps/ccxcon/signals.py @@ -1,9 +1,6 @@ """ Signal handler for posting course updated to CCXCon """ - - -import six from django.dispatch.dispatcher import receiver from xmodule.modulestore.django import SignalHandler @@ -18,4 +15,4 @@ def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable # update the course information on ccxcon using celery # import here, because signal is registered at startup, but items in tasks are not yet able to be loaded from openedx.core.djangoapps.ccxcon import tasks - tasks.update_ccxcon.delay(six.text_type(course_key)) + tasks.update_ccxcon.delay(str(course_key)) diff --git a/openedx/core/djangoapps/ccxcon/tasks.py b/openedx/core/djangoapps/ccxcon/tasks.py index 65e7d0f085..d5d25f943c 100644 --- a/openedx/core/djangoapps/ccxcon/tasks.py +++ b/openedx/core/djangoapps/ccxcon/tasks.py @@ -28,9 +28,9 @@ def update_ccxcon(course_id, cur_retry=0): course_key = CourseKey.from_string(course_id) try: api.course_info_to_ccxcon(course_key) - log.info(u'Course update to CCXCon returned no errors. Course key: %s', course_id) + log.info('Course update to CCXCon returned no errors. Course key: %s', course_id) except (ConnectionError, HTTPError, RequestException, TooManyRedirects, api.CCXConnServerError) as exp: - log.error(u'Course update to CCXCon failed for course_id %s with error: %s', course_id, exp) + log.error('Course update to CCXCon failed for course_id %s with error: %s', course_id, exp) # in case the maximum amount of retries has not been reached, # insert another task delayed exponentially up to 5 retries if cur_retry < 5: @@ -38,4 +38,4 @@ def update_ccxcon(course_id, cur_retry=0): kwargs={'course_id': course_id, 'cur_retry': cur_retry + 1}, countdown=10 ** cur_retry # number of seconds the task should be delayed ) - log.info(u'Requeued celery task for course key %s ; retry # %s', course_id, cur_retry + 1) + log.info('Requeued celery task for course key %s ; retry # %s', course_id, cur_retry + 1) diff --git a/openedx/core/djangoapps/ccxcon/tests/factories.py b/openedx/core/djangoapps/ccxcon/tests/factories.py index 7d2e3258c7..56afa8b0b2 100644 --- a/openedx/core/djangoapps/ccxcon/tests/factories.py +++ b/openedx/core/djangoapps/ccxcon/tests/factories.py @@ -12,7 +12,7 @@ class CcxConFactory(DjangoModelFactory): """ Model factory for the CCXCon model """ - class Meta(object): + class Meta: model = CCXCon oauth_client_id = 'asdfjasdljfasdkjffsdfjksd98fsd8y24fdsiuhsfdsf' diff --git a/openedx/core/djangoapps/ccxcon/tests/test_api.py b/openedx/core/djangoapps/ccxcon/tests/test_api.py index 113646e51e..a44a921116 100644 --- a/openedx/core/djangoapps/ccxcon/tests/test_api.py +++ b/openedx/core/djangoapps/ccxcon/tests/test_api.py @@ -1,15 +1,13 @@ """ Unit tests for the API module """ - - import datetime +from unittest import mock +from urllib import parse + import pytest -import mock import pytz -import six.moves.urllib.parse # lint-amnesty, pylint: disable=import-error, wrong-import-order from opaque_keys.edx.keys import CourseKey -from six.moves import range from openedx.core.djangoapps.ccxcon import api as ccxconapi from common.djangoapps.student.tests.factories import AdminFactory @@ -42,7 +40,7 @@ class APIsTestCase(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(APIsTestCase, cls).setUpClass() + super().setUpClass() cls.course = course = CourseFactory.create() cls.course_key = cls.course.location.course_key @@ -65,7 +63,7 @@ class APIsTestCase(SharedModuleStoreTestCase): cls.verticals = flatten([ [ ItemFactory.create( - start=start, due=due, parent=sequential, graded=True, format='Homework', category=u'vertical' + start=start, due=due, parent=sequential, graded=True, format='Homework', category='vertical' ) for _ in range(2) ] for sequential in cls.sequentials ]) @@ -83,7 +81,7 @@ class APIsTestCase(SharedModuleStoreTestCase): """ Set up tests """ - super(APIsTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Create instructor account self.instructor = AdminFactory.create() # create an instance of modulestore @@ -163,7 +161,7 @@ class APIsTestCase(SharedModuleStoreTestCase): # no args used for the call assert k_args == tuple() assert k_kwargs.get('url') ==\ - six.moves.urllib.parse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL) + parse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL) # second call with different status code mock_response.status_code = 200 @@ -176,7 +174,7 @@ class APIsTestCase(SharedModuleStoreTestCase): # no args used for the call assert k_args == tuple() assert k_kwargs.get('url') ==\ - six.moves.urllib.parse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL) + parse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL) @mock.patch('requests_oauthlib.oauth2_session.OAuth2Session.fetch_token', fetch_token_mock) @mock.patch('requests_oauthlib.oauth2_session.OAuth2Session.post') diff --git a/openedx/core/djangoapps/ccxcon/tests/test_signals.py b/openedx/core/djangoapps/ccxcon/tests/test_signals.py index 2a4a225ca2..ec3c61c3fb 100644 --- a/openedx/core/djangoapps/ccxcon/tests/test_signals.py +++ b/openedx/core/djangoapps/ccxcon/tests/test_signals.py @@ -3,7 +3,7 @@ Test for contentstore signals receiver """ -import mock +from unittest import mock from django.test import TestCase from opaque_keys.edx.keys import CourseKey @@ -26,7 +26,7 @@ class CCXConSignalTestCase(TestCase): mock_response = mock.MagicMock(return_value=None) mock_upc.return_value = mock_response - course_id = u'course-v1:OrgFoo+CN199+CR-FALL01' + course_id = 'course-v1:OrgFoo+CN199+CR-FALL01' course_key = CourseKey.from_string(course_id) signal_handler = SignalHandler(modulestore()) diff --git a/openedx/core/djangoapps/ccxcon/tests/test_tasks.py b/openedx/core/djangoapps/ccxcon/tests/test_tasks.py index 8885ab6dd5..309b465bd4 100644 --- a/openedx/core/djangoapps/ccxcon/tests/test_tasks.py +++ b/openedx/core/djangoapps/ccxcon/tests/test_tasks.py @@ -3,7 +3,7 @@ Tests for the CCXCon celery tasks """ -import mock +from unittest import mock from django.test import TestCase from opaque_keys.edx.keys import CourseKey @@ -23,7 +23,7 @@ class CCXConTaskTestCase(TestCase): mock_response = mock.Mock() mock_citc.return_value = mock_response - course_id = u'course-v1:OrgFoo+CN199+CR-FALL01' + course_id = 'course-v1:OrgFoo+CN199+CR-FALL01' tasks.update_ccxcon.delay(course_id) mock_citc.assert_called_once_with(CourseKey.from_string(course_id)) @@ -34,7 +34,7 @@ class CCXConTaskTestCase(TestCase): Test task with exception that triggers a retry """ mock_citc.side_effect = api.CCXConnServerError() - course_id = u'course-v1:OrgFoo+CN199+CR-FALL01' + course_id = 'course-v1:OrgFoo+CN199+CR-FALL01' tasks.update_ccxcon.delay(course_id) assert mock_citc.call_count == 6 diff --git a/openedx/core/djangoapps/certificates/api.py b/openedx/core/djangoapps/certificates/api.py index ee01cb2ced..bfcbc32542 100644 --- a/openedx/core/djangoapps/certificates/api.py +++ b/openedx/core/djangoapps/certificates/api.py @@ -6,7 +6,6 @@ The public API for certificates. import logging from datetime import datetime -import six # lint-amnesty, pylint: disable=unused-import from pytz import UTC from lms.djangoapps.certificates.models import CertificateStatuses, CertificateWhitelist diff --git a/openedx/core/djangoapps/certificates/config/waffle.py b/openedx/core/djangoapps/certificates/config/waffle.py index fad252530a..af01915d71 100644 --- a/openedx/core/djangoapps/certificates/config/waffle.py +++ b/openedx/core/djangoapps/certificates/config/waffle.py @@ -7,14 +7,14 @@ waffle switches for the Certificates app. from edx_toggles.toggles import LegacyWaffleSwitchNamespace # Namespace -WAFFLE_NAMESPACE = u'certificates' +WAFFLE_NAMESPACE = 'certificates' # Switches -AUTO_CERTIFICATE_GENERATION = u'auto_certificate_generation' +AUTO_CERTIFICATE_GENERATION = 'auto_certificate_generation' def waffle(): """ Returns the namespaced, cached, audited Waffle class for Certificates. """ - return LegacyWaffleSwitchNamespace(name=WAFFLE_NAMESPACE, log_prefix=u'Certificates: ') + return LegacyWaffleSwitchNamespace(name=WAFFLE_NAMESPACE, log_prefix='Certificates: ') diff --git a/openedx/core/djangoapps/certificates/tests/test_api.py b/openedx/core/djangoapps/certificates/tests/test_api.py index 4502329897..7a5c27caeb 100644 --- a/openedx/core/djangoapps/certificates/tests/test_api.py +++ b/openedx/core/djangoapps/certificates/tests/test_api.py @@ -1,5 +1,3 @@ - - import itertools from contextlib import contextmanager from datetime import datetime, timedelta @@ -20,7 +18,7 @@ from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, U # TODO: Copied from lms.djangoapps.certificates.models, # to be resolved per https://openedx.atlassian.net/browse/EDUCATOR-1318 -class CertificateStatuses(object): +class CertificateStatuses: """ Enum for certificate statuses """ @@ -45,7 +43,7 @@ class CertificateStatuses(object): ) -class MockGeneratedCertificate(object): +class MockGeneratedCertificate: """ We can't import GeneratedCertificate from LMS here, so we roll our own minimal Certificate model for testing. @@ -76,7 +74,7 @@ def configure_waffle_namespace(feature_enabled): @ddt.ddt class CertificatesApiTestCase(TestCase): def setUp(self): - super(CertificatesApiTestCase, self).setUp() + super().setUp() self.course = CourseOverviewFactory.create( start=datetime(2017, 1, 1, tzinfo=pytz.UTC), end=datetime(2017, 1, 31, tzinfo=pytz.UTC),