pyupgrade in program_enrollments (#26597)

This commit is contained in:
M. Zulqarnain
2021-02-22 12:58:16 +05:00
committed by GitHub
parent b6a2b91dd5
commit f4a5af29d3
40 changed files with 176 additions and 196 deletions

View File

@@ -116,7 +116,7 @@ def _pending_role_assignment_enrollment_id(pending_role_assignment):
"admin:program_enrollments_programcourseenrollment_change",
args=[pce.id],
)
link_text = "id={pce.id:05}".format(pce=pce)
link_text = f"id={pce.id:05}"
return format_html("<a href={}>{}</a>", link_url, link_text)

View File

@@ -8,10 +8,8 @@ from `lms.djangoapps.program_enrollments.api`.
import logging
from six import text_type
from lms.djangoapps.grades.api import CourseGradeFactory, clear_prefetched_course_grades, prefetch_course_grades
from common.djangoapps.util.query import read_replica_or_default
from lms.djangoapps.grades.api import CourseGradeFactory, clear_prefetched_course_grades, prefetch_course_grades
from .reading import fetch_program_course_enrollments
@@ -74,7 +72,7 @@ def _generate_grades(course_key, enrollments):
error_string = error_template.format(
user.id,
course_key,
text_type(exception) if exception else 'Unknown error'
str(exception) if exception else 'Unknown error'
)
logger.error(error_string)
yield ProgramCourseGradeError(enrollment, exception)
@@ -82,7 +80,7 @@ def _generate_grades(course_key, enrollments):
clear_prefetched_course_grades(course_key)
class BaseProgramCourseGrade(object):
class BaseProgramCourseGrade:
"""
Base for either a courserun grade or grade-loading failure.
@@ -109,7 +107,7 @@ class ProgramCourseGradeOk(BaseProgramCourseGrade):
Given a ProgramCourseEnrollment and course grade object,
create a ProgramCourseGradeOk.
"""
super(ProgramCourseGradeOk, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(
program_course_enrollment
)
self.passed = course_grade.passed
@@ -129,7 +127,7 @@ class ProgramCourseGradeError(BaseProgramCourseGrade):
Given a ProgramCourseEnrollment and an Exception,
create a ProgramCourseGradeError.
"""
super(ProgramCourseGradeError, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments
super().__init__(
program_course_enrollment
)
self.error = text_type(exception) if exception else "Unknown error"
self.error = str(exception) if exception else "Unknown error"

View File

@@ -9,9 +9,9 @@ from `lms.djangoapps.program_enrollments.api`.
from organizations.models import Organization
from social_django.models import UserSocialAuth
from openedx.core.djangoapps.catalog.utils import get_programs
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.third_party_auth.models import SAMLProviderConfig
from openedx.core.djangoapps.catalog.utils import get_programs
from ..constants import ProgramCourseEnrollmentRoles
from ..exceptions import (

View File

@@ -3,23 +3,23 @@ Tests for account linking Python API.
"""
from unittest.mock import patch
from uuid import uuid4
from unittest.mock import patch
from django.test import TestCase
from edx_django_utils.cache import RequestCache
from opaque_keys.edx.keys import CourseKey
from testfixtures import LogCapture
from common.djangoapps.student.api import get_course_access_role
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseAccessRoleFactory, UserFactory
from lms.djangoapps.program_enrollments.tests.factories import (
CourseAccessRoleAssignmentFactory,
ProgramCourseEnrollmentFactory,
ProgramEnrollmentFactory
)
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from common.djangoapps.student.api import get_course_access_role
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseAccessRoleFactory, UserFactory
from ..linking import (
NO_LMS_USER_TEMPLATE,
@@ -31,7 +31,7 @@ from ..linking import (
LOG_PATH = 'lms.djangoapps.program_enrollments.api.linking'
class TestLinkProgramEnrollmentsMixin(object):
class TestLinkProgramEnrollmentsMixin:
""" Utility methods and test data for testing linking """
@classmethod

View File

@@ -14,6 +14,9 @@ from organizations.tests.factories import OrganizationFactory
from social_django.models import UserSocialAuth
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from lms.djangoapps.program_enrollments.constants import ProgramCourseEnrollmentStatuses as PCEStatuses
from lms.djangoapps.program_enrollments.constants import ProgramEnrollmentStatuses as PEStatuses
from lms.djangoapps.program_enrollments.exceptions import (
@@ -33,9 +36,6 @@ from openedx.core.djangoapps.catalog.tests.factories import OrganizationFactory
from openedx.core.djangoapps.catalog.tests.factories import ProgramFactory
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from ..reading import (
fetch_program_course_enrollments,
@@ -78,7 +78,7 @@ class ProgramEnrollmentReadingTests(TestCase):
@classmethod
def setUpTestData(cls):
super(ProgramEnrollmentReadingTests, cls).setUpTestData()
super().setUpTestData()
cls.user_0 = UserFactory(username=cls.username_0) # No enrollments
cls.user_1 = UserFactory(username=cls.username_1)
cls.user_2 = UserFactory(username=cls.username_2)
@@ -495,7 +495,7 @@ class GetUsersByExternalKeysTests(CacheIsolationTestCase):
@classmethod
def setUpTestData(cls):
super(GetUsersByExternalKeysTests, cls).setUpTestData()
super().setUpTestData()
cls.program_uuid = UUID('e7a82f8d-d485-486b-b733-a28222af92bf')
cls.organization_key = 'ufo'
cls.external_user_id = '1234'
@@ -504,7 +504,7 @@ class GetUsersByExternalKeysTests(CacheIsolationTestCase):
cls.user_2 = UserFactory(username='user-2')
def setUp(self):
super(GetUsersByExternalKeysTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
catalog_org = CatalogOrganizationFactory.create(key=self.organization_key)
program = ProgramFactory.create(
uuid=self.program_uuid,
@@ -518,7 +518,7 @@ class GetUsersByExternalKeysTests(CacheIsolationTestCase):
"""
UserSocialAuth.objects.create(
user=user,
uid='{0}:{1}'.format(provider.slug, external_id),
uid=f'{provider.slug}:{external_id}',
provider=provider.backend_name,
)
@@ -637,7 +637,7 @@ class IsCourseStaffEnrollmentTest(TestCase):
@classmethod
def setUpTestData(cls):
super(IsCourseStaffEnrollmentTest, cls).setUpTestData()
super().setUpTestData()
cls.user_0 = UserFactory(username=cls.username_0) # No enrollments
CourseOverviewFactory(id=cls.course_key_p)
CourseOverviewFactory(id=cls.course_key_q)

View File

@@ -17,6 +17,9 @@ from opaque_keys.edx.keys import CourseKey
from organizations.tests.factories import OrganizationFactory
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from lms.djangoapps.program_enrollments.constants import ProgramCourseEnrollmentRoles
from lms.djangoapps.program_enrollments.constants import ProgramCourseOperationStatuses as CourseStatuses
from lms.djangoapps.program_enrollments.constants import ProgramEnrollmentStatuses as PEStatuses
@@ -32,9 +35,6 @@ from openedx.core.djangoapps.catalog.tests.factories import OrganizationFactory
from openedx.core.djangoapps.catalog.tests.factories import ProgramFactory
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from ..writing import write_program_course_enrollments, write_program_enrollments
@@ -56,7 +56,7 @@ class EnrollmentTestMixin(CacheIsolationTestCase):
"""
Set up test data
"""
super(EnrollmentTestMixin, cls).setUpClass()
super().setUpClass()
catalog_org = CatalogOrganizationFactory.create(key=cls.organization_key)
cls.program = ProgramFactory.create(
uuid=cls.program_uuid,
@@ -66,7 +66,7 @@ class EnrollmentTestMixin(CacheIsolationTestCase):
SAMLProviderConfigFactory.create(organization=organization)
catalog_course_id_str = 'course-v1:edX+ToyX'
course_run_id_str = '{}+Toy_Course'.format(catalog_course_id_str)
course_run_id_str = f'{catalog_course_id_str}+Toy_Course'
cls.course_id = CourseKey.from_string(course_run_id_str)
CourseOverviewFactory(id=cls.course_id)
course_run = CourseRunFactory(key=course_run_id_str)
@@ -75,7 +75,7 @@ class EnrollmentTestMixin(CacheIsolationTestCase):
cls.student_2 = UserFactory(username='student-2')
def setUp(self):
super(EnrollmentTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
cache.set(PROGRAM_CACHE_KEY_TPL.format(uuid=self.program_uuid), self.program, None)
def create_program_enrollment(self, external_user_key, user=False):

View File

@@ -11,9 +11,9 @@ import logging
from simple_history.utils import bulk_create_with_history
from common.djangoapps.course_modes.models import CourseMode
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from common.djangoapps.student.models import CourseEnrollment, NonExistentCourseError
from common.djangoapps.student.roles import CourseStaffRole
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from ..constants import ProgramCourseEnrollmentRoles, ProgramCourseEnrollmentStatuses
from ..constants import ProgramCourseOperationStatuses as ProgramCourseOpStatuses
@@ -390,7 +390,7 @@ def enroll_in_masters_track(user, course_key, status):
"""
_ensure_course_exists(course_key, user.id)
if status not in ProgramCourseEnrollmentStatuses.__ALL__:
raise ValueError("invalid ProgramCourseEnrollmentStatus: {}".format(status))
raise ValueError(f"invalid ProgramCourseEnrollmentStatus: {status}")
if CourseEnrollment.is_enrolled(user, course_key):
course_enrollment = CourseEnrollment.objects.get(
user=user,
@@ -552,8 +552,8 @@ def _get_conflicting_active_course_enrollments(
and str(existing_enrollment.program_enrollment.program_uuid) != str(program_uuid)
):
logger.error(
u'Detected conflicting active ProgramCourseEnrollment. This is happening on'
u' The program_uuid [{}] with course_key [{}] for external_user_key [{}]'.format(
'Detected conflicting active ProgramCourseEnrollment. This is happening on'
' The program_uuid [{}] with course_key [{}] for external_user_key [{}]'.format(
program_uuid,
course_key,
external_user_key

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
ProgramEnrollments Application Configuration
"""

View File

@@ -5,7 +5,7 @@ in-process apps through api.py.
from common.djangoapps.student.roles import CourseStaffRole
class ProgramEnrollmentStatuses(object):
class ProgramEnrollmentStatuses:
"""
Status that a user may have enrolled in a program.
@@ -26,7 +26,7 @@ class ProgramEnrollmentStatuses(object):
)
class ProgramCourseEnrollmentStatuses(object):
class ProgramCourseEnrollmentStatuses:
"""
Status that a user may have enrolled in a course.
@@ -43,7 +43,7 @@ class ProgramCourseEnrollmentStatuses(object):
)
class _EnrollmentErrorStatuses(object):
class _EnrollmentErrorStatuses:
"""
Error statuses common to program and program-course enrollments responses.
"""
@@ -116,7 +116,7 @@ class ProgramCourseOperationStatuses(
__ALL__ = __OK__ + __ERRORS__
class ProgramCourseEnrollmentRoles(object):
class ProgramCourseEnrollmentRoles:
"""
Valid roles that can be assigned as part of a ProgramCourseEnrollment
"""

View File

@@ -15,7 +15,7 @@ class ProgramDoesNotExistException(Exception):
self.program_uuid = program_uuid
def __str__(self):
return 'Unable to find catalog program matching uuid {}'.format(self.program_uuid)
return f'Unable to find catalog program matching uuid {self.program_uuid}'
class OrganizationDoesNotExistException(Exception):

View File

@@ -95,7 +95,7 @@ class Command(BaseCommand):
email=email,
slug=slug
))
auth.uid = '{slug}:{uid}'.format(slug=slug, uid=uid)
auth.uid = f'{slug}:{uid}'
auth.save()
not_previously_linked, updated, duplicated_in_mapping = \

View File

@@ -11,10 +11,9 @@ from textwrap import dedent
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from six.moves import input
from lms.djangoapps.program_enrollments.models import ProgramEnrollment
from common.djangoapps.student.models import CourseEnrollment
from lms.djangoapps.program_enrollments.models import ProgramEnrollment
log = logging.getLogger(__name__)

View File

@@ -1,12 +1,12 @@
"""
Tests for the expire_waiting_enrollments management command.
"""
from unittest.mock import patch
import pytest
import ddt
from django.core.management import call_command
from django.test import TestCase
from mock import patch
from lms.djangoapps.program_enrollments.management.commands import expire_waiting_enrollments
@@ -17,7 +17,7 @@ class TestExpireWaitingEnrollments(TestCase):
@classmethod
def setUpClass(cls):
super(TestExpireWaitingEnrollments, cls).setUpClass()
super().setUpClass()
cls.command = expire_waiting_enrollments.Command()
@ddt.data(90, None)

View File

@@ -3,9 +3,9 @@ Tests for the link_program_enrollments management command.
"""
from unittest import mock
from uuid import UUID
import mock
from django.core.management import call_command
from django.core.management.base import CommandError
from django.test import TestCase

View File

@@ -1,17 +1,15 @@
"""
Tests for the migrate_saml_uids management command.
"""
from unittest.mock import mock_open, patch
import six
from django.core.management import call_command
from django.test import TestCase
from mock import mock_open, patch
from social_django.models import UserSocialAuth
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.program_enrollments.management.commands import migrate_saml_uids
from lms.djangoapps.program_enrollments.management.commands.tests.utils import UserSocialAuthFactory
from common.djangoapps.student.tests.factories import UserFactory
_COMMAND_PATH = 'lms.djangoapps.program_enrollments.management.commands.migrate_saml_uids'
@@ -24,11 +22,11 @@ class TestMigrateSamlUids(TestCase):
@classmethod
def setUpClass(cls):
super(TestMigrateSamlUids, cls).setUpClass()
super().setUpClass()
cls.command = migrate_saml_uids.Command()
def _format_email_uid_pair(self, email, uid):
return '{{"email":"{email}","student_key":"{new_urn}"}}'.format(email=email, new_urn=uid)
return f'{{"email":"{email}","student_key":"{uid}"}}'
def _format_single_email_uid_pair_json(self, email, uid):
return '[{obj}]'.format(
@@ -50,7 +48,7 @@ class TestMigrateSamlUids(TestCase):
)
def _format_slug_urn_pair(self, slug, urn):
return '{slug}:{urn}'.format(slug=slug, urn=urn)
return f'{slug}:{urn}'
def test_single_mapping(self):
new_urn = '9001'
@@ -111,8 +109,8 @@ class TestMigrateSamlUids(TestCase):
self._call_command(self._format_single_email_uid_pair_json(email, new_urn))
mock_info.assert_any_call(
u'Number of users identified in the mapping file without'
u' {slug} UserSocialAuth records: 1'.format(
'Number of users identified in the mapping file without'
' {slug} UserSocialAuth records: 1'.format(
slug=self.provider_slug
)
)
@@ -128,8 +126,8 @@ class TestMigrateSamlUids(TestCase):
self._call_command(self._format_single_email_uid_pair_json('different' + email, new_urn))
mock_info.assert_any_call(
u'Number of users with {slug} UserSocialAuth records '
u'for which there was no mapping in the provided file: 1'.format(
'Number of users with {slug} UserSocialAuth records '
'for which there was no mapping in the provided file: 1'.format(
slug=self.provider_slug
)
)
@@ -146,7 +144,7 @@ class TestMigrateSamlUids(TestCase):
[
self._format_email_uid_pair(
auth.user.email,
new_urn + six.text_type(ind)
new_urn + str(ind)
)
for ind, auth
in enumerate(auths)
@@ -156,8 +154,8 @@ class TestMigrateSamlUids(TestCase):
for ind, auth in enumerate(auths):
auth.refresh_from_db()
assert auth.uid == self._format_slug_urn_pair(self.provider_slug, new_urn + six.text_type(ind))
mock_info.assert_any_call(u'Number of mappings in the mapping file updated: 5')
assert auth.uid == self._format_slug_urn_pair(self.provider_slug, new_urn + str(ind))
mock_info.assert_any_call('Number of mappings in the mapping file updated: 5')
@patch(_COMMAND_PATH + '.log')
def test_learner_duplicated_in_mapping(self, mock_log):
@@ -170,5 +168,5 @@ class TestMigrateSamlUids(TestCase):
self._call_command('[{}]'.format(
','.join([self._format_email_uid_pair(email, new_urn) for _ in range(5)])
))
mock_info.assert_any_call(u'Number of mappings in the mapping file where the '
u'identified user has already been processed: 4')
mock_info.assert_any_call('Number of mappings in the mapping file where the '
'identified user has already been processed: 4')

View File

@@ -12,11 +12,11 @@ from django.core.management.base import CommandError
from django.test import TestCase
from six import StringIO
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.program_enrollments.management.commands import reset_enrollment_data
from lms.djangoapps.program_enrollments.models import ProgramCourseEnrollment, ProgramEnrollment
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import UserFactory
class TestResetEnrollmentData(TestCase):
@@ -24,12 +24,12 @@ class TestResetEnrollmentData(TestCase):
@classmethod
def setUpClass(cls):
super(TestResetEnrollmentData, cls).setUpClass()
super().setUpClass()
cls.command = reset_enrollment_data.Command()
cls.program_uuid = uuid4()
def setUp(self):
super(TestResetEnrollmentData, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory()
@contextmanager
@@ -105,6 +105,6 @@ class TestResetEnrollmentData(TestCase):
alt_user = UserFactory()
self._create_program_and_course_enrollment(alt_program_uuid, alt_user)
call_command(self.command, '{},{}'.format(self.program_uuid, alt_program_uuid), force=True)
call_command(self.command, f'{self.program_uuid},{alt_program_uuid}', force=True)
self._validate_enrollments_count(0)

View File

@@ -13,10 +13,10 @@ class UserSocialAuthFactory(DjangoModelFactory):
"""
Factory for UserSocialAuth records.
"""
class Meta(object):
class Meta:
model = UserSocialAuth
user = SubFactory(UserFactory)
uid = LazyAttributeSequence(lambda o, n: '%s:%d' % (o.slug, n))
class Params(object):
class Params:
slug = 'gatech'

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-09 19:32

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-19 16:48

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-24 16:22
@@ -16,6 +15,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterUniqueTogether(
name='programenrollment',
unique_together=set([('user', 'external_user_key', 'program_uuid', 'curriculum_uuid')]),
unique_together={('user', 'external_user_key', 'program_uuid', 'curriculum_uuid')},
),
]

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-01 21:46

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-06-03 13:14

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.23 on 2019-08-23 15:37
@@ -16,6 +15,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterUniqueTogether(
name='programenrollment',
unique_together=set([('user', 'program_uuid', 'curriculum_uuid'), ('external_user_key', 'program_uuid', 'curriculum_uuid')]),
unique_together={('user', 'program_uuid', 'curriculum_uuid'), ('external_user_key', 'program_uuid', 'curriculum_uuid')},
),
]

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.23 on 2019-08-27 13:11
@@ -14,6 +13,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterUniqueTogether(
name='programcourseenrollment',
unique_together=set([('program_enrollment', 'course_key')]),
unique_together={('program_enrollment', 'course_key')},
),
]

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.24 on 2019-10-09 16:49

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-02-26 21:20

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2020-03-25 19:28
@@ -26,6 +25,6 @@ class Migration(migrations.Migration):
),
migrations.AlterUniqueTogether(
name='CourseAccessRoleAssignment',
unique_together=set([('role', 'enrollment')]),
unique_together={('role', 'enrollment')},
),
]

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Django model specifications for the Program Enrollments API
"""
@@ -28,7 +27,7 @@ class ProgramEnrollment(TimeStampedModel):
"""
STATUS_CHOICES = ProgramEnrollmentStatuses.__MODEL_CHOICES__
class Meta(object):
class Meta:
app_label = "program_enrollments"
# A student enrolled in a given (program, curriculum) should always
@@ -82,7 +81,7 @@ class ProgramEnrollment(TimeStampedModel):
return True
def __str__(self):
return '[ProgramEnrollment id={}]'.format(self.id)
return f'[ProgramEnrollment id={self.id}]'
def __repr__(self):
return ( # lint-amnesty, pylint: disable=missing-format-attribute
@@ -106,7 +105,7 @@ class ProgramCourseEnrollment(TimeStampedModel):
"""
STATUS_CHOICES = ProgramCourseEnrollmentStatuses.__MODEL_CHOICES__
class Meta(object):
class Meta:
app_label = "program_enrollments"
# For each program enrollment, there may be only one
@@ -138,7 +137,7 @@ class ProgramCourseEnrollment(TimeStampedModel):
return self.status == ProgramCourseEnrollmentStatuses.ACTIVE
def __str__(self):
return '[ProgramCourseEnrollment id={}]'.format(self.id)
return f'[ProgramCourseEnrollment id={self.id}]'
def __repr__(self):
return ( # lint-amnesty, pylint: disable=missing-format-attribute
@@ -158,14 +157,14 @@ class CourseAccessRoleAssignment(TimeStampedModel):
.. no_pii:
"""
class Meta(object):
class Meta:
unique_together = ('role', 'enrollment')
role = models.CharField(max_length=64, choices=ProgramCourseEnrollmentRoles.__MODEL_CHOICES__)
enrollment = models.ForeignKey(ProgramCourseEnrollment, on_delete=models.CASCADE)
def __str__(self):
return '[CourseAccessRoleAssignment id={}]'.format(self.id)
return f'[CourseAccessRoleAssignment id={self.id}]'
def __repr__(self):
return ( # lint-amnesty, pylint: disable=missing-format-attribute

View File

@@ -17,7 +17,7 @@ REQUEST_STUDENT_KEY = 'student_key'
ENABLE_ENROLLMENT_RESET_FLAG = 'ENABLE_ENROLLMENT_RESET'
class CourseRunProgressStatuses(object):
class CourseRunProgressStatuses:
"""
Statuses that a course run can be in with respect to user progress.
"""

View File

@@ -4,7 +4,6 @@ API Serializers
from rest_framework import serializers
from six import text_type
from lms.djangoapps.program_enrollments.api import is_course_staff_enrollment
from lms.djangoapps.program_enrollments.models import ProgramCourseEnrollment, ProgramEnrollment
@@ -14,7 +13,7 @@ from .constants import CourseRunProgressStatuses
# pylint: disable=abstract-method
class InvalidStatusMixin(object):
class InvalidStatusMixin:
"""
Mixin to provide has_invalid_status method
"""
@@ -40,7 +39,7 @@ class ProgramEnrollmentSerializer(serializers.Serializer):
username = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
class Meta(object):
class Meta:
model = ProgramEnrollment
def get_account_exists(self, obj):
@@ -92,7 +91,7 @@ class ProgramCourseEnrollmentSerializer(serializers.Serializer):
curriculum_uuid = serializers.SerializerMethodField()
course_staff = serializers.SerializerMethodField()
class Meta(object):
class Meta:
model = ProgramCourseEnrollment
def get_student_key(self, obj):
@@ -102,7 +101,7 @@ class ProgramCourseEnrollmentSerializer(serializers.Serializer):
return bool(obj.program_enrollment.user)
def get_curriculum_uuid(self, obj):
return text_type(obj.program_enrollment.curriculum_uuid)
return str(obj.program_enrollment.curriculum_uuid)
def get_course_staff(self, obj):
return is_course_staff_enrollment(obj)

View File

@@ -5,10 +5,10 @@ Unit tests for ProgramEnrollment views.
import json
from collections import OrderedDict, defaultdict
from datetime import datetime, timedelta
from unittest import mock
from uuid import UUID, uuid4
import ddt
import mock
from django.conf import settings
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.cache import cache
@@ -20,12 +20,14 @@ from opaque_keys.edx.keys import CourseKey
from organizations.tests.factories import OrganizationFactory as LMSOrganizationFactory
from rest_framework import status
from rest_framework.test import APITestCase
from six import text_type
from six.moves import range, zip
from social_django.models import UserSocialAuth
from lms.djangoapps.bulk_email.models import BulkEmailFlag, Optout
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from lms.djangoapps.bulk_email.models import BulkEmailFlag, Optout
from lms.djangoapps.certificates.models import CertificateStatuses
from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory
from lms.djangoapps.courseware.tests.factories import GlobalStaffFactory, InstructorFactory
@@ -50,10 +52,6 @@ from openedx.core.djangoapps.catalog.tests.factories import (
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from openedx.core.djangolib.testing.utils import CacheIsolationMixin
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.roles import CourseStaffRole
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory as ModulestoreCourseFactory
from xmodule.modulestore.tests.factories import ItemFactory
@@ -102,7 +100,7 @@ class EnrollmentsDataMixin(ProgramCacheMixin):
@classmethod
def setUpClass(cls):
super(EnrollmentsDataMixin, cls).setUpClass()
super().setUpClass()
cls.start_cache_isolation()
cls.organization_key = "testorg"
cls.catalog_org = OrganizationFactory(key=cls.organization_key)
@@ -114,7 +112,7 @@ class EnrollmentsDataMixin(ProgramCacheMixin):
inactive_curriculum_uuid = UUID('cccccccc-1111-2222-3333-444444444444')
catalog_course_id_str = 'course-v1:edX+ToyX'
course_run_id_str = '{}+Toy_Course'.format(catalog_course_id_str)
course_run_id_str = f'{catalog_course_id_str}+Toy_Course'
cls.course_id = CourseKey.from_string(course_run_id_str)
CourseOverviewFactory(id=cls.course_id)
course_run = CourseRunFactory(key=course_run_id_str)
@@ -137,12 +135,12 @@ class EnrollmentsDataMixin(ProgramCacheMixin):
cls.global_staff = GlobalStaffFactory(username='global-staff', password=cls.password)
def setUp(self):
super(EnrollmentsDataMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.set_program_in_catalog_cache(self.program_uuid, self.program)
@classmethod
def tearDownClass(cls):
super(EnrollmentsDataMixin, cls).tearDownClass()
super().tearDownClass()
cls.end_cache_isolation()
def get_url(self, program_uuid=None, course_id=None):
@@ -219,7 +217,7 @@ class ProgramEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
Helper method for creating program enrollment records.
"""
for i in range(2):
user_key = 'user-{}'.format(i)
user_key = f'user-{i}'
ProgramEnrollmentFactory.create(
program_uuid=self.program_uuid,
curriculum_uuid=self.curriculum_uuid,
@@ -229,11 +227,11 @@ class ProgramEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
)
for i in range(2, 4):
user_key = 'user-{}'.format(i)
user_key = f'user-{i}'
ProgramEnrollmentFactory.create(
program_uuid=self.program_uuid,
curriculum_uuid=self.curriculum_uuid,
user=UserFactory.create(username='student-{}'.format(i), email='email-{}'.format(i)),
user=UserFactory.create(username=f'student-{i}', email=f'email-{i}'),
external_user_key=user_key,
)
@@ -286,19 +284,19 @@ class ProgramEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
'results': [
{
'student_key': 'user-0', 'status': 'pending', 'account_exists': False,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "", 'email': ""
'curriculum_uuid': str(self.curriculum_uuid), 'username': "", 'email': ""
},
{
'student_key': 'user-1', 'status': 'pending', 'account_exists': False,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "", 'email': ""
'curriculum_uuid': str(self.curriculum_uuid), 'username': "", 'email': ""
},
{
'student_key': 'user-2', 'status': 'enrolled', 'account_exists': True,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "student-2", 'email': "email-2"
'curriculum_uuid': str(self.curriculum_uuid), 'username': "student-2", 'email': "email-2"
},
{
'student_key': 'user-3', 'status': 'enrolled', 'account_exists': True,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "student-3", 'email': "email-3"
'curriculum_uuid': str(self.curriculum_uuid), 'username': "student-3", 'email': "email-3"
},
],
}
@@ -315,11 +313,11 @@ class ProgramEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
expected_results = [
{
'student_key': 'user-0', 'status': 'pending', 'account_exists': False,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "", 'email': ""
'curriculum_uuid': str(self.curriculum_uuid), 'username': "", 'email': ""
},
{
'student_key': 'user-1', 'status': 'pending', 'account_exists': False,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "", 'email': ""
'curriculum_uuid': str(self.curriculum_uuid), 'username': "", 'email': ""
},
]
assert expected_results == response.data['results']
@@ -334,11 +332,11 @@ class ProgramEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
next_expected_results = [
{
'student_key': 'user-2', 'status': 'enrolled', 'account_exists': True,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "student-2", 'email': "email-2"
'curriculum_uuid': str(self.curriculum_uuid), 'username': "student-2", 'email': "email-2"
},
{
'student_key': 'user-3', 'status': 'enrolled', 'account_exists': True,
'curriculum_uuid': text_type(self.curriculum_uuid), 'username': "student-3", 'email': "email-3"
'curriculum_uuid': str(self.curriculum_uuid), 'username': "student-3", 'email': "email-3"
},
]
assert next_expected_results == next_response.data['results']
@@ -456,12 +454,12 @@ class ProgramEnrollmentsPostTests(ProgramEnrollmentsWriteMixin, APITestCase):
add_uuid = True
def setUp(self):
super(ProgramEnrollmentsPostTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.request = self.client.post
self.client.login(username=self.global_staff.username, password='password')
def tearDown(self):
super(ProgramEnrollmentsPostTests, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments
super().tearDown()
ProgramEnrollment.objects.all().delete()
def test_successful_program_enrollments_no_existing_user(self):
@@ -522,7 +520,7 @@ class ProgramEnrollmentsPostTests(ProgramEnrollmentsWriteMixin, APITestCase):
post_data = [
{
'status': 'enrolled',
REQUEST_STUDENT_KEY: 'abc{}'.format(i),
REQUEST_STUDENT_KEY: f'abc{i}',
'curriculum_uuid': str(self.curriculum_uuid)
} for i in range(3)
]
@@ -538,7 +536,7 @@ class ProgramEnrollmentsPostTests(ProgramEnrollmentsWriteMixin, APITestCase):
assert response.status_code == 200
for i in range(3):
enrollment = ProgramEnrollment.objects.get(external_user_key='abc{}'.format(i))
enrollment = ProgramEnrollment.objects.get(external_user_key=f'abc{i}')
assert enrollment.program_uuid == self.program_uuid
assert enrollment.status == 'enrolled'
@@ -554,7 +552,7 @@ class ProgramEnrollmentsPatchTests(ProgramEnrollmentsWriteMixin, APITestCase):
add_uuid = False
def setUp(self):
super(ProgramEnrollmentsPatchTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.request = self.client.patch
self.client.login(username=self.global_staff.username, password=self.password)
@@ -570,7 +568,7 @@ class ProgramEnrollmentsPatchTests(ProgramEnrollmentsWriteMixin, APITestCase):
def test_successfully_patched_program_enrollment(self):
enrollments = {}
for i in range(4):
user_key = 'user-{}'.format(i)
user_key = f'user-{i}'
instance = ProgramEnrollment.objects.create(
program_uuid=self.program_uuid,
curriculum_uuid=self.curriculum_uuid,
@@ -612,7 +610,7 @@ class ProgramEnrollmentsPatchTests(ProgramEnrollmentsWriteMixin, APITestCase):
def test_duplicate_enrollment_record_changed(self):
enrollments = {}
for i in range(4):
user_key = 'user-{}'.format(i)
user_key = f'user-{i}'
instance = ProgramEnrollment.objects.create(
program_uuid=self.program_uuid,
curriculum_uuid=self.curriculum_uuid,
@@ -649,7 +647,7 @@ class ProgramEnrollmentsPatchTests(ProgramEnrollmentsWriteMixin, APITestCase):
def test_partially_valid_enrollment_record_changed(self):
enrollments = {}
for i in range(4):
user_key = 'user-{}'.format(i)
user_key = f'user-{i}'
instance = ProgramEnrollment.objects.create(
program_uuid=self.program_uuid,
curriculum_uuid=self.curriculum_uuid,
@@ -693,7 +691,7 @@ class ProgramEnrollmentsPutTests(ProgramEnrollmentsWriteMixin, APITestCase):
add_uuid = True
def setUp(self):
super(ProgramEnrollmentsPutTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.request = self.client.put
self.client.login(username=self.global_staff.username, password='password')
@@ -770,16 +768,16 @@ class ProgramCourseEnrollmentsMixin(EnrollmentsDataMixin):
@classmethod
def setUpClass(cls):
super(ProgramCourseEnrollmentsMixin, cls).setUpClass()
super().setUpClass()
cls.start_cache_isolation()
@classmethod
def tearDownClass(cls):
cls.end_cache_isolation()
super(ProgramCourseEnrollmentsMixin, cls).tearDownClass()
super().tearDownClass()
def setUp(self):
super(ProgramCourseEnrollmentsMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.default_url = self.get_url(course_id=self.course_id)
self.log_in_staff()
@@ -971,11 +969,11 @@ class ProgramCourseEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
'results': [
{
'student_key': 'user-0', 'status': 'active', 'account_exists': True,
'curriculum_uuid': text_type(self.curriculum_uuid), 'course_staff': True
'curriculum_uuid': str(self.curriculum_uuid), 'course_staff': True
},
{
'student_key': 'user-0', 'status': 'inactive', 'account_exists': False,
'curriculum_uuid': text_type(self.other_curriculum_uuid), 'course_staff': True
'curriculum_uuid': str(self.other_curriculum_uuid), 'course_staff': True
},
],
}
@@ -992,7 +990,7 @@ class ProgramCourseEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
expected_results = [
{
'student_key': 'user-0', 'status': 'active', 'account_exists': True,
'curriculum_uuid': text_type(self.curriculum_uuid), 'course_staff': True
'curriculum_uuid': str(self.curriculum_uuid), 'course_staff': True
},
]
assert expected_results == response.data['results']
@@ -1007,7 +1005,7 @@ class ProgramCourseEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
next_expected_results = [
{
'student_key': 'user-0', 'status': 'inactive', 'account_exists': False,
'curriculum_uuid': text_type(self.other_curriculum_uuid), 'course_staff': True
'curriculum_uuid': str(self.other_curriculum_uuid), 'course_staff': True
},
]
assert next_expected_results == next_response.data['results']
@@ -1128,7 +1126,7 @@ class MultiprogramEnrollmentsTest(EnrollmentsDataMixin, APITestCase):
""" Tests for the Multiple Program with same course scenario """
@classmethod
def setUpClass(cls):
super(MultiprogramEnrollmentsTest, cls).setUpClass()
super().setUpClass()
cls.another_curriculum_uuid = UUID('bbbbbbbb-8888-9999-7777-666666666666')
cls.another_curriculum = CurriculumFactory(
uuid=cls.another_curriculum_uuid,
@@ -1144,7 +1142,7 @@ class MultiprogramEnrollmentsTest(EnrollmentsDataMixin, APITestCase):
cls.user = UserFactory.create(username='multiprogram_user')
def setUp(self):
super(MultiprogramEnrollmentsTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.set_program_in_catalog_cache(self.another_program_uuid, self.another_program)
self.client.login(username=self.global_staff.username, password=self.password)
@@ -1217,7 +1215,7 @@ class MultiprogramEnrollmentsTest(EnrollmentsDataMixin, APITestCase):
)
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.organization_key, self.external_user_key),
uid=f'{self.organization_key}:{self.external_user_key}',
provider=self.organization_key
)
@@ -1278,8 +1276,8 @@ class MultiprogramEnrollmentsTest(EnrollmentsDataMixin, APITestCase):
)
assert response.status_code == 422
mock_log.error.assert_called_with(
u'Detected conflicting active ProgramCourseEnrollment. This is happening on'
u' The program_uuid [{}] with course_key [{}] for external_user_key [{}]'.format(
'Detected conflicting active ProgramCourseEnrollment. This is happening on'
' The program_uuid [{}] with course_key [{}] for external_user_key [{}]'.format(
self.another_program_uuid,
self.course_id,
self.external_user_key
@@ -1441,7 +1439,7 @@ class UserProgramReadOnlyAccessGetTests(EnrollmentsDataMixin, APITestCase):
@classmethod
def setUpClass(cls):
super(UserProgramReadOnlyAccessGetTests, cls).setUpClass()
super().setUpClass()
cls.mock_program_data = [
{'uuid': cls.program_uuid_tmpl.format(11), 'marketing_slug': 'garbage-program', 'type': 'masters'},
@@ -1505,7 +1503,7 @@ class UserProgramReadOnlyAccessGetTests(EnrollmentsDataMixin, APITestCase):
"""
course_key_to_create = CourseKey.from_string(course_key_string)
CourseOverviewFactory(id=course_key_to_create)
CourseRunFactory.create(key=text_type(course_key_to_create))
CourseRunFactory.create(key=str(course_key_to_create))
CourseEnrollmentFactory.create(course_id=course_key_to_create, user=user)
CourseStaffRole(course_key_to_create).add_users(user)
return course_key_to_create
@@ -1578,7 +1576,7 @@ class UserProgramReadOnlyAccessGetTests(EnrollmentsDataMixin, APITestCase):
curriculum_uuid=self.curriculum_uuid,
user=self.student,
status='enrolled',
external_user_key='user-{}'.format(self.student.id),
external_user_key=f'user-{self.student.id}',
)
self.client.login(username=self.student.username, password=self.password)
@@ -1613,7 +1611,7 @@ class UserProgramReadOnlyAccessGetTests(EnrollmentsDataMixin, APITestCase):
curriculum_uuid=self.curriculum_uuid,
user=self.student,
status='pending',
external_user_key='user-{}'.format(self.student.id),
external_user_key=f'user-{self.student.id}',
)
self.client.login(username=self.student.username, password=self.password)
@@ -1645,14 +1643,14 @@ class ProgramCourseEnrollmentOverviewGetTests(
@classmethod
def setUpClass(cls):
super(ProgramCourseEnrollmentOverviewGetTests, cls).setUpClass()
super().setUpClass()
cls.program_uuid = '00000000-1111-2222-3333-444444444444'
cls.curriculum_uuid = 'aaaaaaaa-1111-2222-3333-444444444444'
cls.other_curriculum_uuid = 'bbbbbbbb-1111-2222-3333-444444444444'
cls.course_id = CourseKey.from_string('course-v1:edX+ToyX+Toy_Course')
cls.course_run = CourseRunFactory.create(key=text_type(cls.course_id))
cls.course_run = CourseRunFactory.create(key=str(cls.course_id))
cls.course = CourseFactory.create(course_runs=[cls.course_run])
cls.username = 'student'
@@ -1786,7 +1784,7 @@ class ProgramCourseEnrollmentOverviewGetTests(
Helper method to create another course, an overview for it,
add it to the program, and re-load the cache.
"""
other_course_run = CourseRunFactory.create(key=text_type(course_run_key))
other_course_run = CourseRunFactory.create(key=str(course_run_key))
other_course = CourseFactory.create(course_runs=[other_course_run])
program['courses'].append(other_course)
self.set_program_in_catalog_cache(program['uuid'], program)
@@ -1815,9 +1813,9 @@ class ProgramCourseEnrollmentOverviewGetTests(
assert status.HTTP_200_OK == response_status_code
actual_course_run_ids = {run['course_run_id'] for run in response_course_runs}
expected_course_run_ids = {text_type(self.course_id)}
expected_course_run_ids = {str(self.course_id)}
if other_enrollment_active:
expected_course_run_ids.add(text_type(other_course_key))
expected_course_run_ids.add(str(other_course_key))
assert expected_course_run_ids == actual_course_run_ids
@patch_resume_url
@@ -2097,7 +2095,7 @@ class ProgramCourseEnrollmentOverviewGetTests(
def test_course_run_url(self):
self.log_in()
course_run_url = 'http://testserver/courses/{}/course/'.format(text_type(self.course_id))
course_run_url = 'http://testserver/courses/{}/course/'.format(str(self.course_id))
response_status_code, response_course_runs = self.get_status_and_course_runs()
assert status.HTTP_200_OK == response_status_code
@@ -2130,8 +2128,8 @@ class ProgramCourseEnrollmentOverviewGetTests(
course_run_overview = response_course_runs[0]
assert course_run_overview['course_run_id'] == text_type(self.course_id)
assert course_run_overview['display_name'] == '{} Course'.format(text_type(self.course_id))
assert course_run_overview['course_run_id'] == str(self.course_id)
assert course_run_overview['display_name'] == '{} Course'.format(str(self.course_id))
def test_emails_enabled(self):
self.log_in()
@@ -2365,7 +2363,7 @@ class EnrollmentDataResetViewTests(ProgramCacheMixin, APITestCase):
)
def setUp(self):
super(EnrollmentDataResetViewTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.start_cache_isolation()
self.organization = LMSOrganizationFactory(short_name='uox')
@@ -2383,7 +2381,7 @@ class EnrollmentDataResetViewTests(ProgramCacheMixin, APITestCase):
def tearDown(self):
self.end_cache_isolation()
super(EnrollmentDataResetViewTests, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments
super().tearDown()
@patch_call_command
def test_feature_disabled_by_default(self, mock_call_command):

View File

@@ -31,7 +31,7 @@ urlpatterns = [
name='user_program_readonly_access'
),
url(
r'^programs/{program_uuid}/enrollments/$'.format(program_uuid=PROGRAM_UUID_PATTERN),
fr'^programs/{PROGRAM_UUID_PATTERN}/enrollments/$',
ProgramEnrollmentsView.as_view(),
name='program_enrollments'
),

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
ProgramEnrollment V1 API internal utilities.
"""
@@ -13,6 +12,8 @@ from rest_framework import status
from rest_framework.pagination import CursorPagination
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.helpers import get_resume_urls_for_enrollments
from common.djangoapps.student.models import CourseEnrollment
from lms.djangoapps.bulk_email.api import get_emails_enabled
from lms.djangoapps.certificates.api import get_certificates_for_user_by_course_keys
from lms.djangoapps.course_api.api import get_course_run_url, get_due_dates
@@ -20,8 +21,6 @@ from lms.djangoapps.program_enrollments.api import fetch_program_enrollments
from lms.djangoapps.program_enrollments.constants import ProgramEnrollmentStatuses
from openedx.core.djangoapps.catalog.utils import course_run_keys_for_program, get_programs, is_course_run_in_program
from openedx.core.lib.api.view_utils import verify_course_exists
from common.djangoapps.student.helpers import get_resume_urls_for_enrollments
from common.djangoapps.student.models import CourseEnrollment
from .constants import CourseRunProgressStatuses
@@ -56,7 +55,7 @@ class UserProgramCourseEnrollmentPagination(CursorPagination):
ordering = 'id'
class ProgramSpecificViewMixin(object):
class ProgramSpecificViewMixin:
"""
A mixin for views that operate on or within a specific program.

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
ProgramEnrollment Views
"""
@@ -18,6 +17,8 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole, UserBasedRole
from common.djangoapps.util.query import read_replica_or_default
from lms.djangoapps.program_enrollments.api import (
fetch_program_course_enrollments,
fetch_program_enrollments,
@@ -43,8 +44,6 @@ from openedx.core.djangoapps.catalog.utils import (
)
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, PaginatedAPIView
from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole, UserBasedRole
from common.djangoapps.util.query import read_replica_or_default
from .constants import ENABLE_ENROLLMENT_RESET_FLAG, MAX_ENROLLMENT_RECORDS
from .serializers import (
@@ -72,7 +71,7 @@ from .utils import (
)
class EnrollmentWriteMixin(object):
class EnrollmentWriteMixin:
"""
Common functionality for viewsets with enrollment-writing POST/PATCH/PUT methods.
@@ -992,7 +991,7 @@ class EnrollmentDataResetView(APIView):
try:
organization = Organization.objects.get(short_name=org_key)
except Organization.DoesNotExist:
return Response('organization {} not found'.format(org_key), status.HTTP_404_NOT_FOUND)
return Response(f'organization {org_key} not found', status.HTTP_404_NOT_FOUND)
try:
provider = get_saml_provider_for_organization(organization)

View File

@@ -9,9 +9,9 @@ from django.db.models.signals import post_save
from django.dispatch import receiver
from social_django.models import UserSocialAuth
from common.djangoapps.third_party_auth.models import SAMLProviderConfig
from openedx.core.djangoapps.catalog.utils import get_programs
from openedx.core.djangoapps.user_api.accounts.signals import USER_RETIRE_LMS_MISC
from common.djangoapps.third_party_auth.models import SAMLProviderConfig
from .api import fetch_program_enrollments_by_student, link_program_enrollment_to_lms_user
from .models import ProgramEnrollment

View File

@@ -9,13 +9,13 @@ import factory
from factory.django import DjangoModelFactory
from opaque_keys.edx.keys import CourseKey
from lms.djangoapps.program_enrollments import models
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from lms.djangoapps.program_enrollments import models
class ProgramEnrollmentFactory(DjangoModelFactory):
""" A Factory for the ProgramEnrollment model. """
class Meta(object):
class Meta:
model = models.ProgramEnrollment
user = factory.SubFactory(UserFactory)
@@ -32,7 +32,7 @@ PROGRAM_COURSE_ENROLLMENT_DEFAULT_COURSE_KEY = (
class ProgramCourseEnrollmentFactory(DjangoModelFactory):
""" A factory for the ProgramCourseEnrollment model. """
class Meta(object):
class Meta:
model = models.ProgramCourseEnrollment
program_enrollment = factory.SubFactory(ProgramEnrollmentFactory)
@@ -49,7 +49,7 @@ class ProgramCourseEnrollmentFactory(DjangoModelFactory):
class CourseAccessRoleAssignmentFactory(DjangoModelFactory):
""" A factory for the CourseAccessRoleAssignment model. """
class Meta(object):
class Meta:
model = models.CourseAccessRoleAssignment
enrollment = factory.SubFactory(ProgramCourseEnrollmentFactory)

View File

@@ -3,7 +3,8 @@ Unit tests for the ProgramEnrollment admin classes.
"""
import mock
from unittest import mock
from django.contrib.admin.sites import AdminSite
from django.test import TestCase
@@ -18,7 +19,7 @@ class ProgramEnrollmentAdminTests(TestCase):
new fields, etc.
"""
def setUp(self):
super(ProgramEnrollmentAdminTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.program_admin = ProgramEnrollmentAdmin(ProgramEnrollment, AdminSite())
self.program_course_admin = ProgramCourseEnrollmentAdmin(ProgramCourseEnrollment, AdminSite())

View File

@@ -12,8 +12,8 @@ from edx_django_utils.cache import RequestCache
from opaque_keys.edx.keys import CourseKey
from common.djangoapps.course_modes.models import CourseMode
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from ..constants import ProgramCourseEnrollmentRoles
from ..models import ProgramEnrollment
@@ -28,7 +28,7 @@ class ProgramEnrollmentModelTests(TestCase):
"""
Set up the test data used in the specific tests
"""
super(ProgramEnrollmentModelTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.user = UserFactory(username="rocko")
self.program_uuid = UUID("88888888-4444-2222-1111-000000000000")
self.other_program_uuid = UUID("88888888-4444-3333-1111-000000000000")
@@ -116,7 +116,7 @@ class ProgramCourseEnrollmentModelTests(TestCase):
"""
Set up test data
"""
super(ProgramCourseEnrollmentModelTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
RequestCache.clear_all_namespaces()
self.user = UserFactory(username="rocko")
self.program_uuid = UUID("88888888-4444-2222-1111-000000000000")
@@ -208,7 +208,7 @@ class CourseAccessRoleAssignmentTests(TestCase):
Tests for the CourseAccessRoleAssignment model.
"""
def setUp(self):
super(CourseAccessRoleAssignmentTests, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
self.program_course_enrollment = ProgramCourseEnrollmentFactory()
self.pending_role_assignment = CourseAccessRoleAssignmentFactory(
enrollment=self.program_course_enrollment,

View File

@@ -3,7 +3,8 @@ Test signal handlers for program_enrollments
"""
import mock
from unittest import mock
import pytest
from django.core.cache import cache
from edx_django_utils.cache import RequestCache
@@ -13,6 +14,10 @@ from social_django.models import UserSocialAuth
from testfixtures import LogCapture
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollmentException
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.models import SAMLProviderConfig
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from lms.djangoapps.program_enrollments.signals import _listen_for_lms_retire, logger
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
from openedx.core.djangoapps.catalog.cache import PROGRAM_CACHE_KEY_TPL
@@ -22,10 +27,6 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOvervi
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from openedx.core.djangoapps.user_api.accounts.tests.retirement_helpers import fake_completed_retirement
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from common.djangoapps.student.models import CourseEnrollmentException
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.third_party_auth.models import SAMLProviderConfig
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
@@ -107,7 +108,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
@classmethod
def setUpClass(cls):
super(SocialAuthEnrollmentCompletionSignalTest, cls).setUpClass()
super().setUpClass()
cls.external_id = '0000'
cls.provider_slug = 'uox'
@@ -127,7 +128,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
)
def setUp(self):
super(SocialAuthEnrollmentCompletionSignalTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
super().setUp()
RequestCache.clear_all_namespaces()
catalog_org = CatalogOrganizationFactory.create(key=self.organization.short_name)
self.program_uuid = self._create_catalog_program(catalog_org)['uuid']
@@ -181,14 +182,14 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
user_social_auth = UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, 'gobbledegook')
uid='{}:{}'.format(self.provider_slug, 'gobbledegook')
)
# Not yet a thing, didn't match
program_enrollment.refresh_from_db()
assert program_enrollment.user is None
user_social_auth.uid = '{0}:{1}'.format(self.provider_slug, self.external_id)
user_social_auth.uid = f'{self.provider_slug}:{self.external_id}'
user_social_auth.save()
# now we see the enrollments realized
@@ -202,7 +203,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id)
uid=f'{self.provider_slug}:{self.external_id}'
)
self._assert_program_enrollment_user(program_enrollment, self.user)
@@ -226,19 +227,19 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
UserSocialAuth.objects.create(
user=UserFactory.create(),
uid='{0}:{1}'.format('not_used', self.external_id),
uid='{}:{}'.format('not_used', self.external_id),
)
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id),
uid=f'{self.provider_slug}:{self.external_id}',
)
self._assert_program_enrollment_user(uox_program_enrollment, self.user)
aiu_user = UserFactory.create()
UserSocialAuth.objects.create(
user=aiu_user,
uid='{0}:{1}'.format('aiu', self.external_id),
uid='{}:{}'.format('aiu', self.external_id),
)
self._assert_program_enrollment_user(aiu_program_enrollment, aiu_user)
@@ -253,7 +254,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id)
uid=f'{self.provider_slug}:{self.external_id}'
)
program_enrollment.refresh_from_db()
assert program_enrollment.user is None
@@ -268,7 +269,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id)
uid=f'{self.provider_slug}:{self.external_id}'
)
self._assert_program_enrollment_user(program_enrollment, self.user)
@@ -286,7 +287,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id)
uid=f'{self.provider_slug}:{self.external_id}'
)
self._assert_program_enrollment_user(program_enrollment, self.user)
@@ -297,7 +298,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
"""
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id)
uid=f'{self.provider_slug}:{self.external_id}'
)
def test_create_social_auth_provider_has_no_organization(self):
@@ -307,7 +308,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
provider = SAMLProviderConfigFactory.create()
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(provider.slug, self.external_id)
uid=f'{provider.slug}:{self.external_id}'
)
def test_create_social_auth_non_saml_provider(self):
@@ -352,7 +353,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
with LogCapture(logger.name) as log:
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id)
uid=f'{self.provider_slug}:{self.external_id}'
)
error_template = (
'Failed to complete waiting enrollments for organization={}.'
@@ -375,7 +376,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
with pytest.raises(CourseEnrollmentException):
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id)
uid=f'{self.provider_slug}:{self.external_id}'
)
def test_log_on_unexpected_exception(self):
@@ -391,7 +392,7 @@ class SocialAuthEnrollmentCompletionSignalTest(CacheIsolationTestCase):
with self.assertRaisesRegex(Exception, 'unexpected error'):
UserSocialAuth.objects.create(
user=self.user,
uid='{0}:{1}'.format(self.provider_slug, self.external_id),
uid=f'{self.provider_slug}:{self.external_id}',
)
error_template = 'Unable to link waiting enrollments for user {}, social auth creation failed: {}'
log.check_present(

View File

@@ -13,11 +13,11 @@ from opaque_keys.edx.keys import CourseKey
from testfixtures import LogCapture
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from lms.djangoapps.program_enrollments.models import ProgramCourseEnrollment, ProgramEnrollment
from lms.djangoapps.program_enrollments.tasks import expire_waiting_enrollments, log
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
class ExpireWaitingEnrollmentsTest(TestCase):