diff --git a/openedx/core/djangoapps/programs/__init__.py b/openedx/core/djangoapps/programs/__init__.py index 380a63c022b2c7666de89a965de7b43a65b47254..5a4ef836a812b42fd11ea9ea0b4e0e4a55b51fd4 100644 --- a/openedx/core/djangoapps/programs/__init__.py +++ b/openedx/core/djangoapps/programs/__init__.py @@ -8,7 +8,9 @@ if and only if the service is deployed in the Open edX installation. To ensure maximum separation of concerns, and a minimum of interdependencies, this package should be kept small, thin, and stateless. """ -from openedx.core.djangoapps.waffle_utils import (WaffleSwitch, WaffleSwitchNamespace) +from __future__ import absolute_import + +from openedx.core.djangoapps.waffle_utils import WaffleSwitch, WaffleSwitchNamespace PROGRAMS_WAFFLE_SWITCH_NAMESPACE = WaffleSwitchNamespace(name='programs') diff --git a/openedx/core/djangoapps/programs/admin.py b/openedx/core/djangoapps/programs/admin.py index 64da72dca3bda761e48fc87baae0931df6ba4228..44b95b707b18e90fd9ae1c0bb7c7a5aca0c3c04e 100644 --- a/openedx/core/djangoapps/programs/admin.py +++ b/openedx/core/djangoapps/programs/admin.py @@ -1,6 +1,8 @@ """ django admin pages for program support models """ +from __future__ import absolute_import + from config_models.admin import ConfigurationModelAdmin from django.contrib import admin diff --git a/openedx/core/djangoapps/programs/apps.py b/openedx/core/djangoapps/programs/apps.py index e6d87eab18a771409e8307af7bde9ba51973eaf1..936e94f621a832d69cc14e63a0ca08b899ce4164 100644 --- a/openedx/core/djangoapps/programs/apps.py +++ b/openedx/core/djangoapps/programs/apps.py @@ -1,6 +1,8 @@ """ Programs Configuration """ +from __future__ import absolute_import + from django.apps import AppConfig diff --git a/openedx/core/djangoapps/programs/models.py b/openedx/core/djangoapps/programs/models.py index 89b2dd77c83f6252cd505159f564d2d9d3078c2c..0cf5c0bb198b40d8bae35abb0ebc24d16c328d6d 100644 --- a/openedx/core/djangoapps/programs/models.py +++ b/openedx/core/djangoapps/programs/models.py @@ -1,5 +1,7 @@ """Models providing Programs support for the LMS and Studio.""" +from __future__ import absolute_import + from config_models.models import ConfigurationModel from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/openedx/core/djangoapps/programs/signals.py b/openedx/core/djangoapps/programs/signals.py index 6f18239fd7a5313b3c51ae9a39f1929c7205c200..1d8351b4eacd17112d76da48f15d88b9a1663516 100644 --- a/openedx/core/djangoapps/programs/signals.py +++ b/openedx/core/djangoapps/programs/signals.py @@ -1,6 +1,8 @@ """ This module contains signals / handlers related to programs. """ +from __future__ import absolute_import + import logging from django.dispatch import receiver diff --git a/openedx/core/djangoapps/programs/utils.py b/openedx/core/djangoapps/programs/utils.py index 119d2450108b92b82cacb7fb89960588d2a39e80..38d22b86cdd0efc55851bc6257df9319b075468e 100644 --- a/openedx/core/djangoapps/programs/utils.py +++ b/openedx/core/djangoapps/programs/utils.py @@ -1,12 +1,15 @@ # -*- coding: utf-8 -*- """Helper functions for working with Programs.""" +from __future__ import absolute_import + import datetime import logging from collections import defaultdict from copy import deepcopy from itertools import chain -from urlparse import urljoin, urlparse, urlunparse +import six +from six.moves.urllib.parse import urljoin, urlparse, urlunparse # pylint: disable=import-error from dateutil.parser import parse from django.conf import settings from django.contrib.auth import get_user_model @@ -25,7 +28,7 @@ from lms.djangoapps.certificates.models import GeneratedCertificate from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.courseware.access import has_access from lms.djangoapps.grades.api import CourseGradeFactory -from openedx.core.djangoapps.catalog.utils import get_programs, get_fulfillable_course_runs_for_entitlement +from openedx.core.djangoapps.catalog.utils import get_fulfillable_course_runs_for_entitlement, get_programs from openedx.core.djangoapps.certificates.api import available_date_for_certificate from openedx.core.djangoapps.commerce.utils import ecommerce_api_client from openedx.core.djangoapps.content.course_overviews.models import CourseOverview @@ -95,7 +98,7 @@ class ProgramProgressMeter(object): self.course_run_ids = [] for enrollment in self.enrollments: # enrollment.course_id is really a CourseKey (╯ಠ_ಠ)╯︵ â”»â”â”» - enrollment_id = unicode(enrollment.course_id) + enrollment_id = six.text_type(enrollment.course_id) mode = enrollment.mode if mode == CourseMode.NO_ID_PROFESSIONAL_MODE: mode = CourseMode.PROFESSIONAL @@ -140,7 +143,7 @@ class ProgramProgressMeter(object): program_list.append(program) # Sort programs by title for consistent presentation. - for program_list in inverted_programs.itervalues(): + for program_list in six.itervalues(inverted_programs): program_list.sort(key=lambda p: p['title']) return inverted_programs @@ -326,14 +329,16 @@ class ProgramProgressMeter(object): if modes_match and certificate_api.is_passing_status(certificate.status): course_overview = CourseOverview.get_from_id(key) available_date = available_date_for_certificate(course_overview, certificate) - earliest_course_run_date = min(filter(None, [available_date, earliest_course_run_date])) + earliest_course_run_date = min( + [date for date in [available_date, earliest_course_run_date] if date] + ) # If we're missing a cert for a course, the program isn't completed and we should just bail now if earliest_course_run_date is None: return None # Keep the catalog course date if it's the latest one - program_available_date = max(filter(None, [earliest_course_run_date, program_available_date])) + program_available_date = max([date for date in [earliest_course_run_date, program_available_date] if date]) return program_available_date @@ -427,7 +432,7 @@ class ProgramProgressMeter(object): completed_runs, failed_runs = [], [] for certificate in course_run_certificates: course_data = { - 'course_run_id': unicode(certificate['course_key']), + 'course_run_id': six.text_type(certificate['course_key']), 'type': self._certificate_mode_translation(certificate['type']), } @@ -592,7 +597,7 @@ class ProgramDataExtender(object): # Here we check the entitlements' expired_at_datetime property rather than filter by the expired_at attribute # to ensure that the expiration status is as up to date as possible entitlements = [e for e in entitlements if not e.expired_at_datetime] - courses_with_entitlements = set(unicode(entitlement.course_uuid) for entitlement in entitlements) + courses_with_entitlements = set(six.text_type(entitlement.course_uuid) for entitlement in entitlements) return [course for course in courses if course['uuid'] not in courses_with_entitlements] def _filter_out_courses_with_enrollments(self, courses): @@ -610,10 +615,10 @@ class ProgramDataExtender(object): is_active=True, mode__in=self.data['applicable_seat_types'] ) - course_runs_with_enrollments = set(unicode(enrollment.course_id) for enrollment in enrollments) + course_runs_with_enrollments = set(six.text_type(enrollment.course_id) for enrollment in enrollments) courses_without_enrollments = [] for course in courses: - if all(unicode(run['key']) not in course_runs_with_enrollments for run in course['course_runs']): + if all(six.text_type(run['key']) not in course_runs_with_enrollments for run in course['course_runs']): courses_without_enrollments.append(course) return courses_without_enrollments @@ -805,7 +810,7 @@ class ProgramMarketingDataExtender(ProgramDataExtender): self.data['instructor_ordering'] = [] sorted_instructor_names = [ - ' '.join(filter(None, (instructor['given_name'], instructor['family_name']))) + ' '.join([name for name in (instructor['given_name'], instructor['family_name']) if name]) for instructor in self.data['instructor_ordering'] ] instructors_to_be_sorted = [