From 6294766c244165b4963975b9233b4dfe7e08f2db Mon Sep 17 00:00:00 2001 From: John Eskew Date: Tue, 19 Sep 2017 17:50:05 -0400 Subject: [PATCH 1/9] Split emitted signals from the student models file. --- .../student/management/tests/test_transfer_students.py | 3 ++- common/djangoapps/student/models.py | 8 ++------ common/djangoapps/student/signals/__init__.py | 6 ++++++ common/djangoapps/student/signals/signals.py | 3 +++ common/djangoapps/student/tests/test_views.py | 3 ++- common/djangoapps/student/views.py | 4 ++-- lms/djangoapps/badges/handlers.py | 3 ++- lms/djangoapps/commerce/signals.py | 2 +- lms/djangoapps/commerce/tests/test_signals.py | 2 +- lms/djangoapps/grades/signals/handlers.py | 2 +- lms/djangoapps/shoppingcart/models.py | 3 ++- 11 files changed, 24 insertions(+), 15 deletions(-) diff --git a/common/djangoapps/student/management/tests/test_transfer_students.py b/common/djangoapps/student/management/tests/test_transfer_students.py index 62d2527d3b..6431f60095 100644 --- a/common/djangoapps/student/management/tests/test_transfer_students.py +++ b/common/djangoapps/student/management/tests/test_transfer_students.py @@ -10,8 +10,9 @@ import ddt from shoppingcart.models import Order, CertificateItem # pylint: disable=import-error from course_modes.models import CourseMode from student.management.commands import transfer_students -from student.models import CourseEnrollment, UNENROLL_DONE, EVENT_NAME_ENROLLMENT_DEACTIVATED, \ +from student.models import CourseEnrollment, EVENT_NAME_ENROLLMENT_DEACTIVATED, \ EVENT_NAME_ENROLLMENT_ACTIVATED, EVENT_NAME_ENROLLMENT_MODE_CHANGED +from student.signals import UNENROLL_DONE from student.tests.factories import UserFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py index 5717f377be..459342a493 100644 --- a/common/djangoapps/student/models.py +++ b/common/djangoapps/student/models.py @@ -31,7 +31,7 @@ from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.db import IntegrityError, models from django.db.models import Count from django.db.models.signals import post_save, pre_save -from django.dispatch import Signal, receiver +from django.dispatch import receiver from django.utils import timezone from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ @@ -48,6 +48,7 @@ from slumber.exceptions import HttpClientError, HttpServerError import dogstats_wrapper as dog_stats_api import lms.lib.comment_client as cc import request_cache +from student.signals import UNENROLL_DONE, ENROLL_STATUS_CHANGE, REFUND_ORDER, ENROLLMENT_TRACK_UPDATED from certificates.models import GeneratedCertificate from course_modes.models import CourseMode from courseware.models import DynamicUpgradeDeadlineConfiguration, CourseDynamicUpgradeDeadlineConfiguration @@ -63,11 +64,6 @@ from util.milestones_helpers import is_entrance_exams_enabled from util.model_utils import emit_field_changed_events, get_changed_fields_dict from util.query import use_read_replica_if_available -from .signals.signals import ENROLLMENT_TRACK_UPDATED - -UNENROLL_DONE = Signal(providing_args=["course_enrollment", "skip_refund"]) -ENROLL_STATUS_CHANGE = Signal(providing_args=["event", "user", "course_id", "mode", "cost", "currency"]) -REFUND_ORDER = Signal(providing_args=["course_enrollment"]) log = logging.getLogger(__name__) AUDIT_LOG = logging.getLogger("audit") SessionStore = import_module(settings.SESSION_ENGINE).SessionStore # pylint: disable=invalid-name diff --git a/common/djangoapps/student/signals/__init__.py b/common/djangoapps/student/signals/__init__.py index e69de29bb2..6a50ccf072 100644 --- a/common/djangoapps/student/signals/__init__.py +++ b/common/djangoapps/student/signals/__init__.py @@ -0,0 +1,6 @@ +from student.signals.signals import ( + ENROLLMENT_TRACK_UPDATED, + UNENROLL_DONE, + ENROLL_STATUS_CHANGE, + REFUND_ORDER +) diff --git a/common/djangoapps/student/signals/signals.py b/common/djangoapps/student/signals/signals.py index 7f280b98b0..d1c080584d 100644 --- a/common/djangoapps/student/signals/signals.py +++ b/common/djangoapps/student/signals/signals.py @@ -4,3 +4,6 @@ Enrollment track related signals. from django.dispatch import Signal ENROLLMENT_TRACK_UPDATED = Signal(providing_args=['user', 'course_key']) +UNENROLL_DONE = Signal(providing_args=["course_enrollment", "skip_refund"]) +ENROLL_STATUS_CHANGE = Signal(providing_args=["event", "user", "course_id", "mode", "cost", "currency"]) +REFUND_ORDER = Signal(providing_args=["course_enrollment"]) diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index 4dc046093a..d44c4d948e 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -20,7 +20,8 @@ from opaque_keys import InvalidKeyError from milestones.tests.utils import MilestonesTestCaseMixin from student.cookies import get_user_info_cookie_data from student.helpers import DISABLE_UNENROLL_CERT_STATES -from student.models import CourseEnrollment, REFUND_ORDER, UserProfile +from student.models import CourseEnrollment, UserProfile +from student.signals import REFUND_ORDER from student.tests.factories import CourseEnrollmentFactory, UserFactory from util.milestones_helpers import set_prerequisite_courses, remove_prerequisite_course, get_course_milestones from xmodule.modulestore import ModuleStoreEnum diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 47223681f2..463e56f557 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -118,9 +118,9 @@ from student.models import ( UserStanding, anonymous_id_for_user, create_comments_service_user, - unique_id_for_user, - REFUND_ORDER + unique_id_for_user ) +from student.signals import REFUND_ORDER from student.tasks import send_activation_email from third_party_auth import pipeline, provider from util.bad_request_rate_limiter import BadRequestRateLimiter diff --git a/lms/djangoapps/badges/handlers.py b/lms/djangoapps/badges/handlers.py index 79887d5330..d53a50b762 100644 --- a/lms/djangoapps/badges/handlers.py +++ b/lms/djangoapps/badges/handlers.py @@ -5,7 +5,8 @@ from django.dispatch import receiver from lms.djangoapps.badges.events.course_meta import award_enrollment_badge from lms.djangoapps.badges.utils import badges_enabled -from student.models import ENROLL_STATUS_CHANGE, EnrollStatusChange +from student.models import EnrollStatusChange +from student.signals import ENROLL_STATUS_CHANGE @receiver(ENROLL_STATUS_CHANGE) diff --git a/lms/djangoapps/commerce/signals.py b/lms/djangoapps/commerce/signals.py index a9c8feb62e..58e7ffe712 100644 --- a/lms/djangoapps/commerce/signals.py +++ b/lms/djangoapps/commerce/signals.py @@ -19,7 +19,7 @@ from openedx.core.djangoapps.commerce.utils import ecommerce_api_client, is_comm from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.theming import helpers as theming_helpers from request_cache.middleware import RequestCache -from student.models import REFUND_ORDER +from student.signals import REFUND_ORDER log = logging.getLogger(__name__) diff --git a/lms/djangoapps/commerce/tests/test_signals.py b/lms/djangoapps/commerce/tests/test_signals.py index 2954f22d2b..f74f1f2500 100644 --- a/lms/djangoapps/commerce/tests/test_signals.py +++ b/lms/djangoapps/commerce/tests/test_signals.py @@ -23,7 +23,7 @@ from commerce.signals import create_zendesk_ticket, generate_refund_notification from commerce.tests import JSON from commerce.tests.mocks import mock_create_refund, mock_process_refund from course_modes.models import CourseMode -from student.models import REFUND_ORDER +from student.signals import REFUND_ORDER from student.tests.factories import CourseEnrollmentFactory, UserFactory ZENDESK_URL = 'http://zendesk.example.com/' diff --git a/lms/djangoapps/grades/signals/handlers.py b/lms/djangoapps/grades/signals/handlers.py index a5420049ec..3651bb6519 100644 --- a/lms/djangoapps/grades/signals/handlers.py +++ b/lms/djangoapps/grades/signals/handlers.py @@ -9,7 +9,7 @@ from django.dispatch import receiver from openedx.core.djangoapps.course_groups.signals.signals import COHORT_MEMBERSHIP_UPDATED from openedx.core.lib.grade_utils import is_score_higher_or_equal from student.models import user_by_anonymous_id -from student.signals.signals import ENROLLMENT_TRACK_UPDATED +from student.signals import ENROLLMENT_TRACK_UPDATED from submissions.models import score_reset, score_set from track.event_transaction_utils import get_event_transaction_id, get_event_transaction_type from util.date_utils import to_timestamp diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py index 144df4bbed..82906b772a 100644 --- a/lms/djangoapps/shoppingcart/models.py +++ b/lms/djangoapps/shoppingcart/models.py @@ -37,7 +37,8 @@ from eventtracking import tracker from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.xmodule_django.models import CourseKeyField from shoppingcart.pdf import PDFInvoice -from student.models import UNENROLL_DONE, CourseEnrollment, EnrollStatusChange +from student.models import CourseEnrollment, EnrollStatusChange +from student.signals import UNENROLL_DONE from util.query import use_read_replica_if_available from xmodule.modulestore.django import modulestore From 8b5b1eba86d95f423d205a7d3b682860b2c6e945 Mon Sep 17 00:00:00 2001 From: John Eskew Date: Tue, 19 Sep 2017 17:50:39 -0400 Subject: [PATCH 2/9] Use Django 1.11 compatible version of django-countries. --- .../djangoapps/user_api/tests/test_constants.py | 14 +++++++------- requirements/edx/base.txt | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openedx/core/djangoapps/user_api/tests/test_constants.py b/openedx/core/djangoapps/user_api/tests/test_constants.py index af3b113b76..332eb73117 100644 --- a/openedx/core/djangoapps/user_api/tests/test_constants.py +++ b/openedx/core/djangoapps/user_api/tests/test_constants.py @@ -2,7 +2,7 @@ """Constants used in the test suite. """ SORTED_COUNTRIES = [ (u"AF", u"Afghanistan"), - (u"AX", u"Åland Islands"), + (u"AX", u"\xc5land Islands"), (u"AL", u"Albania"), (u"DZ", u"Algeria"), (u"AS", u"American Samoa"), @@ -55,12 +55,12 @@ SORTED_COUNTRIES = [ (u"CD", u"Congo (the Democratic Republic of the)"), (u"CK", u"Cook Islands"), (u"CR", u"Costa Rica"), - (u"CI", u"Côte d'Ivoire"), + (u"CI", u"C\xf4te d'Ivoire"), (u"HR", u"Croatia"), (u"CU", u"Cuba"), - (u"CW", u"Curaçao"), + (u"CW", u"Cura\xe7ao"), (u"CY", u"Cyprus"), - (u"CZ", u"Czech Republic"), + (u"CZ", u"Czechia"), (u"DK", u"Denmark"), (u"DJ", u"Djibouti"), (u"DM", u"Dominica"), @@ -181,11 +181,11 @@ SORTED_COUNTRIES = [ (u"PT", u"Portugal"), (u"PR", u"Puerto Rico"), (u"QA", u"Qatar"), - (u"RE", u"Réunion"), + (u"RE", u"R\xe9union"), (u"RO", u"Romania"), (u"RU", u"Russia"), (u"RW", u"Rwanda"), - (u"BL", u"Saint Barthélemy"), + (u"BL", u"Saint Barth\xe9lemy"), (u"SH", u"Saint Helena, Ascension and Tristan da Cunha"), (u"KN", u"Saint Kitts and Nevis"), (u"LC", u"Saint Lucia"), @@ -250,5 +250,5 @@ SORTED_COUNTRIES = [ (u"EH", u"Western Sahara"), (u"YE", u"Yemen"), (u"ZM", u"Zambia"), - (u"ZW", u"Zimbabwe"), + (u"ZW", u"Zimbabwe") ] diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 40b875204c..687a5637f9 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -17,7 +17,7 @@ defusedxml==0.4.1 django-babel-underscore==0.5.2 markey==0.8 # From django-babel-underscore django-config-models==0.1.8 -django-countries==4.0 +django-countries==4.6.1 django-extensions==1.5.9 django-filter==1.0.4 django-ipware==1.1.0 From 02f26f55ce54e99e5fc67fe8a36e73c18985743f Mon Sep 17 00:00:00 2001 From: John Eskew Date: Tue, 19 Sep 2017 17:55:14 -0400 Subject: [PATCH 3/9] Remove unused imports. Push model imports down into relevant methods. Mock out the static_replace modules in the proper location. --- common/djangoapps/static_replace/__init__.py | 5 ++--- .../static_replace/test/test_static_replace.py | 14 +++++++------- common/lib/xmodule/xmodule/modulestore/django.py | 4 +++- lms/djangoapps/branding/__init__.py | 4 +++- lms/djangoapps/commerce/signals.py | 11 ++++++++--- openedx/core/djangoapps/coursegraph/tasks.py | 9 +++++++-- openedx/core/djangoapps/credit/signals.py | 1 - .../core/djangoapps/site_configuration/helpers.py | 7 ++++++- openedx/core/djangoapps/waffle_utils/__init__.py | 11 +++++++---- openedx/core/djangolib/testing/utils.py | 3 ++- 10 files changed, 45 insertions(+), 24 deletions(-) diff --git a/common/djangoapps/static_replace/__init__.py b/common/djangoapps/static_replace/__init__.py index a4a63430f5..3fb2b0c9a0 100644 --- a/common/djangoapps/static_replace/__init__.py +++ b/common/djangoapps/static_replace/__init__.py @@ -5,9 +5,6 @@ from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles import finders from django.conf import settings -from static_replace.models import AssetBaseUrlConfig, AssetExcludedExtensionsConfig -from xmodule.modulestore.django import modulestore -from xmodule.modulestore import ModuleStoreEnum from xmodule.contentstore.content import StaticContent from opaque_keys.edx.locator import AssetLocator @@ -191,6 +188,8 @@ def replace_static_urls(text, data_directory=None, course_id=None, static_asset_ else: # if not, then assume it's courseware specific content and then look in the # Mongo-backed database + # Import is placed here to avoid model import at project startup. + from static_replace.models import AssetBaseUrlConfig, AssetExcludedExtensionsConfig base_url = AssetBaseUrlConfig.get_base_url() excluded_exts = AssetExcludedExtensionsConfig.get_excluded_extensions() url = StaticContent.get_canonicalized_asset_path(course_id, rest, base_url, excluded_exts) diff --git a/common/djangoapps/static_replace/test/test_static_replace.py b/common/djangoapps/static_replace/test/test_static_replace.py index 802571a777..759e50abad 100644 --- a/common/djangoapps/static_replace/test/test_static_replace.py +++ b/common/djangoapps/static_replace/test/test_static_replace.py @@ -116,9 +116,9 @@ def test_storage_url_not_exists(mock_storage): @patch('static_replace.StaticContent', autospec=True) -@patch('static_replace.modulestore', autospec=True) -@patch('static_replace.AssetBaseUrlConfig.get_base_url') -@patch('static_replace.AssetExcludedExtensionsConfig.get_excluded_extensions') +@patch('xmodule.modulestore.django.modulestore', autospec=True) +@patch('static_replace.models.AssetBaseUrlConfig.get_base_url') +@patch('static_replace.models.AssetExcludedExtensionsConfig.get_excluded_extensions') def test_mongo_filestore(mock_get_excluded_extensions, mock_get_base_url, mock_modulestore, mock_static_content): mock_modulestore.return_value = Mock(MongoModuleStore) @@ -139,7 +139,7 @@ def test_mongo_filestore(mock_get_excluded_extensions, mock_get_base_url, mock_m @patch('static_replace.settings', autospec=True) -@patch('static_replace.modulestore', autospec=True) +@patch('xmodule.modulestore.django.modulestore', autospec=True) @patch('static_replace.staticfiles_storage', autospec=True) def test_data_dir_fallback(mock_storage, mock_modulestore, mock_settings): mock_modulestore.return_value = Mock(XMLModuleStore) @@ -165,7 +165,7 @@ def test_raw_static_check(): @pytest.mark.django_db @patch('static_replace.staticfiles_storage', autospec=True) -@patch('static_replace.modulestore', autospec=True) +@patch('xmodule.modulestore.django.modulestore', autospec=True) def test_static_url_with_query(mock_modulestore, mock_storage): """ Make sure that for urls with query params: @@ -201,7 +201,7 @@ def test_regex(): @patch('static_replace.staticfiles_storage', autospec=True) -@patch('static_replace.modulestore', autospec=True) +@patch('xmodule.modulestore.django.modulestore', autospec=True) def test_static_url_with_xblock_resource(mock_modulestore, mock_storage): """ Make sure that for URLs with XBlock resource URL, which start with /static/, @@ -216,7 +216,7 @@ def test_static_url_with_xblock_resource(mock_modulestore, mock_storage): @patch('static_replace.staticfiles_storage', autospec=True) -@patch('static_replace.modulestore', autospec=True) +@patch('xmodule.modulestore.django.modulestore', autospec=True) @override_settings(STATIC_URL='https://example.com/static/') def test_static_url_with_xblock_resource_on_cdn(mock_modulestore, mock_storage): """ diff --git a/common/lib/xmodule/xmodule/modulestore/django.py b/common/lib/xmodule/xmodule/modulestore/django.py index 094890c194..45a8b8b987 100644 --- a/common/lib/xmodule/xmodule/modulestore/django.py +++ b/common/lib/xmodule/xmodule/modulestore/django.py @@ -29,7 +29,6 @@ from xmodule.contentstore.django import contentstore from xmodule.modulestore.draft_and_published import BranchSettingMixin from xmodule.modulestore.mixed import MixedModuleStore from xmodule.util.django import get_current_request_hostname -import xblock.reference.plugins try: # We may not always have the request_cache module available @@ -245,6 +244,9 @@ def create_modulestore_instance( """ This will return a new instance of a modulestore given an engine and options """ + # Import is placed here to avoid model import at project startup. + import xblock.reference.plugins + class_ = load_function(engine) _options = {} diff --git a/lms/djangoapps/branding/__init__.py b/lms/djangoapps/branding/__init__.py index b8d909af53..534c0c4faf 100644 --- a/lms/djangoapps/branding/__init__.py +++ b/lms/djangoapps/branding/__init__.py @@ -10,7 +10,6 @@ such as the site visible courses, university name and logo. from django.conf import settings from opaque_keys.edx.keys import CourseKey -from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -25,6 +24,9 @@ def get_visible_courses(org=None, filter_=None): filter_ (dict): Optional parameter that allows custom filtering by fields on the course. """ + # Import is placed here to avoid model import at project startup. + from openedx.core.djangoapps.content.course_overviews.models import CourseOverview + courses = [] current_site_orgs = configuration_helpers.get_current_site_orgs() diff --git a/lms/djangoapps/commerce/signals.py b/lms/djangoapps/commerce/signals.py index 58e7ffe712..25cb10ebc1 100644 --- a/lms/djangoapps/commerce/signals.py +++ b/lms/djangoapps/commerce/signals.py @@ -10,12 +10,9 @@ from urlparse import urljoin import requests from django.conf import settings from django.contrib.auth import get_user_model -from django.contrib.auth.models import AnonymousUser from django.dispatch import receiver from django.utils.translation import ugettext as _ -from commerce.models import CommerceConfiguration -from openedx.core.djangoapps.commerce.utils import ecommerce_api_client, is_commerce_service_configured from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.theming import helpers as theming_helpers from request_cache.middleware import RequestCache @@ -31,6 +28,10 @@ def handle_refund_order(sender, course_enrollment=None, **kwargs): Signal receiver for unenrollments, used to automatically initiate refunds when applicable. """ + # Import is placed here to avoid model import at project startup. + from django.contrib.auth.models import AnonymousUser + from openedx.core.djangoapps.commerce.utils import is_commerce_service_configured + if not is_commerce_service_configured(): return @@ -83,6 +84,10 @@ def refund_seat(course_enrollment): exceptions.SlumberBaseException: for any unhandled HTTP error during communication with the E-Commerce Service. exceptions.Timeout: if the attempt to reach the commerce service timed out. """ + # Import is placed here to avoid model import at project startup. + from commerce.models import CommerceConfiguration + from openedx.core.djangoapps.commerce.utils import ecommerce_api_client + User = get_user_model() # pylint:disable=invalid-name course_key_str = unicode(course_enrollment.course_id) enrollee = course_enrollment.user diff --git a/openedx/core/djangoapps/coursegraph/tasks.py b/openedx/core/djangoapps/coursegraph/tasks.py index 9138612ae7..ee73e25c35 100644 --- a/openedx/core/djangoapps/coursegraph/tasks.py +++ b/openedx/core/djangoapps/coursegraph/tasks.py @@ -13,10 +13,8 @@ from opaque_keys.edx.keys import CourseKey from py2neo import Graph, Node, Relationship, authenticate, NodeSelector from py2neo.compat import integer, string, unicode as neo4j_unicode from request_cache.middleware import RequestCache -from xmodule.modulestore.django import modulestore from xmodule.modulestore.store_utilities import DETACHED_XBLOCK_TYPES -from openedx.core.djangoapps.content.course_structures.models import CourseStructure log = logging.getLogger(__name__) celery_log = logging.getLogger('edx.celery.task') @@ -135,6 +133,8 @@ def get_course_last_published(course_key): text, or None, if there's no record of the last time this course was published. """ + # Import is placed here to avoid model import at project startup. + from openedx.core.djangoapps.content.course_structures.models import CourseStructure try: structure = CourseStructure.objects.get(course_id=course_key) course_last_published_date = six.text_type(structure.modified) @@ -154,6 +154,9 @@ def serialize_course(course_id): nodes: a list of py2neo Node objects relationships: a list of py2neo Relationships objects """ + # Import is placed here to avoid model import at project startup. + from xmodule.modulestore.django import modulestore + # create a location to node mapping we'll need later for # writing relationships location_to_node = {} @@ -292,6 +295,8 @@ class ModuleStoreSerializer(object): For example, ["course-v1:org+course+run"]. skip: Also a list of string serializations of course keys. """ + # Import is placed here to avoid model import at project startup. + from xmodule.modulestore.django import modulestore if courses: course_keys = [CourseKey.from_string(course.strip()) for course in courses] else: diff --git a/openedx/core/djangoapps/credit/signals.py b/openedx/core/djangoapps/credit/signals.py index 0a3e5e2af8..20872871e6 100644 --- a/openedx/core/djangoapps/credit/signals.py +++ b/openedx/core/djangoapps/credit/signals.py @@ -9,7 +9,6 @@ from django.utils import timezone from opaque_keys.edx.keys import CourseKey from openedx.core.djangoapps.signals.signals import COURSE_GRADE_CHANGED -from xmodule.modulestore.django import SignalHandler log = logging.getLogger(__name__) diff --git a/openedx/core/djangoapps/site_configuration/helpers.py b/openedx/core/djangoapps/site_configuration/helpers.py index 559cc36f3d..fc6e0084be 100644 --- a/openedx/core/djangoapps/site_configuration/helpers.py +++ b/openedx/core/djangoapps/site_configuration/helpers.py @@ -4,7 +4,6 @@ Helpers methods for site configuration. from django.conf import settings from microsite_configuration import microsite -from openedx.core.djangoapps.site_configuration.models import SiteConfiguration def get_current_site_configuration(): @@ -20,6 +19,8 @@ def get_current_site_configuration(): from openedx.core.djangoapps.theming.helpers import get_current_site site = get_current_site() + # Import is placed here to avoid model import at project startup. + from openedx.core.djangoapps.site_configuration.models import SiteConfiguration try: return getattr(site, "configuration", None) except SiteConfiguration.DoesNotExist: @@ -183,6 +184,8 @@ def get_value_for_org(org, val_name, default=None): """ # Here we first look for the asked org inside site configuration, and if org is not present in site configuration # then we go ahead and look it inside microsite configuration. + # Import is placed here to avoid model import at project startup. + from openedx.core.djangoapps.site_configuration.models import SiteConfiguration if SiteConfiguration.has_org(org): return SiteConfiguration.get_value_for_org(org, val_name, default) else: @@ -212,6 +215,8 @@ def get_all_orgs(): Returns: A list of all organizations present in either microsite configuration or site configuration. """ + # Import is placed here to avoid model import at project startup. + from openedx.core.djangoapps.site_configuration.models import SiteConfiguration site_configuration_orgs = SiteConfiguration.get_all_orgs() microsite_orgs = microsite.get_all_orgs() diff --git a/openedx/core/djangoapps/waffle_utils/__init__.py b/openedx/core/djangoapps/waffle_utils/__init__.py index 30a8460e8b..c0a8b2da64 100644 --- a/openedx/core/djangoapps/waffle_utils/__init__.py +++ b/openedx/core/djangoapps/waffle_utils/__init__.py @@ -51,10 +51,6 @@ from contextlib import contextmanager from opaque_keys.edx.keys import CourseKey from request_cache import get_cache as get_request_cache, get_request from waffle import flag_is_active, switch_is_active -from waffle.models import Flag -from waffle.testutils import override_switch as waffle_override_switch - -from .models import WaffleFlagCourseOverrideModel log = logging.getLogger(__name__) @@ -154,6 +150,8 @@ class WaffleSwitchNamespace(WaffleNamespace): contextmanager. Note: The value is overridden in the model, not the request cache. """ + # Import is placed here to avoid model import at project startup. + from waffle.testutils import override_switch as waffle_override_switch namespaced_switch_name = self._namespaced_name(switch_name) with waffle_override_switch(namespaced_switch_name, active): log.info(u"%sSwitch '%s' set to %s in model.", self.log_prefix, namespaced_switch_name, active) @@ -206,6 +204,9 @@ class WaffleFlagNamespace(WaffleNamespace): flag_undefined_default (Boolean): A default value to be returned if the waffle flag is to be checked, but doesn't exist. """ + # Import is placed here to avoid model import at project startup. + from waffle.models import Flag + # validate arguments namespaced_flag_name = self._namespaced_name(flag_name) value = None @@ -295,6 +296,8 @@ class CourseWaffleFlag(WaffleFlag): namespaced_flag_name (String): A namespaced version of the flag to check. """ + # Import is placed here to avoid model import at project startup. + from .models import WaffleFlagCourseOverrideModel cache_key = u'{}.{}'.format(namespaced_flag_name, unicode(course_key)) force_override = self.waffle_namespace._cached_flags.get(cache_key) diff --git a/openedx/core/djangolib/testing/utils.py b/openedx/core/djangolib/testing/utils.py index dc734c033a..29278d6d02 100644 --- a/openedx/core/djangolib/testing/utils.py +++ b/openedx/core/djangolib/testing/utils.py @@ -16,7 +16,6 @@ import crum from django import db from django.conf import settings from django.contrib import sites -from django.contrib.auth.models import AnonymousUser from django.core.cache import caches from django.db import DEFAULT_DB_ALIAS, connections from django.test import RequestFactory, TestCase, override_settings @@ -244,6 +243,8 @@ def get_mock_request(user=None): """ Create a request object for the user, if specified. """ + # Import is placed here to avoid model import at project startup. + from django.contrib.auth.models import AnonymousUser request = RequestFactory().get('/') if user is not None: request.user = user From 7dfb6cc681608b5ddf509ece0bfec4a9f91871e7 Mon Sep 17 00:00:00 2001 From: John Eskew Date: Tue, 19 Sep 2017 18:17:03 -0400 Subject: [PATCH 4/9] Change all UTC timezones to import from pytz instead of Django. --- .../tests/test_course_settings.py | 17 +++++++------ .../tests/test_courseware_index.py | 9 ++++--- common/djangoapps/util/tests/test_file.py | 4 ++-- common/lib/xmodule/xmodule/lti_module.py | 4 ++-- common/lib/xmodule/xmodule/seq_module.py | 4 ++-- .../lib/xmodule/xmodule/tests/test_fields.py | 22 ++++++++--------- .../lib/xmodule/xmodule/tests/test_import.py | 4 ++-- .../xmodule/xmodule/tests/test_lti20_unit.py | 4 ++-- .../xmodule/xmodule/tests/test_lti_unit.py | 4 ++-- .../xmodule/tests/test_randomize_module.py | 4 ++-- lms/djangoapps/ccx/tests/test_views.py | 20 +++++++--------- lms/djangoapps/courseware/access.py | 9 ++++--- lms/djangoapps/courseware/access_utils.py | 4 ++-- .../courseware/tests/test_masquerade.py | 4 ++-- lms/djangoapps/courseware/views/views.py | 4 ++-- .../dashboard/tests/test_sysadmin.py | 2 +- .../django_comment_client/tests/test_utils.py | 2 -- lms/djangoapps/django_comment_client/utils.py | 9 ++++--- lms/djangoapps/instructor/tests/test_api.py | 13 +++++----- lms/djangoapps/instructor/tests/test_tools.py | 24 +++++++++---------- lms/djangoapps/instructor/tests/utils.py | 4 ++-- lms/djangoapps/instructor/views/tools.py | 4 ++-- .../models/tests/test_course_details.py | 8 +++---- .../core/djangoapps/profile_images/views.py | 4 ++-- openedx/core/lib/xblock_utils/__init__.py | 4 ++-- .../views/course_home_messages.py | 5 ++-- 26 files changed, 94 insertions(+), 102 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index bfa1f985a5..b826afc652 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -10,7 +10,7 @@ import ddt import mock from django.conf import settings from django.test.utils import override_settings -from django.utils.timezone import UTC +from pytz import UTC from milestones.tests.utils import MilestonesTestCaseMixin from mock import Mock, patch @@ -61,7 +61,7 @@ class CourseSettingsEncoderTest(CourseTestCase): doesn't work for these dates. """ details = CourseDetails.fetch(self.course.id) - pre_1900 = datetime.datetime(1564, 4, 23, 1, 1, 1, tzinfo=UTC()) + pre_1900 = datetime.datetime(1564, 4, 23, 1, 1, 1, tzinfo=UTC) details.enrollment_start = pre_1900 dumped_jsondetails = json.dumps(details, cls=CourseSettingsEncoder) loaded_jsondetails = json.loads(dumped_jsondetails) @@ -74,7 +74,7 @@ class CourseSettingsEncoderTest(CourseTestCase): details = { 'number': 1, 'string': 'string', - 'datetime': datetime.datetime.now(UTC()) + 'datetime': datetime.datetime.now(UTC) } jsondetails = json.dumps(details, cls=CourseSettingsEncoder) jsondetails = json.loads(jsondetails) @@ -121,13 +121,12 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): resp = self.client.get_json(url) self.compare_details_with_encoding(json.loads(resp.content), details.__dict__, "virgin get") - utc = UTC() - self.alter_field(url, details, 'start_date', datetime.datetime(2012, 11, 12, 1, 30, tzinfo=utc)) - self.alter_field(url, details, 'start_date', datetime.datetime(2012, 11, 1, 13, 30, tzinfo=utc)) - self.alter_field(url, details, 'end_date', datetime.datetime(2013, 2, 12, 1, 30, tzinfo=utc)) - self.alter_field(url, details, 'enrollment_start', datetime.datetime(2012, 10, 12, 1, 30, tzinfo=utc)) + self.alter_field(url, details, 'start_date', datetime.datetime(2012, 11, 12, 1, 30, tzinfo=UTC)) + self.alter_field(url, details, 'start_date', datetime.datetime(2012, 11, 1, 13, 30, tzinfo=UTC)) + self.alter_field(url, details, 'end_date', datetime.datetime(2013, 2, 12, 1, 30, tzinfo=UTC)) + self.alter_field(url, details, 'enrollment_start', datetime.datetime(2012, 10, 12, 1, 30, tzinfo=UTC)) - self.alter_field(url, details, 'enrollment_end', datetime.datetime(2012, 11, 15, 1, 30, tzinfo=utc)) + self.alter_field(url, details, 'enrollment_end', datetime.datetime(2012, 11, 15, 1, 30, tzinfo=UTC)) self.alter_field(url, details, 'short_description', "Short Description") self.alter_field(url, details, 'overview', "Overview") self.alter_field(url, details, 'intro_video', "intro_video") diff --git a/cms/djangoapps/contentstore/tests/test_courseware_index.py b/cms/djangoapps/contentstore/tests/test_courseware_index.py index 488c3a27f4..a00c9f6061 100644 --- a/cms/djangoapps/contentstore/tests/test_courseware_index.py +++ b/cms/djangoapps/contentstore/tests/test_courseware_index.py @@ -9,7 +9,6 @@ from uuid import uuid4 import ddt import pytest -from dateutil.tz import tzutc from django.conf import settings from lazy.lazy import lazy from mock import patch @@ -1187,7 +1186,7 @@ class GroupConfigurationSearchMongo(CourseTestCase, MixedWithOptionsTestCase): 'content_type': 'Text', 'org': self.course.org, 'content_groups': content_groups, - 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=tzutc()) + 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=UTC) } def _html_experiment_group_result(self, html_unit, content_groups): @@ -1207,7 +1206,7 @@ class GroupConfigurationSearchMongo(CourseTestCase, MixedWithOptionsTestCase): 'content_type': 'Text', 'org': self.course.org, 'content_groups': content_groups, - 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=tzutc()) + 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=UTC) } def _vertical_experiment_group_result(self, vertical, content_groups): @@ -1215,7 +1214,7 @@ class GroupConfigurationSearchMongo(CourseTestCase, MixedWithOptionsTestCase): Return object with arguments and content group for split_test vertical. """ return { - 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=tzutc()), + 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=UTC), 'content': {'display_name': vertical.display_name}, 'course': unicode(self.course.id), 'location': [ @@ -1247,7 +1246,7 @@ class GroupConfigurationSearchMongo(CourseTestCase, MixedWithOptionsTestCase): 'content_type': 'Text', 'org': self.course.org, 'content_groups': None, - 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=tzutc()) + 'start_date': datetime(2015, 4, 1, 0, 0, tzinfo=UTC) } def _get_index_values_from_call_args(self, mock_index): diff --git a/common/djangoapps/util/tests/test_file.py b/common/djangoapps/util/tests/test_file.py index 2df186bafd..1ae7cabc29 100644 --- a/common/djangoapps/util/tests/test_file.py +++ b/common/djangoapps/util/tests/test_file.py @@ -11,7 +11,7 @@ from django.core import exceptions from django.core.files.uploadedfile import SimpleUploadedFile from django.http import HttpRequest from django.test import TestCase -from django.utils.timezone import UTC +from pytz import UTC from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import CourseLocator @@ -45,7 +45,7 @@ class FilenameGeneratorTestCase(TestCase): """ Tests for course_and_time_based_filename_generator """ - NOW = datetime.strptime('1974-06-22T01:02:03', '%Y-%m-%dT%H:%M:%S').replace(tzinfo=UTC()) + NOW = datetime.strptime('1974-06-22T01:02:03', '%Y-%m-%dT%H:%M:%S').replace(tzinfo=UTC) def setUp(self): super(FilenameGeneratorTestCase, self).setUp() diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py index 733fa0bab7..caaf830790 100644 --- a/common/lib/xmodule/xmodule/lti_module.py +++ b/common/lib/xmodule/xmodule/lti_module.py @@ -62,7 +62,7 @@ from xml.sax.saxutils import escape import bleach import mock import oauthlib.oauth1 -from django.utils.timezone import UTC +from pytz import UTC from lxml import etree from oauthlib.oauth1.rfc5849 import signature from pkg_resources import resource_string @@ -889,7 +889,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} close_date = due_date + self.graceperiod # pylint: disable=no-member else: close_date = due_date - return close_date is not None and datetime.datetime.now(UTC()) > close_date + return close_date is not None and datetime.datetime.now(UTC) > close_date class LTIDescriptor(LTIFields, MetadataOnlyEditingDescriptor, EmptyDataRawDescriptor): diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index c6d0a72b91..ae63fb8b80 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -5,10 +5,10 @@ xModule implementation of a learning sequence # pylint: disable=abstract-method import collections from datetime import datetime -from django.utils.timezone import UTC import json import logging from pkg_resources import resource_string +from pytz import UTC from lxml import etree from xblock.core import XBlock @@ -215,7 +215,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule): return ( not date or not hide_after_date or - datetime.now(UTC()) < date + datetime.now(UTC) < date ) def student_view(self, context): diff --git a/common/lib/xmodule/xmodule/tests/test_fields.py b/common/lib/xmodule/xmodule/tests/test_fields.py index 4464470eab..670e294549 100644 --- a/common/lib/xmodule/xmodule/tests/test_fields.py +++ b/common/lib/xmodule/xmodule/tests/test_fields.py @@ -3,7 +3,7 @@ import datetime import unittest -from django.utils.timezone import UTC +from pytz import UTC from xmodule.fields import Date, Timedelta, RelativeTime from xmodule.timeinfo import TimeInfo @@ -57,15 +57,15 @@ class DateTest(unittest.TestCase): self.assertEqual(DateTest.date.enforce_type(""), None) self.assertEqual( DateTest.date.enforce_type("2012-12-31T23:00:01"), - datetime.datetime(2012, 12, 31, 23, 0, 1, tzinfo=UTC()) + datetime.datetime(2012, 12, 31, 23, 0, 1, tzinfo=UTC) ) self.assertEqual( DateTest.date.enforce_type(1234567890000), - datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=UTC()) + datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=UTC) ) self.assertEqual( - DateTest.date.enforce_type(datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC())), - datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC()) + DateTest.date.enforce_type(datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC)), + datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC) ) with self.assertRaises(TypeError): DateTest.date.enforce_type([1]) @@ -79,11 +79,11 @@ class DateTest(unittest.TestCase): def test_old_due_date_format(self): current = datetime.datetime.today() self.assertEqual( - datetime.datetime(current.year, 3, 12, 12, tzinfo=UTC()), + datetime.datetime(current.year, 3, 12, 12, tzinfo=UTC), DateTest.date.from_json("March 12 12:00") ) self.assertEqual( - datetime.datetime(current.year, 12, 4, 16, 30, tzinfo=UTC()), + datetime.datetime(current.year, 12, 4, 16, 30, tzinfo=UTC), DateTest.date.from_json("December 4 16:30") ) self.assertIsNone(DateTest.date.from_json("12 12:00")) @@ -92,13 +92,13 @@ class DateTest(unittest.TestCase): """ Test the non-standard args being passed to from_json """ - now = datetime.datetime.now(UTC()) - delta = now - datetime.datetime.fromtimestamp(0, UTC()) + now = datetime.datetime.now(UTC) + delta = now - datetime.datetime.fromtimestamp(0, UTC) self.assertEqual( DateTest.date.from_json(delta.total_seconds() * 1000), now ) - yesterday = datetime.datetime.now(UTC()) - datetime.timedelta(days=-1) + yesterday = datetime.datetime.now(UTC) - datetime.timedelta(days=-1) self.assertEqual(DateTest.date.from_json(yesterday), yesterday) def test_to_json(self): @@ -157,7 +157,7 @@ class TimedeltaTest(unittest.TestCase): class TimeInfoTest(unittest.TestCase): def test_time_info(self): - due_date = datetime.datetime(2000, 4, 14, 10, tzinfo=UTC()) + due_date = datetime.datetime(2000, 4, 14, 10, tzinfo=UTC) grace_pd_string = '1 day 12 hours 59 minutes 59 seconds' timeinfo = TimeInfo(due_date, grace_pd_string) self.assertEqual( diff --git a/common/lib/xmodule/xmodule/tests/test_import.py b/common/lib/xmodule/xmodule/tests/test_import.py index efad2d853a..52d4a9e630 100644 --- a/common/lib/xmodule/xmodule/tests/test_import.py +++ b/common/lib/xmodule/xmodule/tests/test_import.py @@ -8,7 +8,7 @@ from fs.memoryfs import MemoryFS from lxml import etree from mock import Mock, patch -from django.utils.timezone import UTC +from pytz import UTC from xmodule.xml_module import is_pointer_tag from opaque_keys.edx.locations import Location @@ -346,7 +346,7 @@ class ImportTestCase(BaseCourseTestCase): # Check that the child hasn't started yet self.assertLessEqual( - datetime.datetime.now(UTC()), + datetime.datetime.now(UTC), child.start ) diff --git a/common/lib/xmodule/xmodule/tests/test_lti20_unit.py b/common/lib/xmodule/xmodule/tests/test_lti20_unit.py index bd31475288..43011d7a7b 100644 --- a/common/lib/xmodule/xmodule/tests/test_lti20_unit.py +++ b/common/lib/xmodule/xmodule/tests/test_lti20_unit.py @@ -3,7 +3,7 @@ import datetime import textwrap -from django.utils.timezone import UTC +from pytz import UTC from mock import Mock from xmodule.lti_module import LTIDescriptor from xmodule.lti_2_util import LTIError @@ -388,7 +388,7 @@ class LTI20RESTResultServiceTest(LogicTest): Test that we get a 404 when accept_grades_past_due is False and it is past due """ self.setup_system_xmodule_mocks_for_lti20_request_test() - self.xmodule.due = datetime.datetime.now(UTC()) + self.xmodule.due = datetime.datetime.now(UTC) self.xmodule.accept_grades_past_due = False mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT) response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd") diff --git a/common/lib/xmodule/xmodule/tests/test_lti_unit.py b/common/lib/xmodule/xmodule/tests/test_lti_unit.py index ce83fed603..0017519c2b 100644 --- a/common/lib/xmodule/xmodule/tests/test_lti_unit.py +++ b/common/lib/xmodule/xmodule/tests/test_lti_unit.py @@ -2,7 +2,7 @@ """Test for LTI Xmodule functional logic.""" import datetime -from django.utils.timezone import UTC +from pytz import UTC from mock import Mock, patch, PropertyMock import textwrap from lxml import etree @@ -180,7 +180,7 @@ class LTIModuleTest(LogicTest): Should fail if we do not accept past due grades, and it is past due. """ self.xmodule.accept_grades_past_due = False - self.xmodule.due = datetime.datetime.now(UTC()) + self.xmodule.due = datetime.datetime.now(UTC) self.xmodule.graceperiod = Timedelta().from_json("0 seconds") request = Request(self.environ) request.body = self.get_request_body() diff --git a/common/lib/xmodule/xmodule/tests/test_randomize_module.py b/common/lib/xmodule/xmodule/tests/test_randomize_module.py index 798d3028b1..48c5220b21 100644 --- a/common/lib/xmodule/xmodule/tests/test_randomize_module.py +++ b/common/lib/xmodule/xmodule/tests/test_randomize_module.py @@ -4,7 +4,7 @@ Test cases covering workflows and behaviors for the Randomize XModule import unittest from datetime import datetime, timedelta -from django.utils.timezone import UTC +from pytz import UTC from opaque_keys.edx.locator import BlockUsageLocator from xblock.fields import ScopeIds from xmodule.randomize_module import RandomizeModule @@ -16,7 +16,7 @@ ORG = 'test_org' COURSE = 'test_course' START = '2013-01-01T01:00:00' -_TODAY = datetime.now(UTC()) +_TODAY = datetime.now(UTC) _LAST_WEEK = _TODAY - timedelta(days=7) _NEXT_WEEK = _TODAY + timedelta(days=7) diff --git a/lms/djangoapps/ccx/tests/test_views.py b/lms/djangoapps/ccx/tests/test_views.py index b388e040cb..7d271e7668 100644 --- a/lms/djangoapps/ccx/tests/test_views.py +++ b/lms/djangoapps/ccx/tests/test_views.py @@ -7,14 +7,12 @@ import re import urlparse import ddt -import pytz from ccx_keys.locator import CCXLocator -from dateutil.tz import tzutc from django.conf import settings from django.core.urlresolvers import resolve, reverse from django.test import RequestFactory from django.test.utils import override_settings -from django.utils.timezone import UTC +from pytz import UTC from django.utils.translation import ugettext as _ from mock import MagicMock, patch from nose.plugins.attrib import attr @@ -183,8 +181,8 @@ class TestCCXProgressChanges(CcxTestCase, LoginEnrollmentTestCase): Set up tests """ super(TestCCXProgressChanges, cls).setUpClass() - start = datetime.datetime(2016, 7, 1, 0, 0, tzinfo=tzutc()) - due = datetime.datetime(2016, 7, 8, 0, 0, tzinfo=tzutc()) + start = datetime.datetime(2016, 7, 1, 0, 0, tzinfo=UTC) + due = datetime.datetime(2016, 7, 8, 0, 0, tzinfo=UTC) cls.course = course = CourseFactory.create(enable_ccx=True, start=start) chapter = ItemFactory.create(start=start, parent=course, category=u'chapter') @@ -467,7 +465,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase): """ Get CCX schedule, modify it, save it. """ - today.return_value = datetime.datetime(2014, 11, 25, tzinfo=pytz.UTC) + today.return_value = datetime.datetime(2014, 11, 25, tzinfo=UTC) self.make_coach() ccx = self.make_ccx() url = reverse( @@ -919,10 +917,10 @@ class TestCoachDashboardSchedule(CcxTestCase, LoginEnrollmentTestCase, ModuleSto # Create a course outline self.mooc_start = start = datetime.datetime( - 2010, 5, 12, 2, 42, tzinfo=pytz.UTC + 2010, 5, 12, 2, 42, tzinfo=UTC ) self.mooc_due = due = datetime.datetime( - 2010, 7, 7, 0, 0, tzinfo=pytz.UTC + 2010, 7, 7, 0, 0, tzinfo=UTC ) self.chapters = [ @@ -1004,7 +1002,7 @@ class TestCoachDashboardSchedule(CcxTestCase, LoginEnrollmentTestCase, ModuleSto Hides nodes at a different depth and checks that these nodes are not in the schedule. """ - today.return_value = datetime.datetime(2014, 11, 25, tzinfo=pytz.UTC) + today.return_value = datetime.datetime(2014, 11, 25, tzinfo=UTC) self.make_coach() ccx = self.make_ccx() url = reverse( @@ -1066,7 +1064,7 @@ class TestCCXGrades(FieldOverrideTestMixin, SharedModuleStoreTestCase, LoginEnro # Create a course outline cls.mooc_start = start = datetime.datetime( - 2010, 5, 12, 2, 42, tzinfo=pytz.UTC + 2010, 5, 12, 2, 42, tzinfo=UTC ) chapter = ItemFactory.create( start=start, parent=course, category='sequential' @@ -1332,7 +1330,7 @@ class TestStudentViewsWithCCX(ModuleStoreTestCase): # Create a CCX course and enroll the user in it. self.ccx = CcxFactory(course_id=self.split_course.id, coach=self.coach) - last_week = datetime.datetime.now(UTC()) - datetime.timedelta(days=7) + last_week = datetime.datetime.now(UTC) - datetime.timedelta(days=7) override_field_for_ccx(self.ccx, self.split_course, 'start', last_week) # Required by self.ccx.has_started(). self.ccx_course_key = CCXLocator.from_course_locator(self.split_course.id, self.ccx.id) CourseEnrollment.enroll(self.student, self.ccx_course_key) diff --git a/lms/djangoapps/courseware/access.py b/lms/djangoapps/courseware/access.py index ec7871c4d6..5fb708a956 100644 --- a/lms/djangoapps/courseware/access.py +++ b/lms/djangoapps/courseware/access.py @@ -13,11 +13,10 @@ Note: The access control logic in this file does NOT check for enrollment in import logging from datetime import datetime -import pytz from ccx_keys.locator import CCXLocator from django.conf import settings from django.contrib.auth.models import AnonymousUser -from django.utils.timezone import UTC +from pytz import UTC from opaque_keys.edx.keys import CourseKey, UsageKey from xblock.core import XBlock @@ -274,9 +273,9 @@ def _can_enroll_courselike(user, courselike): debug("Deny: invitation only") return ACCESS_DENIED - now = datetime.now(UTC()) - enrollment_start = courselike.enrollment_start or datetime.min.replace(tzinfo=pytz.UTC) - enrollment_end = courselike.enrollment_end or datetime.max.replace(tzinfo=pytz.UTC) + now = datetime.now(UTC) + enrollment_start = courselike.enrollment_start or datetime.min.replace(tzinfo=UTC) + enrollment_end = courselike.enrollment_end or datetime.max.replace(tzinfo=UTC) if reg_method_ok and enrollment_start < now < enrollment_end: debug("Allow: in enrollment period") return ACCESS_GRANTED diff --git a/lms/djangoapps/courseware/access_utils.py b/lms/djangoapps/courseware/access_utils.py index 7dc3a01b4a..5a9084e8c5 100644 --- a/lms/djangoapps/courseware/access_utils.py +++ b/lms/djangoapps/courseware/access_utils.py @@ -7,7 +7,7 @@ from datetime import datetime, timedelta from logging import getLogger from django.conf import settings -from django.utils.timezone import UTC +from pytz import UTC from courseware.access_response import AccessResponse, StartDateError from courseware.masquerade import is_masquerading_as_student @@ -64,7 +64,7 @@ def check_start_date(user, days_early_for_beta, start, course_key): if start_dates_disabled and not is_masquerading_as_student(user, course_key): return ACCESS_GRANTED else: - now = datetime.now(UTC()) + now = datetime.now(UTC) if start is None or in_preview_mode(): return ACCESS_GRANTED diff --git a/lms/djangoapps/courseware/tests/test_masquerade.py b/lms/djangoapps/courseware/tests/test_masquerade.py index fbe1f9733c..5049438b84 100644 --- a/lms/djangoapps/courseware/tests/test_masquerade.py +++ b/lms/djangoapps/courseware/tests/test_masquerade.py @@ -8,7 +8,7 @@ from datetime import datetime from django.conf import settings from django.core.urlresolvers import reverse from django.test import TestCase -from django.utils.timezone import UTC +from pytz import UTC from mock import patch from nose.plugins.attrib import attr from xblock.runtime import DictKeyValueStore @@ -42,7 +42,7 @@ class MasqueradeTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase): @classmethod def setUpClass(cls): super(MasqueradeTestCase, cls).setUpClass() - cls.course = CourseFactory.create(number='masquerade-test', metadata={'start': datetime.now(UTC())}) + cls.course = CourseFactory.create(number='masquerade-test', metadata={'start': datetime.now(UTC)}) cls.info_page = ItemFactory.create( category="course_info", parent_location=cls.course.location, data="OOGIE BLOOGIE", display_name="updates" diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index a07ebac5ce..90872ee083 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -49,7 +49,7 @@ from django.shortcuts import redirect from django.utils.decorators import method_decorator from django.utils.http import urlquote_plus from django.utils.text import slugify -from django.utils.timezone import UTC +from pytz import UTC from django.utils.translation import ugettext as _ from django.views.decorators.cache import cache_control from django.views.decorators.csrf import ensure_csrf_cookie @@ -1650,7 +1650,7 @@ def get_financial_aid_courses(user): enrollment.course_overview and \ enrollment.course_overview.eligible_for_financial_aid and \ CourseMode.objects.filter( - Q(_expiration_datetime__isnull=True) | Q(_expiration_datetime__gt=datetime.now(UTC())), + Q(_expiration_datetime__isnull=True) | Q(_expiration_datetime__gt=datetime.now(UTC)), course_id=enrollment.course_id, mode_slug=CourseMode.VERIFIED).exists(): diff --git a/lms/djangoapps/dashboard/tests/test_sysadmin.py b/lms/djangoapps/dashboard/tests/test_sysadmin.py index 5ae1eeba19..655d55ca8d 100644 --- a/lms/djangoapps/dashboard/tests/test_sysadmin.py +++ b/lms/djangoapps/dashboard/tests/test_sysadmin.py @@ -14,7 +14,7 @@ from django.conf import settings from django.core.urlresolvers import reverse from django.test.client import Client from django.test.utils import override_settings -from django.utils.timezone import utc as UTC +from pytz import UTC from nose.plugins.attrib import attr from opaque_keys.edx.keys import CourseKey diff --git a/lms/djangoapps/django_comment_client/tests/test_utils.py b/lms/djangoapps/django_comment_client/tests/test_utils.py index 1d28963684..5f29b23261 100644 --- a/lms/djangoapps/django_comment_client/tests/test_utils.py +++ b/lms/djangoapps/django_comment_client/tests/test_utils.py @@ -7,7 +7,6 @@ import mock from django.core.management import call_command from django.core.urlresolvers import reverse from django.test import RequestFactory, TestCase -from django.utils.timezone import UTC as django_utc from mock import Mock, patch from nose.plugins.attrib import attr from pytz import UTC @@ -539,7 +538,6 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): ) def test_get_unstarted_discussion_xblocks(self): - later = datetime.datetime(datetime.MAXYEAR, 1, 1, tzinfo=django_utc()) self.create_discussion("Chapter 1", "Discussion 1", start=later) diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index 80d67c27a2..f07af6a0f8 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -3,13 +3,12 @@ import logging from collections import defaultdict from datetime import datetime -import pytz from django.conf import settings from django.contrib.auth.models import User from django.core.urlresolvers import reverse from django.db import connection from django.http import HttpResponse -from django.utils.timezone import UTC +from pytz import UTC from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import i4xEncoder @@ -231,7 +230,7 @@ def _filter_unstarted_categories(category_map, course): Returns a subset of categories from the provided map which have not yet met the start date Includes information about category children, subcategories (different), and entries """ - now = datetime.now(UTC()) + now = datetime.now(UTC) result_map = {} @@ -344,7 +343,7 @@ def get_discussion_category_map(course, user, divided_only_if_explicit=False, ex sort_key = xblock.sort_key category = " / ".join([x.strip() for x in xblock.discussion_category.split("/")]) # Handle case where xblock.start is None - entry_start_date = xblock.start if xblock.start else datetime.max.replace(tzinfo=pytz.UTC) + entry_start_date = xblock.start if xblock.start else datetime.max.replace(tzinfo=UTC) unexpanded_category_map[category].append({"title": title, "id": discussion_id, "sort_key": sort_key, @@ -411,7 +410,7 @@ def get_discussion_category_map(course, user, divided_only_if_explicit=False, ex category_map['entries'][topic] = { "id": entry["id"], "sort_key": entry.get("sort_key", topic), - "start_date": datetime.now(UTC()), + "start_date": datetime.now(UTC), "is_divided": ( discussion_division_enabled and entry["id"] in divided_discussion_ids ) diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index b3d1a528c4..dc0cd0e922 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -11,7 +11,6 @@ import shutil import tempfile import ddt -import pytz from boto.exception import BotoServerError from django.conf import settings from django.contrib.auth.models import User @@ -21,7 +20,7 @@ from django.core.urlresolvers import reverse as django_reverse from django.http import HttpRequest, HttpResponse from django.test import RequestFactory, TestCase from django.test.utils import override_settings -from django.utils.timezone import utc +from pytz import UTC from django.utils.translation import ugettext as _ from mock import Mock, patch from nose.plugins.attrib import attr @@ -4135,7 +4134,7 @@ class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase): def setUpClass(cls): super(TestDueDateExtensions, cls).setUpClass() cls.course = CourseFactory.create() - cls.due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc) + cls.due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=UTC) with cls.store.bulk_operations(cls.course.id, emit_signals=False): cls.week1 = ItemFactory.create(due=cls.due) @@ -4217,7 +4216,7 @@ class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase): 'due_datetime': '12/30/2013 00:00' }) self.assertEqual(response.status_code, 200, response.content) - self.assertEqual(datetime.datetime(2013, 12, 30, 0, 0, tzinfo=utc), + self.assertEqual(datetime.datetime(2013, 12, 30, 0, 0, tzinfo=UTC), get_extended_due(self.course, self.week1, self.user1)) def test_change_to_invalid_due_date(self): @@ -4304,7 +4303,7 @@ class TestDueDateExtensionsDeletedDate(ModuleStoreTestCase, LoginEnrollmentTestC super(TestDueDateExtensionsDeletedDate, self).setUp() self.course = CourseFactory.create() - self.due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc) + self.due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=UTC) with self.store.bulk_operations(self.course.id, emit_signals=False): self.week1 = ItemFactory.create(due=self.due) @@ -4385,7 +4384,7 @@ class TestDueDateExtensionsDeletedDate(ModuleStoreTestCase, LoginEnrollmentTestC 'due_datetime': '12/30/2013 00:00' }) self.assertEqual(response.status_code, 200, response.content) - self.assertEqual(datetime.datetime(2013, 12, 30, 0, 0, tzinfo=utc), + self.assertEqual(datetime.datetime(2013, 12, 30, 0, 0, tzinfo=UTC), get_extended_due(self.course, self.week1, self.user1)) self.week1.due = None @@ -4949,7 +4948,7 @@ class TestCourseRegistrationCodes(SharedModuleStoreTestCase): coupon = Coupon( code='coupon{0}'.format(i), description='test_description', course_id=self.course.id, percentage_discount='{0}'.format(i), created_by=self.instructor, is_active=True, - expiration_date=datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=2) + expiration_date=datetime.datetime.now(UTC) + datetime.timedelta(days=2) ) coupon.save() diff --git a/lms/djangoapps/instructor/tests/test_tools.py b/lms/djangoapps/instructor/tests/test_tools.py index 07a147788f..0754dd2036 100644 --- a/lms/djangoapps/instructor/tests/test_tools.py +++ b/lms/djangoapps/instructor/tests/test_tools.py @@ -9,7 +9,7 @@ import unittest import mock from django.test import TestCase from django.test.utils import override_settings -from django.utils.timezone import utc +from pytz import UTC from nose.plugins.attrib import attr from opaque_keys.edx.keys import CourseKey @@ -96,7 +96,7 @@ class TestParseDatetime(unittest.TestCase): def test_parse_no_error(self): self.assertEqual( tools.parse_datetime('5/12/2010 2:42'), - datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc)) + datetime.datetime(2010, 5, 12, 2, 42, tzinfo=UTC)) def test_parse_error(self): with self.assertRaises(tools.DashboardError): @@ -144,7 +144,7 @@ class TestGetUnitsWithDueDate(ModuleStoreTestCase): """ super(TestGetUnitsWithDueDate, self).setUp() - due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc) + due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=UTC) course = CourseFactory.create() week1 = ItemFactory.create(due=due, parent=course) week2 = ItemFactory.create(due=due, parent=course) @@ -199,7 +199,7 @@ class TestSetDueDateExtension(ModuleStoreTestCase): """ super(TestSetDueDateExtension, self).setUp() - self.due = due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc) + self.due = due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=UTC) course = CourseFactory.create() week1 = ItemFactory.create(due=due, parent=course) week2 = ItemFactory.create(due=due, parent=course) @@ -234,7 +234,7 @@ class TestSetDueDateExtension(ModuleStoreTestCase): block.fields['due']._del_cached_value(block) # pylint: disable=protected-access def test_set_due_date_extension(self): - extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=utc) + extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=UTC) tools.set_due_date_extension(self.course, self.week1, self.user, extended) self._clear_field_data_cache() self.assertEqual(self.week1.due, extended) @@ -242,23 +242,23 @@ class TestSetDueDateExtension(ModuleStoreTestCase): self.assertEqual(self.assignment.due, extended) def test_set_due_date_extension_num_queries(self): - extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=utc) + extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=UTC) with self.assertNumQueries(5): tools.set_due_date_extension(self.course, self.week1, self.user, extended) self._clear_field_data_cache() def test_set_due_date_extension_invalid_date(self): - extended = datetime.datetime(2009, 1, 1, 0, 0, tzinfo=utc) + extended = datetime.datetime(2009, 1, 1, 0, 0, tzinfo=UTC) with self.assertRaises(tools.DashboardError): tools.set_due_date_extension(self.course, self.week1, self.user, extended) def test_set_due_date_extension_no_date(self): - extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=utc) + extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=UTC) with self.assertRaises(tools.DashboardError): tools.set_due_date_extension(self.course, self.week3, self.user, extended) def test_reset_due_date_extension(self): - extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=utc) + extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=UTC) tools.set_due_date_extension(self.course, self.week1, self.user, extended) tools.set_due_date_extension(self.course, self.week1, self.user, None) self.assertEqual(self.week1.due, self.due) @@ -276,7 +276,7 @@ class TestDataDumps(ModuleStoreTestCase): """ super(TestDataDumps, self).setUp() - due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc) + due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=UTC) course = CourseFactory.create() week1 = ItemFactory.create(due=due, parent=course) week2 = ItemFactory.create(due=due, parent=course) @@ -296,7 +296,7 @@ class TestDataDumps(ModuleStoreTestCase): self.user2 = user2 def test_dump_module_extensions(self): - extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=utc) + extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=UTC) tools.set_due_date_extension(self.course, self.week1, self.user1, extended) tools.set_due_date_extension(self.course, self.week1, self.user2, @@ -316,7 +316,7 @@ class TestDataDumps(ModuleStoreTestCase): "Extended Due Date": "2013-12-25 00:00"}]) def test_dump_student_extensions(self): - extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=utc) + extended = datetime.datetime(2013, 12, 25, 0, 0, tzinfo=UTC) tools.set_due_date_extension(self.course, self.week1, self.user1, extended) tools.set_due_date_extension(self.course, self.week2, self.user1, diff --git a/lms/djangoapps/instructor/tests/utils.py b/lms/djangoapps/instructor/tests/utils.py index 8c1308ebb3..84c34e1cf2 100644 --- a/lms/djangoapps/instructor/tests/utils.py +++ b/lms/djangoapps/instructor/tests/utils.py @@ -5,7 +5,7 @@ import datetime import json import random -from django.utils.timezone import utc +from pytz import UTC from util.date_utils import get_default_time_display @@ -62,7 +62,7 @@ class FakeEmail(FakeInfo): day = random.randint(1, 28) hour = random.randint(0, 23) minute = random.randint(0, 59) - self.created = datetime.datetime(year, month, day, hour, minute, tzinfo=utc) + self.created = datetime.datetime(year, month, day, hour, minute, tzinfo=UTC) self.targets = FakeTargetGroup() diff --git a/lms/djangoapps/instructor/views/tools.py b/lms/djangoapps/instructor/views/tools.py index 3e70b2168d..25f843e007 100644 --- a/lms/djangoapps/instructor/views/tools.py +++ b/lms/djangoapps/instructor/views/tools.py @@ -6,7 +6,7 @@ import json import dateutil from django.contrib.auth.models import User from django.http import HttpResponseBadRequest -from django.utils.timezone import utc +from pytz import UTC from django.utils.translation import ugettext as _ from opaque_keys.edx.keys import UsageKey @@ -91,7 +91,7 @@ def parse_datetime(datestr): UTC. """ try: - return dateutil.parser.parse(datestr).replace(tzinfo=utc) + return dateutil.parser.parse(datestr).replace(tzinfo=UTC) except ValueError: raise DashboardError(_("Unable to parse date: ") + datestr) diff --git a/openedx/core/djangoapps/models/tests/test_course_details.py b/openedx/core/djangoapps/models/tests/test_course_details.py index 74ad8eb8b2..4653bb1b38 100644 --- a/openedx/core/djangoapps/models/tests/test_course_details.py +++ b/openedx/core/djangoapps/models/tests/test_course_details.py @@ -4,7 +4,7 @@ Tests for CourseDetails import datetime import ddt -from django.utils.timezone import UTC +from pytz import UTC from nose.plugins.attrib import attr from xmodule.modulestore import ModuleStoreEnum @@ -84,17 +84,17 @@ class CourseDetailsTestCase(ModuleStoreTestCase): CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).self_paced, jsondetails.self_paced ) - jsondetails.start_date = datetime.datetime(2010, 10, 1, 0, tzinfo=UTC()) + jsondetails.start_date = datetime.datetime(2010, 10, 1, 0, tzinfo=UTC) self.assertEqual( CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).start_date, jsondetails.start_date ) - jsondetails.end_date = datetime.datetime(2011, 10, 1, 0, tzinfo=UTC()) + jsondetails.end_date = datetime.datetime(2011, 10, 1, 0, tzinfo=UTC) self.assertEqual( CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).end_date, jsondetails.end_date ) - jsondetails.certificate_available_date = datetime.datetime(2010, 10, 1, 0, tzinfo=UTC()) + jsondetails.certificate_available_date = datetime.datetime(2010, 10, 1, 0, tzinfo=UTC) self.assertEqual( CourseDetails.update_from_json( self.course.id, jsondetails.__dict__, self.user diff --git a/openedx/core/djangoapps/profile_images/views.py b/openedx/core/djangoapps/profile_images/views.py index d4aa052b66..43bb324022 100644 --- a/openedx/core/djangoapps/profile_images/views.py +++ b/openedx/core/djangoapps/profile_images/views.py @@ -6,7 +6,7 @@ import itertools import logging from contextlib import closing -from django.utils.timezone import utc +from pytz import UTC from django.utils.translation import ugettext as _ from rest_framework import permissions, status from rest_framework.parsers import FormParser, MultiPartParser @@ -37,7 +37,7 @@ def _make_upload_dt(): Generate a server-side timestamp for the upload. This is in a separate function so its behavior can be overridden in tests. """ - return datetime.datetime.utcnow().replace(tzinfo=utc) + return datetime.datetime.utcnow().replace(tzinfo=UTC) class ProfileImageView(DeveloperErrorViewMixin, APIView): diff --git a/openedx/core/lib/xblock_utils/__init__.py b/openedx/core/lib/xblock_utils/__init__.py index fa8603d7c7..a396fb4224 100644 --- a/openedx/core/lib/xblock_utils/__init__.py +++ b/openedx/core/lib/xblock_utils/__init__.py @@ -15,7 +15,7 @@ from contracts import contract from django.conf import settings from django.contrib.staticfiles.storage import staticfiles_storage from django.core.urlresolvers import reverse -from django.utils.timezone import UTC +from pytz import UTC from django.utils.html import escape from django.contrib.auth.models import User from edxmako.shortcuts import render_to_string @@ -350,7 +350,7 @@ def add_staff_markup(user, has_instructor_access, disable_staff_debug_info, bloc # Useful to indicate to staff if problem has been released or not. # TODO (ichuang): use _has_access_descriptor.can_load in lms.courseware.access, # instead of now>mstart comparison here. - now = datetime.datetime.now(UTC()) + now = datetime.datetime.now(UTC) is_released = "unknown" mstart = block.start diff --git a/openedx/features/course_experience/views/course_home_messages.py b/openedx/features/course_experience/views/course_home_messages.py index 3f35c8e68f..aea1864aaf 100644 --- a/openedx/features/course_experience/views/course_home_messages.py +++ b/openedx/features/course_experience/views/course_home_messages.py @@ -9,7 +9,8 @@ from django.conf import settings from django.contrib import auth from django.template.loader import render_to_string from django.utils.http import urlquote_plus -from django.utils.timezone import UTC +from pytz import UTC +from django.utils.translation import get_language, to_locale from django.utils.translation import ugettext as _ from django.utils.translation import get_language, to_locale from opaque_keys.edx.keys import CourseKey @@ -54,7 +55,7 @@ class CourseHomeMessageFragmentView(EdxFragmentView): course = get_course_with_access(request.user, 'load', course_key) # Get time until the start date, if already started, or no start date, value will be zero or negative - now = datetime.now(UTC()) + now = datetime.now(UTC) already_started = course.start and now > course.start days_until_start_string = "started" if already_started else format_timedelta(course.start - now, locale=to_locale(get_language())) course_start_data = { From 040f5cc9c441a4520d30930671a136550219506b Mon Sep 17 00:00:00 2001 From: John Eskew Date: Wed, 20 Sep 2017 20:30:43 -0400 Subject: [PATCH 5/9] Move edxnotes model import down into method. --- lms/djangoapps/edxnotes/decorators.py | 3 ++- lms/djangoapps/edxnotes/tests.py | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lms/djangoapps/edxnotes/decorators.py b/lms/djangoapps/edxnotes/decorators.py index 42857d7845..90b4257af1 100644 --- a/lms/djangoapps/edxnotes/decorators.py +++ b/lms/djangoapps/edxnotes/decorators.py @@ -7,7 +7,6 @@ import json from django.conf import settings from edxmako.shortcuts import render_to_string -from edxnotes.helpers import generate_uid, get_edxnotes_id_token, get_public_endpoint, get_token_url, is_feature_enabled def edxnotes(cls): @@ -20,6 +19,8 @@ def edxnotes(cls): """ Returns raw html for the component. """ + # Import is placed here to avoid model import at project startup. + from edxnotes.helpers import generate_uid, get_edxnotes_id_token, get_public_endpoint, get_token_url, is_feature_enabled is_studio = getattr(self.system, "is_author_mode", False) course = self.descriptor.runtime.modulestore.get_course(self.runtime.course_id) diff --git a/lms/djangoapps/edxnotes/tests.py b/lms/djangoapps/edxnotes/tests.py index dfc8e28139..d55c51e1f3 100644 --- a/lms/djangoapps/edxnotes/tests.py +++ b/lms/djangoapps/edxnotes/tests.py @@ -106,10 +106,10 @@ class EdxNotesDecoratorTest(ModuleStoreTestCase): self.problem = TestProblem(self.course) @patch.dict("django.conf.settings.FEATURES", {'ENABLE_EDXNOTES': True}) - @patch("edxnotes.decorators.get_public_endpoint", autospec=True) - @patch("edxnotes.decorators.get_token_url", autospec=True) - @patch("edxnotes.decorators.get_edxnotes_id_token", autospec=True) - @patch("edxnotes.decorators.generate_uid", autospec=True) + @patch("edxnotes.helpers.get_public_endpoint", autospec=True) + @patch("edxnotes.helpers.get_token_url", autospec=True) + @patch("edxnotes.helpers.get_edxnotes_id_token", autospec=True) + @patch("edxnotes.helpers.generate_uid", autospec=True) def test_edxnotes_enabled(self, mock_generate_uid, mock_get_id_token, mock_get_token_url, mock_get_endpoint): """ Tests if get_html is wrapped when feature flag is on and edxnotes are From 4b95abb7158c20503e231648e3d346c13ccc5b73 Mon Sep 17 00:00:00 2001 From: John Eskew Date: Thu, 21 Sep 2017 11:30:07 -0400 Subject: [PATCH 6/9] Make an AppConfig to register ccxcon signals. --- openedx/core/djangoapps/ccxcon/__init__.py | 3 ++- openedx/core/djangoapps/ccxcon/apps.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 openedx/core/djangoapps/ccxcon/apps.py diff --git a/openedx/core/djangoapps/ccxcon/__init__.py b/openedx/core/djangoapps/ccxcon/__init__.py index 6c2cbb1442..9a97524877 100644 --- a/openedx/core/djangoapps/ccxcon/__init__.py +++ b/openedx/core/djangoapps/ccxcon/__init__.py @@ -6,4 +6,5 @@ that is used to interact with the CCX and their master courses. The ccxcon app needs to be placed in `openedx.core.djangoapps` because it will be used both in CMS and LMS. """ -import openedx.core.djangoapps.ccxcon.signals + +default_app_config = 'openedx.core.djangoapps.ccxcon.apps.CCXConnectorConfig' diff --git a/openedx/core/djangoapps/ccxcon/apps.py b/openedx/core/djangoapps/ccxcon/apps.py new file mode 100644 index 0000000000..460e87392b --- /dev/null +++ b/openedx/core/djangoapps/ccxcon/apps.py @@ -0,0 +1,13 @@ +""" +Configuration for CCX connector +""" + +from django.apps import AppConfig + + +class CCXConnectorConfig(AppConfig): + name = 'openedx.core.djangoapps.ccxcon' + verbose_name = "CCX Connector" + + def ready(self): + import openedx.core.djangoapps.ccxcon.signals From 0890193d6b53e8d263d29d828815bcc7b020f917 Mon Sep 17 00:00:00 2001 From: John Eskew Date: Thu, 21 Sep 2017 11:40:52 -0400 Subject: [PATCH 7/9] PLAT-1408: Import csrf from new path. --- cms/djangoapps/contentstore/views/public.py | 2 +- common/djangoapps/student/views.py | 2 +- lms/djangoapps/courseware/module_render.py | 2 +- lms/djangoapps/courseware/views/index.py | 2 +- lms/djangoapps/courseware/views/views.py | 2 +- lms/djangoapps/discussion/views.py | 2 +- openedx/features/course_bookmarks/views/course_bookmarks.py | 2 +- openedx/features/course_experience/views/course_home.py | 2 +- openedx/features/course_experience/views/course_outline.py | 2 +- openedx/features/course_experience/views/course_updates.py | 2 +- openedx/features/course_search/views/course_search.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cms/djangoapps/contentstore/views/public.py b/cms/djangoapps/contentstore/views/public.py index e423ecc3f7..5367971726 100644 --- a/cms/djangoapps/contentstore/views/public.py +++ b/cms/djangoapps/contentstore/views/public.py @@ -2,7 +2,7 @@ Public views """ from django.conf import settings -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.urlresolvers import reverse from django.shortcuts import redirect from django.views.decorators.clickjacking import xframe_options_deny diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 463e56f557..4a269643f1 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -20,7 +20,7 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.models import AnonymousUser, User from django.contrib.auth.views import password_reset_confirm from django.core import mail -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy from django.core.validators import ValidationError, validate_email diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 7bb0833c26..231e960ab3 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -11,7 +11,7 @@ from functools import partial from django.conf import settings from django.contrib.auth.models import User from django.core.cache import cache -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from django.http import Http404, HttpResponse diff --git a/lms/djangoapps/courseware/views/index.py b/lms/djangoapps/courseware/views/index.py index cdc45db8e0..9b49ea544a 100644 --- a/lms/djangoapps/courseware/views/index.py +++ b/lms/djangoapps/courseware/views/index.py @@ -10,7 +10,7 @@ import urllib from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.urlresolvers import reverse from django.http import Http404 from django.utils.decorators import method_decorator diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 90872ee083..d01f8d00e1 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -39,7 +39,7 @@ from courseware.user_state_client import DjangoXBlockUserStateClient from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.models import AnonymousUser, User -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from django.db import transaction diff --git a/lms/djangoapps/discussion/views.py b/lms/djangoapps/discussion/views.py index bc156ec956..00c718e69c 100644 --- a/lms/djangoapps/discussion/views.py +++ b/lms/djangoapps/discussion/views.py @@ -11,7 +11,7 @@ from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.contrib.staticfiles.storage import staticfiles_storage -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.urlresolvers import reverse from django.http import Http404, HttpResponseServerError from django.shortcuts import render_to_response diff --git a/openedx/features/course_bookmarks/views/course_bookmarks.py b/openedx/features/course_bookmarks/views/course_bookmarks.py index 207db69965..4a108434dd 100644 --- a/openedx/features/course_bookmarks/views/course_bookmarks.py +++ b/openedx/features/course_bookmarks/views/course_bookmarks.py @@ -3,7 +3,7 @@ Views to show a course's bookmarks. """ from django.contrib.auth.decorators import login_required -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.urlresolvers import reverse from django.shortcuts import render_to_response from django.template.loader import render_to_string diff --git a/openedx/features/course_experience/views/course_home.py b/openedx/features/course_experience/views/course_home.py index 7c70b8ca99..648f3f716f 100644 --- a/openedx/features/course_experience/views/course_home.py +++ b/openedx/features/course_experience/views/course_home.py @@ -2,7 +2,7 @@ Views for the course home page. """ -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.urlresolvers import reverse from django.template.loader import render_to_string from django.utils.decorators import method_decorator diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py index d8c4263224..ebe7745f48 100644 --- a/openedx/features/course_experience/views/course_outline.py +++ b/openedx/features/course_experience/views/course_outline.py @@ -1,7 +1,7 @@ """ Views to show a course outline. """ -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.template.loader import render_to_string from opaque_keys.edx.keys import CourseKey from web_fragments.fragment import Fragment diff --git a/openedx/features/course_experience/views/course_updates.py b/openedx/features/course_experience/views/course_updates.py index 77ab2404b4..b1a99256f0 100644 --- a/openedx/features/course_experience/views/course_updates.py +++ b/openedx/features/course_experience/views/course_updates.py @@ -4,7 +4,7 @@ Views that handle course updates. from datetime import datetime from django.contrib.auth.decorators import login_required -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.urlresolvers import reverse from django.template.loader import render_to_string from django.utils.decorators import method_decorator diff --git a/openedx/features/course_search/views/course_search.py b/openedx/features/course_search/views/course_search.py index 6c7da085ff..c9b704f120 100644 --- a/openedx/features/course_search/views/course_search.py +++ b/openedx/features/course_search/views/course_search.py @@ -3,7 +3,7 @@ Views for the course search page. """ from django.contrib.auth.decorators import login_required -from django.core.context_processors import csrf +from django.template.context_processors import csrf from django.core.urlresolvers import reverse from django.template.loader import render_to_string from django.utils.decorators import method_decorator From 762b87e25ded495aab3b5ff96774e8a2230f395d Mon Sep 17 00:00:00 2001 From: John Eskew Date: Mon, 2 Oct 2017 19:30:55 -0400 Subject: [PATCH 8/9] Move xblock tagging model import into method. --- cms/lib/xblock/tagging/tagging.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cms/lib/xblock/tagging/tagging.py b/cms/lib/xblock/tagging/tagging.py index c7290b1b62..097ffd1157 100644 --- a/cms/lib/xblock/tagging/tagging.py +++ b/cms/lib/xblock/tagging/tagging.py @@ -13,8 +13,6 @@ from edxmako.shortcuts import render_to_string from xmodule.capa_module import CapaModule from xmodule.x_module import AUTHOR_VIEW -from .models import TagCategories - _ = lambda text: text @@ -30,6 +28,8 @@ class StructuredTagsAside(XBlockAside): """ Return available tags """ + # Import is placed here to avoid model import at project startup. + from .models import TagCategories return TagCategories.objects.all() def _get_studio_resource_url(self, relative_url): From f5f6b08884bb1e9c3f58260faf4a1d7da8f9a859 Mon Sep 17 00:00:00 2001 From: John Eskew Date: Tue, 3 Oct 2017 08:32:08 -0400 Subject: [PATCH 9/9] Add missing 'later' variable. --- .../django_comment_client/tests/test_utils.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lms/djangoapps/django_comment_client/tests/test_utils.py b/lms/djangoapps/django_comment_client/tests/test_utils.py index 5f29b23261..02d02dd038 100644 --- a/lms/djangoapps/django_comment_client/tests/test_utils.py +++ b/lms/djangoapps/django_comment_client/tests/test_utils.py @@ -390,6 +390,7 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): self.discussion_num = 0 self.instructor = InstructorFactory(course_key=self.course.id) self.maxDiff = None # pylint: disable=invalid-name + self.later = datetime.datetime(2050, 1, 1, tzinfo=UTC) def create_discussion(self, discussion_category, discussion_target, **kwargs): self.discussion_num += 1 @@ -539,7 +540,7 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): def test_get_unstarted_discussion_xblocks(self): - self.create_discussion("Chapter 1", "Discussion 1", start=later) + self.create_discussion("Chapter 1", "Discussion 1", start=self.later) self.assert_category_map_equals( { @@ -551,12 +552,12 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): "id": "discussion1", "sort_key": None, "is_divided": False, - "start_date": later + "start_date": self.later } }, "subcategories": {}, "children": [("Discussion 1", TYPE_ENTRY)], - "start_date": later, + "start_date": self.later, "sort_key": "Chapter 1" } }, @@ -696,13 +697,12 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): def test_start_date_filter(self): now = datetime.datetime.now() - later = datetime.datetime.max self.create_discussion("Chapter 1", "Discussion 1", start=now) - self.create_discussion("Chapter 1", "Discussion 2 обсуждение", start=later) + self.create_discussion("Chapter 1", "Discussion 2 обсуждение", start=self.later) self.create_discussion("Chapter 2", "Discussion", start=now) - self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion", start=later) - self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion", start=later) - self.create_discussion("Chapter 3 / Section 1", "Discussion", start=later) + self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion", start=self.later) + self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion", start=self.later) + self.create_discussion("Chapter 3 / Section 1", "Discussion", start=self.later) self.assertFalse(self.course.self_paced) self.assert_category_map_equals( @@ -740,13 +740,12 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): self.course.self_paced = True now = datetime.datetime.now() - later = datetime.datetime.max self.create_discussion("Chapter 1", "Discussion 1", start=now) - self.create_discussion("Chapter 1", "Discussion 2", start=later) + self.create_discussion("Chapter 1", "Discussion 2", start=self.later) self.create_discussion("Chapter 2", "Discussion", start=now) - self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion", start=later) - self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion", start=later) - self.create_discussion("Chapter 3 / Section 1", "Discussion", start=later) + self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion", start=self.later) + self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion", start=self.later) + self.create_discussion("Chapter 3 / Section 1", "Discussion", start=self.later) self.assertTrue(self.course.self_paced) self.assert_category_map_equals(