From 4a120a9e266d011eaea6cbad8f7296ddcd300c1a Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Tue, 22 Sep 2020 11:38:54 -0400 Subject: [PATCH] Fix failures caused by removing lms/djangoapps from sys.path --- cms/envs/bok_choy.py | 2 + cms/envs/common.py | 6 +- cms/envs/test.py | 7 +- .../student/tests/test_verification_status.py | 2 +- docs/docs_settings.py | 2 +- docs/guides/conf.py | 9 --- lms/djangoapps/badges/apps.py | 2 +- lms/djangoapps/branding/tests/test_api.py | 2 +- lms/djangoapps/bulk_email/apps.py | 8 ++ .../bulk_email/tests/test_course_optout.py | 4 +- lms/djangoapps/bulk_email/tests/test_email.py | 12 +-- .../bulk_email/tests/test_err_handling.py | 26 +++---- .../bulk_email/tests/test_models.py | 2 +- .../bulk_email/tests/test_signals.py | 2 +- lms/djangoapps/bulk_email/tests/test_tasks.py | 34 ++++---- lms/djangoapps/bulk_email/urls.py | 2 +- lms/djangoapps/bulk_enroll/urls.py | 2 +- lms/djangoapps/ccx/urls.py | 20 ++--- lms/djangoapps/courseware/models.py | 4 +- .../coursewarehistoryextended/apps.py | 5 ++ lms/djangoapps/dashboard/sysadmin_urls.py | 2 +- lms/djangoapps/discussion/urls.py | 2 +- lms/djangoapps/edxnotes/decorators.py | 2 +- lms/djangoapps/edxnotes/tests.py | 68 ++++++++-------- lms/djangoapps/edxnotes/urls.py | 2 +- lms/djangoapps/email_marketing/signals.py | 2 +- .../email_marketing/tests/__init__.py | 0 .../email_marketing/tests/test_signals.py | 78 +++++++++---------- lms/djangoapps/experiments/apps.py | 8 ++ .../experiments/tests/test_flags.py | 10 +-- lms/djangoapps/experiments/urls.py | 2 +- lms/djangoapps/instructor/tests/test_api.py | 4 +- .../instructor_task/tests/test_api.py | 2 +- lms/djangoapps/lti_provider/apps.py | 2 +- .../lti_provider/tests/test_users.py | 22 +++--- .../lti_provider/tests/test_views.py | 20 ++--- lms/djangoapps/rss_proxy/urls.py | 2 +- .../processors/tests/test_CyberSource2.py | 6 +- .../shoppingcart/tests/test_models.py | 22 +++--- .../shoppingcart/tests/test_views.py | 72 ++++++++--------- lms/djangoapps/shoppingcart/urls.py | 2 +- lms/djangoapps/support/tests/test_views.py | 8 +- lms/djangoapps/support/urls.py | 18 ++--- .../tests/test_fake_software_secure.py | 2 +- lms/envs/bok_choy.py | 1 + lms/envs/common.py | 39 +++++----- lms/envs/production.py | 4 +- lms/envs/test.py | 1 + lms/urls.py | 16 ++-- openedx/tests/settings.py | 4 +- .../courseware/management/commands/import.py | 4 - 51 files changed, 298 insertions(+), 282 deletions(-) create mode 100644 lms/djangoapps/bulk_email/apps.py create mode 100644 lms/djangoapps/coursewarehistoryextended/apps.py create mode 100644 lms/djangoapps/email_marketing/tests/__init__.py create mode 100644 lms/djangoapps/experiments/apps.py delete mode 100644 sys_path_hacks/lms/courseware/management/commands/import.py diff --git a/cms/envs/bok_choy.py b/cms/envs/bok_choy.py index 689c3267f1..10eb112542 100644 --- a/cms/envs/bok_choy.py +++ b/cms/envs/bok_choy.py @@ -20,6 +20,7 @@ from django.utils.translation import ugettext_lazy from path import Path as path from openedx.core.release import RELEASE_LINE +from xmodule.modulestore.modulestore_settings import update_module_store_settings ########################## Prod-like settings ################################### # These should be as close as possible to the settings we use in production. @@ -36,6 +37,7 @@ os.environ['REVISION_CFG'] = "{config_root}/revisions.yml".format(config_root=CO from .production import * # pylint: disable=wildcard-import, unused-wildcard-import, wrong-import-position + ######################### Testing overrides #################################### # Redirect to the test_root folder within the repo diff --git a/cms/envs/common.py b/cms/envs/common.py index 3e37dc89c8..31b53faebb 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -48,7 +48,7 @@ from datetime import timedelta import lms.envs.common # Although this module itself may not use these imported variables, other dependent modules may. from lms.envs.common import ( - USE_TZ, ALL_LANGUAGES, update_module_store_settings, ASSET_IGNORE_REGEX, + USE_TZ, ALL_LANGUAGES, ASSET_IGNORE_REGEX, PARENTAL_CONSENT_AGE_LIMIT, REGISTRATION_EMAIL_PATTERNS_ALLOWED, # The following PROFILE_IMAGE_* settings are included as they are # indirectly accessed through the email opt-in API, which is @@ -1440,7 +1440,7 @@ INSTALLED_APPS = [ # by installed apps. 'openedx.core.djangoapps.oauth_dispatch.apps.OAuthDispatchAppConfig', 'lms.djangoapps.courseware', - 'coursewarehistoryextended', + 'lms.djangoapps.coursewarehistoryextended', 'survey.apps.SurveyConfig', 'lms.djangoapps.verify_student.apps.VerifyStudentConfig', 'completion', @@ -1499,7 +1499,7 @@ INSTALLED_APPS = [ 'openedx.features.course_duration_limits', 'openedx.features.content_type_gating', 'openedx.features.discounts', - 'experiments', + 'lms.djangoapps.experiments', 'openedx.core.djangoapps.external_user_ids', # so sample_task is available to celery workers diff --git a/cms/envs/test.py b/cms/envs/test.py index f6bc09aca3..28acea10ae 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -14,7 +14,6 @@ sessions. Assumes structure: # pylint: disable=wildcard-import, unused-wildcard-import -from .common import * import os from uuid import uuid4 @@ -24,8 +23,12 @@ from path import Path as path from openedx.core.lib.derived import derive_settings from util.db import NoOpMigrationModules +from xmodule.modulestore.modulestore_settings import update_module_store_settings + +from .common import * + # import settings from LMS for consistent behavior with CMS -from lms.envs.test import ( +from lms.envs.test import ( # pylint: disable=wrong-import-order COMPREHENSIVE_THEME_DIRS, DEFAULT_FILE_STORAGE, ECOMMERCE_API_URL, diff --git a/common/djangoapps/student/tests/test_verification_status.py b/common/djangoapps/student/tests/test_verification_status.py index 576a6455c4..63a799950a 100644 --- a/common/djangoapps/student/tests/test_verification_status.py +++ b/common/djangoapps/student/tests/test_verification_status.py @@ -44,7 +44,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase): None: None, } - URLCONF_MODULES = ['verify_student.urls'] + URLCONF_MODULES = ['lms.djangoapps.verify_student.urls'] def setUp(self): # Invoke UrlResetMixin diff --git a/docs/docs_settings.py b/docs/docs_settings.py index 285e589b4f..eab8084a03 100644 --- a/docs/docs_settings.py +++ b/docs/docs_settings.py @@ -40,5 +40,5 @@ INSTALLED_APPS.extend([ 'course_creators', 'xblock_config.apps.XBlockConfig', 'user_tasks', - 'lti_provider' + 'lms.djangoapps.lti_provider' ]) diff --git a/docs/guides/conf.py b/docs/guides/conf.py index 6869940c3f..6c36e8306e 100644 --- a/docs/guides/conf.py +++ b/docs/guides/conf.py @@ -254,15 +254,6 @@ for app in os.listdir(six.text_type(root / 'common' / 'djangoapps')): if os.path.isdir(six.text_type(root / path)) and app != 'terrain': modules[path] = path -# These Django apps under lms don't import correctly with the "lms.djangapps" prefix -# Others don't import correctly without it...INSTALLED_APPS entries are inconsistent -lms_djangoapps = ['badges', 'branding', 'bulk_email', 'courseware', - 'coursewarehistoryextended', 'email_marketing', 'experiments', 'lti_provider', - 'mobile_api', 'notes', 'rss_proxy', 'shoppingcart', 'survey'] -for app in lms_djangoapps: - path = os.path.join('lms', 'djangoapps', app) - modules[path] = path - def update_settings_module(service='lms'): """ diff --git a/lms/djangoapps/badges/apps.py b/lms/djangoapps/badges/apps.py index f637ba7c60..f76094a905 100644 --- a/lms/djangoapps/badges/apps.py +++ b/lms/djangoapps/badges/apps.py @@ -12,7 +12,7 @@ class BadgesConfig(AppConfig): """ Application Configuration for Badges. """ - name = u'badges' + name = u'lms.djangoapps.badges' def ready(self): """ diff --git a/lms/djangoapps/branding/tests/test_api.py b/lms/djangoapps/branding/tests/test_api.py index 934b759b2f..8d6a3c45cf 100644 --- a/lms/djangoapps/branding/tests/test_api.py +++ b/lms/djangoapps/branding/tests/test_api.py @@ -8,7 +8,7 @@ from django.test import TestCase from django.test.utils import override_settings from django.urls import reverse -from branding.api import _footer_business_links, get_footer, get_home_url, get_logo_url +from ..api import _footer_business_links, get_footer, get_home_url, get_logo_url from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration test_config_disabled_contact_us = { # pylint: disable=invalid-name diff --git a/lms/djangoapps/bulk_email/apps.py b/lms/djangoapps/bulk_email/apps.py new file mode 100644 index 0000000000..5210341321 --- /dev/null +++ b/lms/djangoapps/bulk_email/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig + + +class BulkEmailConfig(AppConfig): + """ + Application Configuration for bulk_email. + """ + name = u'lms.djangoapps.bulk_email' diff --git a/lms/djangoapps/bulk_email/tests/test_course_optout.py b/lms/djangoapps/bulk_email/tests/test_course_optout.py index fc03546ce8..8eb793ef88 100644 --- a/lms/djangoapps/bulk_email/tests/test_course_optout.py +++ b/lms/djangoapps/bulk_email/tests/test_course_optout.py @@ -26,7 +26,7 @@ from xmodule.modulestore.tests.factories import CourseFactory from lms.djangoapps.bulk_email.api import get_unsubscribed_link -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestOptoutCourseEmails(ModuleStoreTestCase): """ Test that optouts are referenced in sending course email. @@ -144,7 +144,7 @@ class TestOptoutCourseEmails(ModuleStoreTestCase): self.assertIn(self.instructor.email, sent_addresses) -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestACEOptoutCourseEmails(ModuleStoreTestCase): """ Test that optouts are referenced in sending course email. diff --git a/lms/djangoapps/bulk_email/tests/test_email.py b/lms/djangoapps/bulk_email/tests/test_email.py index 7ec87ea5cb..9fe1a67ab9 100644 --- a/lms/djangoapps/bulk_email/tests/test_email.py +++ b/lms/djangoapps/bulk_email/tests/test_email.py @@ -21,8 +21,8 @@ from django.utils.translation import get_language from markupsafe import escape from mock import Mock, patch -from bulk_email.models import BulkEmailFlag, Optout -from bulk_email.tasks import _get_course_email_context, _get_source_address +from ..models import BulkEmailFlag, Optout +from ..tasks import _get_course_email_context, _get_source_address from course_modes.models import CourseMode from lms.djangoapps.courseware.tests.factories import InstructorFactory, StaffFactory @@ -166,7 +166,7 @@ class SendEmailWithMockedUgettextMixin(object): text=text, ) - with patch('bulk_email.tasks._', side_effect=mock_ugettext): + with patch('lms.djangoapps.bulk_email.tasks._', side_effect=mock_ugettext): self.client.post(self.send_mail_url, test_email) return mail.outbox[0] @@ -229,7 +229,7 @@ class LocalizedFromAddressCourseLangTestCase(SendEmailWithMockedUgettextMixin, E self.assertRegex(message.from_email, 'AR .* Course Staff') -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase): """ Tests email sending with mocked html_to_text. @@ -249,7 +249,7 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase) # We should get back a HttpResponseForbidden (status code 403) self.assertContains(response, "Email is not enabled for this course.", status_code=403) - @patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) + @patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) def test_send_to_self(self): """ Make sure email send to myself goes to myself. @@ -566,7 +566,7 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase) self.assertEqual(len(from_email), 61) @override_settings(BULK_EMAIL_EMAILS_PER_TASK=3) - @patch('bulk_email.tasks.update_subtask_status') + @patch('lms.djangoapps.bulk_email.tasks.update_subtask_status') def test_chunked_queries_send_numerous_emails(self, email_mock): """ Test sending a large number of emails, to test the chunked querying diff --git a/lms/djangoapps/bulk_email/tests/test_err_handling.py b/lms/djangoapps/bulk_email/tests/test_err_handling.py index de041e0479..df970373aa 100644 --- a/lms/djangoapps/bulk_email/tests/test_err_handling.py +++ b/lms/djangoapps/bulk_email/tests/test_err_handling.py @@ -41,7 +41,7 @@ class EmailTestException(Exception): @ddt.ddt -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestEmailErrors(ModuleStoreTestCase): """ Test that errors from sending email are handled properly. @@ -75,8 +75,8 @@ class TestEmailErrors(ModuleStoreTestCase): super(TestEmailErrors, cls).tearDownClass() BulkEmailFlag.objects.all().delete() - @patch('bulk_email.tasks.get_connection', autospec=True) - @patch('bulk_email.tasks.send_course_email.retry') + @patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) + @patch('lms.djangoapps.bulk_email.tasks.send_course_email.retry') def test_data_err_retry(self, retry, get_conn): """ Test that celery handles transient SMTPDataErrors by retrying. @@ -97,9 +97,9 @@ class TestEmailErrors(ModuleStoreTestCase): exc = kwargs['exc'] self.assertIsInstance(exc, SMTPDataError) - @patch('bulk_email.tasks.get_connection', autospec=True) - @patch('bulk_email.tasks.update_subtask_status') - @patch('bulk_email.tasks.send_course_email.retry') + @patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) + @patch('lms.djangoapps.bulk_email.tasks.update_subtask_status') + @patch('lms.djangoapps.bulk_email.tasks.send_course_email.retry') def test_data_err_fail(self, retry, result, get_conn): """ Test that celery handles permanent SMTPDataErrors by failing and not retrying. @@ -130,8 +130,8 @@ class TestEmailErrors(ModuleStoreTestCase): self.assertEqual(subtask_status.failed, expected_fails) self.assertEqual(subtask_status.succeeded, settings.BULK_EMAIL_EMAILS_PER_TASK - expected_fails) - @patch('bulk_email.tasks.get_connection', autospec=True) - @patch('bulk_email.tasks.send_course_email.retry') + @patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) + @patch('lms.djangoapps.bulk_email.tasks.send_course_email.retry') def test_disconn_err_retry(self, retry, get_conn): """ Test that celery handles SMTPServerDisconnected by retrying. @@ -151,8 +151,8 @@ class TestEmailErrors(ModuleStoreTestCase): exc = kwargs['exc'] self.assertIsInstance(exc, SMTPServerDisconnected) - @patch('bulk_email.tasks.get_connection', autospec=True) - @patch('bulk_email.tasks.send_course_email.retry') + @patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) + @patch('lms.djangoapps.bulk_email.tasks.send_course_email.retry') def test_conn_err_retry(self, retry, get_conn): """ Test that celery handles SMTPConnectError by retrying. @@ -173,8 +173,8 @@ class TestEmailErrors(ModuleStoreTestCase): exc = kwargs['exc'] self.assertIsInstance(exc, SMTPConnectError) - @patch('bulk_email.tasks.SubtaskStatus.increment') - @patch('bulk_email.tasks.log') + @patch('lms.djangoapps.bulk_email.tasks.SubtaskStatus.increment') + @patch('lms.djangoapps.bulk_email.tasks.log') def test_nonexistent_email(self, mock_log, result): """ Tests retries when the email doesn't exist @@ -368,5 +368,5 @@ class TestEmailErrors(ModuleStoreTestCase): with self.assertRaises(CourseEmail.DoesNotExist): # we skip the call that updates subtask status, since we've not set up the InstructorTask # for the subtask, and it's not important to the test. - with patch('bulk_email.tasks.update_subtask_status'): + with patch('lms.djangoapps.bulk_email.tasks.update_subtask_status'): send_course_email(entry_id, bogus_email_id, to_list, global_email_context, subtask_status.to_dict()) diff --git a/lms/djangoapps/bulk_email/tests/test_models.py b/lms/djangoapps/bulk_email/tests/test_models.py index dad44c92cc..75592ee7b2 100644 --- a/lms/djangoapps/bulk_email/tests/test_models.py +++ b/lms/djangoapps/bulk_email/tests/test_models.py @@ -31,7 +31,7 @@ from xmodule.modulestore.tests.factories import CourseFactory @ddt.ddt -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class CourseEmailTest(ModuleStoreTestCase): """Test the CourseEmail model.""" diff --git a/lms/djangoapps/bulk_email/tests/test_signals.py b/lms/djangoapps/bulk_email/tests/test_signals.py index fd97eef979..fcd8ee9fa1 100644 --- a/lms/djangoapps/bulk_email/tests/test_signals.py +++ b/lms/djangoapps/bulk_email/tests/test_signals.py @@ -18,7 +18,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestOptoutCourseEmailsBySignal(ModuleStoreTestCase): """ Tests that the force_optout_all signal receiver opts the user out of course emails diff --git a/lms/djangoapps/bulk_email/tests/test_tasks.py b/lms/djangoapps/bulk_email/tests/test_tasks.py index 1d1ac9e451..4ab4de01e6 100644 --- a/lms/djangoapps/bulk_email/tests/test_tasks.py +++ b/lms/djangoapps/bulk_email/tests/test_tasks.py @@ -32,8 +32,8 @@ from mock import Mock, patch from opaque_keys.edx.locator import CourseLocator from six.moves import range -from bulk_email.models import SEND_TO_LEARNERS, SEND_TO_MYSELF, SEND_TO_STAFF, CourseEmail, Optout -from bulk_email.tasks import _get_course_email_context +from ..models import SEND_TO_LEARNERS, SEND_TO_MYSELF, SEND_TO_STAFF, CourseEmail, Optout +from ..tasks import _get_course_email_context from lms.djangoapps.instructor_task.models import InstructorTask from lms.djangoapps.instructor_task.subtasks import SubtaskStatus, update_subtask_status from lms.djangoapps.instructor_task.tasks import send_bulk_course_email @@ -75,7 +75,7 @@ def my_update_subtask_status(entry_id, current_task_id, new_subtask_status): update_subtask_status(entry_id, current_task_id, new_subtask_status) -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): """Tests instructor task that send bulk email.""" @@ -134,7 +134,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): update_subtask_status(entry_id, bogus_task_id, new_subtask_status) with self.assertRaises(ValueError): - with patch('bulk_email.tasks.update_subtask_status', dummy_update_subtask_status): + with patch('lms.djangoapps.bulk_email.tasks.update_subtask_status', dummy_update_subtask_status): send_bulk_course_email(task_entry.id, {}) def _create_students(self, num_students): @@ -194,7 +194,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): num_emails = settings.BULK_EMAIL_EMAILS_PER_TASK # We also send email to the instructor: self._create_students(num_emails - 1) - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: get_conn.return_value.send_messages.side_effect = cycle([None]) self._test_run_with_task(send_bulk_course_email, 'emailed', num_emails, num_emails) @@ -203,12 +203,12 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): num_emails = settings.BULK_EMAIL_EMAILS_PER_TASK # We also send email to the instructor: self._create_students(num_emails - 1) - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: get_conn.return_value.send_messages.side_effect = cycle([None]) task_entry = self._test_run_with_task(send_bulk_course_email, 'emailed', num_emails, num_emails) # submit the same task a second time, and confirm that it is not run again. - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: get_conn.return_value.send_messages.side_effect = cycle([Exception("This should not happen!")]) parent_status = self._run_task_with_mock_celery(send_bulk_course_email, task_entry.id, task_entry.task_id) self.assertEqual(parent_status.get('total'), num_emails) @@ -224,7 +224,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): student = students[0] student.is_active = False student.save() - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: get_conn.return_value.send_messages.side_effect = cycle([None]) self._test_run_with_task(send_bulk_course_email, 'emailed', num_emails - 1, num_emails - 1) @@ -239,7 +239,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): for index in range(0, num_emails, 4): Optout.objects.create(user=students[index], course_id=self.course.id) # mark some students as opting out - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: get_conn.return_value.send_messages.side_effect = cycle([None]) self._test_run_with_task( send_bulk_course_email, 'emailed', num_emails, expected_succeeds, skipped=expected_skipped @@ -253,7 +253,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): self._create_students(num_emails - 1) expected_fails = int((num_emails + 3) / 4.0) expected_succeeds = num_emails - expected_fails - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: # have every fourth email fail due to some address failure: get_conn.return_value.send_messages.side_effect = cycle([exception, None, None, None]) self._test_run_with_task( @@ -298,7 +298,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): expected_succeeds = num_emails - emails_with_non_ascii_chars + num_of_course_instructors expected_fails = emails_with_non_ascii_chars - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: get_conn.return_value.send_messages.side_effect = cycle([None]) self._test_run_with_task( task_class=send_bulk_course_email, @@ -317,7 +317,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): self._create_students(num_emails - 1) expected_fails = 0 expected_succeeds = num_emails - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: # Have every other mail attempt fail due to disconnection. get_conn.return_value.send_messages.side_effect = cycle([exception, None]) self._test_run_with_task( @@ -338,10 +338,10 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): self._create_students(num_emails - 1) expected_fails = num_emails expected_succeeds = 0 - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: # always fail to connect, triggering repeated retries until limit is hit: get_conn.return_value.send_messages.side_effect = cycle([exception]) - with patch('bulk_email.tasks.update_subtask_status', my_update_subtask_status): + with patch('lms.djangoapps.bulk_email.tasks.update_subtask_status', my_update_subtask_status): self._test_run_with_task( send_bulk_course_email, 'emailed', @@ -392,7 +392,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): # exceeded"). The maximum recursion depth is 90, so # num_emails * expected_retries < 90. expected_retries = 10 - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: # Cycle through N throttling errors followed by a success. get_conn.return_value.send_messages.side_effect = cycle( chain(repeat(exception, expected_retries), [None]) @@ -423,7 +423,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): self._create_students(num_emails - 1) expected_fails = num_emails expected_succeeds = 0 - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: # always fail to connect, triggering repeated retries until limit is hit: get_conn.return_value.send_messages.side_effect = cycle([exception]) self._test_run_with_task( @@ -458,7 +458,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase): # We also send email to the instructor: self._create_students(num_emails - 1) - with patch('bulk_email.tasks.get_connection', autospec=True) as get_conn: + with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn: get_conn.return_value.send_messages.side_effect = cycle([None]) self._test_run_with_task(send_bulk_course_email, 'emailed', num_emails, num_emails) diff --git a/lms/djangoapps/bulk_email/urls.py b/lms/djangoapps/bulk_email/urls.py index 6766c2050c..d62026ed9f 100644 --- a/lms/djangoapps/bulk_email/urls.py +++ b/lms/djangoapps/bulk_email/urls.py @@ -5,7 +5,7 @@ URLs for bulk_email app from django.conf.urls import url from django.conf import settings -from bulk_email import views +from . import views urlpatterns = [ url( diff --git a/lms/djangoapps/bulk_enroll/urls.py b/lms/djangoapps/bulk_enroll/urls.py index fe334c2be6..f9f2ab1c73 100644 --- a/lms/djangoapps/bulk_enroll/urls.py +++ b/lms/djangoapps/bulk_enroll/urls.py @@ -5,7 +5,7 @@ URLs for the Bulk Enrollment API from django.conf.urls import url -from bulk_enroll.views import BulkEnrollView +from .views import BulkEnrollView urlpatterns = [ url(r'^bulk_enroll', BulkEnrollView.as_view(), name='bulk_enroll'), diff --git a/lms/djangoapps/ccx/urls.py b/lms/djangoapps/ccx/urls.py index c59df27487..c2e2041dc0 100644 --- a/lms/djangoapps/ccx/urls.py +++ b/lms/djangoapps/ccx/urls.py @@ -5,19 +5,19 @@ URLs for the CCX Feature. from django.conf.urls import url -import ccx.views +from . import views urlpatterns = [ - url(r'^ccx_coach$', ccx.views.dashboard, name='ccx_coach_dashboard'), - url(r'^create_ccx$', ccx.views.create_ccx, name='create_ccx'), - url(r'^save_ccx$', ccx.views.save_ccx, name='save_ccx'), - url(r'^ccx_schedule$', ccx.views.ccx_schedule, name='ccx_schedule'), - url(r'^ccx-manage-students$', ccx.views.ccx_students_management, name='ccx-manage-students'), + url(r'^ccx_coach$', views.dashboard, name='ccx_coach_dashboard'), + url(r'^create_ccx$', views.create_ccx, name='create_ccx'), + url(r'^save_ccx$', views.save_ccx, name='save_ccx'), + url(r'^ccx_schedule$', views.ccx_schedule, name='ccx_schedule'), + url(r'^ccx-manage-students$', views.ccx_students_management, name='ccx-manage-students'), # Grade book - url(r'^ccx_gradebook$', ccx.views.ccx_gradebook, name='ccx_gradebook'), - url(r'^ccx_gradebook/(?P[0-9]+)$', ccx.views.ccx_gradebook, name='ccx_gradebook'), + url(r'^ccx_gradebook$', views.ccx_gradebook, name='ccx_gradebook'), + url(r'^ccx_gradebook/(?P[0-9]+)$', views.ccx_gradebook, name='ccx_gradebook'), - url(r'^ccx_grades.csv$', ccx.views.ccx_grades_csv, name='ccx_grades_csv'), - url(r'^ccx_set_grading_policy$', ccx.views.set_grading_policy, name='ccx_set_grading_policy'), + url(r'^ccx_grades.csv$', views.ccx_grades_csv, name='ccx_grades_csv'), + url(r'^ccx_set_grading_policy$', views.set_grading_policy, name='ccx_set_grading_policy'), ] diff --git a/lms/djangoapps/courseware/models.py b/lms/djangoapps/courseware/models.py index d6dae57db4..68699a9ec1 100644 --- a/lms/djangoapps/courseware/models.py +++ b/lms/djangoapps/courseware/models.py @@ -31,7 +31,6 @@ from lms.djangoapps.courseware.fields import UnsignedBigIntAutoField from six import text_type from six.moves import range -import coursewarehistoryextended from openedx.core.djangolib.markup import HTML log = logging.getLogger("edx.courseware") @@ -217,7 +216,8 @@ class BaseStudentModuleHistory(models.Model): history_entries = [] if settings.FEATURES.get('ENABLE_CSMH_EXTENDED'): - history_entries += coursewarehistoryextended.models.StudentModuleHistoryExtended.objects.filter( + from lms.djangoapps.coursewarehistoryextended.models import StudentModuleHistoryExtended + history_entries += StudentModuleHistoryExtended.objects.filter( # Django will sometimes try to join to courseware_studentmodule # so just do an in query student_module__in=[module.id for module in student_modules] diff --git a/lms/djangoapps/coursewarehistoryextended/apps.py b/lms/djangoapps/coursewarehistoryextended/apps.py new file mode 100644 index 0000000000..91257be909 --- /dev/null +++ b/lms/djangoapps/coursewarehistoryextended/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CoursewareHistoryExtendedConfig(AppConfig): + name = u'lms.djangoapps.coursewarehistoryextended' diff --git a/lms/djangoapps/dashboard/sysadmin_urls.py b/lms/djangoapps/dashboard/sysadmin_urls.py index 34cf67d22b..f5d6a84243 100644 --- a/lms/djangoapps/dashboard/sysadmin_urls.py +++ b/lms/djangoapps/dashboard/sysadmin_urls.py @@ -5,7 +5,7 @@ Urls for sysadmin dashboard feature from django.conf.urls import url -from dashboard import sysadmin +from . import sysadmin urlpatterns = [ url(r'^$', sysadmin.Users.as_view(), name="sysadmin"), diff --git a/lms/djangoapps/discussion/urls.py b/lms/djangoapps/discussion/urls.py index e0fb48e475..01f94dc443 100644 --- a/lms/djangoapps/discussion/urls.py +++ b/lms/djangoapps/discussion/urls.py @@ -5,7 +5,7 @@ Forum urls for the django_comment_client. from django.conf.urls import url -from discussion import views +from . import views urlpatterns = [ url(r'users/(?P\w+)/followed$', views.followed_threads, name='followed_threads'), diff --git a/lms/djangoapps/edxnotes/decorators.py b/lms/djangoapps/edxnotes/decorators.py index 2fdb5da743..0fab13d329 100644 --- a/lms/djangoapps/edxnotes/decorators.py +++ b/lms/djangoapps/edxnotes/decorators.py @@ -22,7 +22,7 @@ def edxnotes(cls): Returns raw html for the component. """ # Import is placed here to avoid model import at project startup. - from edxnotes.helpers import ( + from .helpers import ( generate_uid, get_edxnotes_id_token, get_public_endpoint, get_token_url, is_feature_enabled ) diff --git a/lms/djangoapps/edxnotes/tests.py b/lms/djangoapps/edxnotes/tests.py index ae3fb317ed..d83faf288e 100644 --- a/lms/djangoapps/edxnotes/tests.py +++ b/lms/djangoapps/edxnotes/tests.py @@ -26,10 +26,10 @@ from lms.djangoapps.courseware.model_data import FieldDataCache from lms.djangoapps.courseware.module_render import get_module_for_descriptor from lms.djangoapps.courseware.tabs import get_course_tab_list from edxmako.shortcuts import render_to_string -from edxnotes import helpers -from edxnotes.decorators import edxnotes -from edxnotes.exceptions import EdxNotesParseError, EdxNotesServiceUnavailable -from edxnotes.plugins import EdxNotesTab +from . import helpers +from .decorators import edxnotes +from .exceptions import EdxNotesParseError, EdxNotesServiceUnavailable +from .plugins import EdxNotesTab from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user from openedx.core.djangoapps.oauth_dispatch.tests.factories import ApplicationFactory from openedx.core.djangoapps.user_api.models import RetirementState, UserRetirementStatus @@ -111,10 +111,10 @@ class EdxNotesDecoratorTest(ModuleStoreTestCase): self.problem = TestProblem(self.course, self.user) @patch.dict("django.conf.settings.FEATURES", {'ENABLE_EDXNOTES': 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) + @patch("lms.djangoapps.edxnotes.helpers.get_public_endpoint", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.get_token_url", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.get_edxnotes_id_token", autospec=True) + @patch("lms.djangoapps.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 @@ -312,7 +312,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): with patch_edxnotes_api_settings(None): self.assertRaises(ImproperlyConfigured, get_endpoint_function) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_get_notes_correct_data(self, mock_get): """ Tests the result if correct data is received. @@ -405,7 +405,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): helpers.get_notes(self.request, self.course) ) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_get_notes_json_error(self, mock_get): """ Tests the result if incorrect json is received. @@ -413,7 +413,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): mock_get.return_value.content = b"Error" self.assertRaises(EdxNotesParseError, helpers.get_notes, self.request, self.course) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_get_notes_empty_collection(self, mock_get): """ Tests the result if an empty response is received. @@ -421,7 +421,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): mock_get.return_value.content = json.dumps({}).encode('utf-8') self.assertRaises(EdxNotesParseError, helpers.get_notes, self.request, self.course) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_search_correct_data(self, mock_get): """ Tests the result if correct data is received. @@ -512,7 +512,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): helpers.get_notes(self.request, self.course) ) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_search_json_error(self, mock_get): """ Tests the result if incorrect json is received. @@ -520,7 +520,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): mock_get.return_value.content = b"Error" self.assertRaises(EdxNotesParseError, helpers.get_notes, self.request, self.course) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_search_wrong_data_format(self, mock_get): """ Tests the result if incorrect data structure is received. @@ -528,7 +528,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): mock_get.return_value.content = json.dumps({"1": 2}).encode('utf-8') self.assertRaises(EdxNotesParseError, helpers.get_notes, self.request, self.course) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_search_empty_collection(self, mock_get): """ Tests no results. @@ -542,9 +542,9 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): @override_settings(EDXNOTES_PUBLIC_API="http://example.com") @override_settings(EDXNOTES_INTERNAL_API="http://example.com") - @patch("edxnotes.helpers.anonymous_id_for_user", autospec=True) - @patch("edxnotes.helpers.get_edxnotes_id_token", autospec=True) - @patch("edxnotes.helpers.requests.post") + @patch("lms.djangoapps.edxnotes.helpers.anonymous_id_for_user", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.get_edxnotes_id_token", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.post") def test_delete_all_notes_for_user(self, mock_post, mock_get_id_token, mock_anonymous_id_for_user): """ Test GDPR data deletion for Notes user_id @@ -656,8 +656,8 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): helpers.preprocess_collection(self.user, self.course, initial_collection) ) - @patch("edxnotes.helpers.has_access", autospec=True) - @patch("edxnotes.helpers.modulestore", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.has_access", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.modulestore", autospec=True) def test_preprocess_collection_no_unit(self, mock_modulestore, mock_has_access): """ Tests the result if the unit does not exist. @@ -783,9 +783,9 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): @override_settings(EDXNOTES_PUBLIC_API="http://example.com") @override_settings(EDXNOTES_INTERNAL_API="http://example.com") - @patch("edxnotes.helpers.anonymous_id_for_user", autospec=True) - @patch("edxnotes.helpers.get_edxnotes_id_token", autospec=True) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.anonymous_id_for_user", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.get_edxnotes_id_token", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_send_request_with_text_param(self, mock_get, mock_get_id_token, mock_anonymous_id_for_user): """ Tests that requests are send with correct information. @@ -818,9 +818,9 @@ class EdxNotesHelpersTest(ModuleStoreTestCase): @override_settings(EDXNOTES_PUBLIC_API="http://example.com") @override_settings(EDXNOTES_INTERNAL_API="http://example.com") - @patch("edxnotes.helpers.anonymous_id_for_user", autospec=True) - @patch("edxnotes.helpers.get_edxnotes_id_token", autospec=True) - @patch("edxnotes.helpers.requests.get", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.anonymous_id_for_user", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.get_edxnotes_id_token", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.get", autospec=True) def test_send_request_without_text_param(self, mock_get, mock_get_id_token, mock_anonymous_id_for_user): """ Tests that requests are send with correct information. @@ -1018,7 +1018,7 @@ class EdxNotesViewsTest(ModuleStoreTestCase): # pylint: disable=unused-argument @patch.dict("django.conf.settings.FEATURES", {"ENABLE_EDXNOTES": True}) - @patch("edxnotes.views.get_notes", return_value={'results': []}) + @patch("lms.djangoapps.edxnotes.views.get_notes", return_value={'results': []}) def test_edxnotes_view_is_enabled(self, mock_get_notes): """ Tests that appropriate view is received if EdxNotes feature is enabled. @@ -1029,8 +1029,8 @@ class EdxNotesViewsTest(ModuleStoreTestCase): # pylint: disable=unused-argument @patch.dict("django.conf.settings.FEATURES", {"ENABLE_EDXNOTES": True}) - @patch("edxnotes.views.get_notes", return_value={'results': []}) - @patch("edxnotes.views.get_course_position", return_value={'display_name': 'Section 1', 'url': 'test_url'}) + @patch("lms.djangoapps.edxnotes.views.get_notes", return_value={'results': []}) + @patch("lms.djangoapps.edxnotes.views.get_course_position", return_value={'display_name': 'Section 1', 'url': 'test_url'}) def test_edxnotes_html_tags_should_not_be_escaped(self, mock_get_notes, mock_position): """ Tests that explicit html tags rendered correctly. @@ -1051,7 +1051,7 @@ class EdxNotesViewsTest(ModuleStoreTestCase): self.assertEqual(response.status_code, 404) @patch.dict("django.conf.settings.FEATURES", {"ENABLE_EDXNOTES": True}) - @patch("edxnotes.views.get_notes", autospec=True) + @patch("lms.djangoapps.edxnotes.views.get_notes", autospec=True) def test_search_notes_successfully_respond(self, mock_search): """ Tests that search notes successfully respond if EdxNotes feature is enabled. @@ -1071,7 +1071,7 @@ class EdxNotesViewsTest(ModuleStoreTestCase): self.assertEqual(response.status_code, 404) @patch.dict("django.conf.settings.FEATURES", {"ENABLE_EDXNOTES": True}) - @patch("edxnotes.views.get_notes", autospec=True) + @patch("lms.djangoapps.edxnotes.views.get_notes", autospec=True) def test_search_500_service_unavailable(self, mock_search): """ Tests that 500 status code is received if EdxNotes service is unavailable. @@ -1082,7 +1082,7 @@ class EdxNotesViewsTest(ModuleStoreTestCase): self.assertContains(response, "error", status_code=500) @patch.dict("django.conf.settings.FEATURES", {"ENABLE_EDXNOTES": True}) - @patch("edxnotes.views.get_notes", autospec=True) + @patch("lms.djangoapps.edxnotes.views.get_notes", autospec=True) def test_search_notes_exception(self, mock_search): """ Tests that 500 status code is received if invalid data was received from @@ -1199,7 +1199,7 @@ class EdxNotesRetireAPITest(ModuleStoreTestCase): headers = {'HTTP_AUTHORIZATION': 'JWT ' + token} return headers - @patch("edxnotes.helpers.requests.post", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.requests.post", autospec=True) def test_retire_user_success(self, mock_post): """ Tests that 204 response is received on success. @@ -1258,7 +1258,7 @@ class EdxNotesRetireAPITest(ModuleStoreTestCase): ) self.assertEqual(response.status_code, 405) - @patch("edxnotes.helpers.delete_all_notes_for_user", autospec=True) + @patch("lms.djangoapps.edxnotes.helpers.delete_all_notes_for_user", autospec=True) def test_retire_user_downstream_unavailable(self, mock_delete_all_notes_for_user): """ Tests that 500 response is received if the downstream (i.e. the EdxNotes IDA) is unavailable. diff --git a/lms/djangoapps/edxnotes/urls.py b/lms/djangoapps/edxnotes/urls.py index 62b05a89ac..b2b6696e2f 100644 --- a/lms/djangoapps/edxnotes/urls.py +++ b/lms/djangoapps/edxnotes/urls.py @@ -5,7 +5,7 @@ URLs for EdxNotes. from django.conf.urls import url -from edxnotes import views +from . import views # Additionally, we include login URLs for the browseable API. urlpatterns = [ diff --git a/lms/djangoapps/email_marketing/signals.py b/lms/djangoapps/email_marketing/signals.py index 5ac4ac95dd..88f14b5f48 100644 --- a/lms/djangoapps/email_marketing/signals.py +++ b/lms/djangoapps/email_marketing/signals.py @@ -16,7 +16,7 @@ from six import text_type import third_party_auth from course_modes.models import CourseMode -from email_marketing.models import EmailMarketingConfiguration +from .models import EmailMarketingConfiguration from lms.djangoapps.email_marketing.tasks import get_email_cookies_via_sailthru, update_user, update_user_email from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY from openedx.core.djangoapps.user_authn.cookies import CREATE_LOGON_COOKIE diff --git a/lms/djangoapps/email_marketing/tests/__init__.py b/lms/djangoapps/email_marketing/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lms/djangoapps/email_marketing/tests/test_signals.py b/lms/djangoapps/email_marketing/tests/test_signals.py index ac480e24b3..fd8ab711c9 100644 --- a/lms/djangoapps/email_marketing/tests/test_signals.py +++ b/lms/djangoapps/email_marketing/tests/test_signals.py @@ -20,14 +20,14 @@ from sailthru.sailthru_response import SailthruResponse import six from testfixtures import LogCapture -from email_marketing.models import EmailMarketingConfiguration -from email_marketing.signals import ( +from ..models import EmailMarketingConfiguration +from ..signals import ( add_email_marketing_cookies, email_marketing_register_user, email_marketing_user_field_changed, update_sailthru ) -from email_marketing.tasks import ( +from ..tasks import ( _create_user_list, _get_list_from_email_marketing_provider, _get_or_create_user_list, @@ -43,7 +43,7 @@ from util.json_request import JsonResponse log = logging.getLogger(__name__) -LOGGER_NAME = "email_marketing.signals" +LOGGER_NAME = "lms.djangoapps.email_marketing.signals" TEST_EMAIL = "test@edx.org" @@ -94,7 +94,7 @@ class EmailMarketingTests(TestCase): super(EmailMarketingTests, self).setUp() @freeze_time(datetime.datetime.now()) - @patch('email_marketing.signals.crum.get_current_request') + @patch('lms.djangoapps.email_marketing.signals.crum.get_current_request') @patch('sailthru.sailthru_client.SailthruClient.api_post') def test_drop_cookie(self, mock_sailthru, mock_get_current_request): """ @@ -176,9 +176,9 @@ class EmailMarketingTests(TestCase): add_email_marketing_cookies(None, response=response, user=self.user) self.assertFalse('sailthru_hid' in response.cookies) - @patch('email_marketing.tasks.log.error') - @patch('email_marketing.tasks.SailthruClient.api_post') - @patch('email_marketing.tasks.SailthruClient.api_get') + @patch('lms.djangoapps.email_marketing.tasks.log.error') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_get') def test_add_user(self, mock_sailthru_get, mock_sailthru_post, mock_log_error): """ test async method in tasks that actually updates Sailthru @@ -214,7 +214,7 @@ class EmailMarketingTests(TestCase): ) )) - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_email_not_sent_to_enterprise_learners(self, mock_sailthru_post): """ tests that welcome email is not sent to the enterprise learner @@ -229,7 +229,7 @@ class EmailMarketingTests(TestCase): ) self.assertNotEqual(mock_sailthru_post.call_args[0][0], "send") - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_add_user_list_not_called_on_white_label_domain(self, mock_sailthru_post): """ test user is not added to Sailthru user lists if registered from a whitel labe site @@ -241,8 +241,8 @@ class EmailMarketingTests(TestCase): ) self.assertFalse(mock_sailthru_post.called) - @patch('email_marketing.tasks.log.error') - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.log.error') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_update_user_error_logging(self, mock_sailthru, mock_log_error): """ Ensure that error returned from Sailthru api is logged @@ -270,9 +270,9 @@ class EmailMarketingTests(TestCase): update_user.delay({}, self.user.email, activation=True) self.assertTrue(mock_log_error.called) - @patch('email_marketing.tasks.update_user.retry') - @patch('email_marketing.tasks.log.error') - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.update_user.retry') + @patch('lms.djangoapps.email_marketing.tasks.log.error') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_update_user_error_retryable(self, mock_sailthru, mock_log_error, mock_retry): """ Ensure that retryable error is retried @@ -282,9 +282,9 @@ class EmailMarketingTests(TestCase): self.assertTrue(mock_log_error.called) self.assertTrue(mock_retry.called) - @patch('email_marketing.tasks.update_user.retry') - @patch('email_marketing.tasks.log.error') - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.update_user.retry') + @patch('lms.djangoapps.email_marketing.tasks.log.error') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_update_user_error_nonretryable(self, mock_sailthru, mock_log_error, mock_retry): """ Ensure that non-retryable error is not retried @@ -294,8 +294,8 @@ class EmailMarketingTests(TestCase): self.assertTrue(mock_log_error.called) self.assertFalse(mock_retry.called) - @patch('email_marketing.tasks.log.error') - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.log.error') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_just_return_tasks(self, mock_sailthru, mock_log_error): """ Ensure that disabling Sailthru just returns @@ -312,7 +312,7 @@ class EmailMarketingTests(TestCase): update_email_marketing_config(enabled=True) - @patch('email_marketing.signals.log.error') + @patch('lms.djangoapps.email_marketing.signals.log.error') def test_just_return_signals(self, mock_log_error): """ Ensure that disabling Sailthru just returns @@ -335,7 +335,7 @@ class EmailMarketingTests(TestCase): email_marketing_user_field_changed(None, user=anon) self.assertFalse(mock_log_error.called) - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_change_email(self, mock_sailthru): """ test async method in task that changes email in Sailthru @@ -348,7 +348,7 @@ class EmailMarketingTests(TestCase): self.assertEqual(userparms['id'], "old@edx.org") self.assertEqual(userparms['keys']['email'], TEST_EMAIL) - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_get_or_create_sailthru_list(self, mock_sailthru_client): """ Test the task the create sailthru lists. @@ -382,14 +382,14 @@ class EmailMarketingTests(TestCase): mock_sailthru_client.api_get.return_value = SailthruResponse(JsonResponse({'lists': []})) self.assertEqual(_get_or_create_user_list(mock_sailthru_client, 'test2_user_list'), None) - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_get_sailthru_list_map_no_list(self, mock_sailthru_client): """Test when no list returned from sailthru""" mock_sailthru_client.api_get.return_value = SailthruResponse(JsonResponse({'lists': []})) self.assertEqual(_get_list_from_email_marketing_provider(mock_sailthru_client), {}) mock_sailthru_client.api_get.assert_called_with("list", {}) - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_get_sailthru_list_map_error(self, mock_sailthru_client): """Test when error occurred while fetching data from sailthru""" mock_sailthru_client.api_get.return_value = SailthruResponse( @@ -397,13 +397,13 @@ class EmailMarketingTests(TestCase): ) self.assertEqual(_get_list_from_email_marketing_provider(mock_sailthru_client), {}) - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_get_sailthru_list_map_exception(self, mock_sailthru_client): """Test when exception raised while fetching data from sailthru""" mock_sailthru_client.api_get.side_effect = SailthruClientError self.assertEqual(_get_list_from_email_marketing_provider(mock_sailthru_client), {}) - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_get_sailthru_list(self, mock_sailthru_client): """Test fetch list data from sailthru""" mock_sailthru_client.api_get.return_value = \ @@ -414,7 +414,7 @@ class EmailMarketingTests(TestCase): ) mock_sailthru_client.api_get.assert_called_with("list", {}) - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_create_sailthru_list(self, mock_sailthru_client): """Test create list in sailthru""" mock_sailthru_client.api_post.return_value = SailthruResponse(JsonResponse({'ok': True})) @@ -425,7 +425,7 @@ class EmailMarketingTests(TestCase): self.assertEqual(listparms['primary'], 0) self.assertEqual(listparms['public_name'], 'test_list_name') - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_create_sailthru_list_error(self, mock_sailthru_client): """Test error occurrence while creating sailthru list""" mock_sailthru_client.api_post.return_value = SailthruResponse( @@ -433,14 +433,14 @@ class EmailMarketingTests(TestCase): ) self.assertEqual(_create_user_list(mock_sailthru_client, 'test_list_name'), False) - @patch('email_marketing.tasks.SailthruClient') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient') def test_create_sailthru_list_exception(self, mock_sailthru_client): """Test exception raised while creating sailthru list""" mock_sailthru_client.api_post.side_effect = SailthruClientError self.assertEqual(_create_user_list(mock_sailthru_client, 'test_list_name'), False) - @patch('email_marketing.tasks.log.error') - @patch('email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.tasks.log.error') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') def test_error_logging(self, mock_sailthru, mock_log_error): """ Ensure that error returned from Sailthru api is logged @@ -453,7 +453,7 @@ class EmailMarketingTests(TestCase): update_user_email.delay(self.user.username, "newemail2@test.com") self.assertTrue(mock_log_error.called) - @patch('email_marketing.signals.crum.get_current_request') + @patch('lms.djangoapps.email_marketing.signals.crum.get_current_request') @patch('lms.djangoapps.email_marketing.tasks.update_user.delay') def test_register_user(self, mock_update_user, mock_get_current_request): """ @@ -490,7 +490,7 @@ class EmailMarketingTests(TestCase): self.assertEqual(mock_update_user.call_args[0][0]['ui_lang'], 'es-419') @patch.dict(settings.FEATURES, {"ENABLE_THIRD_PARTY_AUTH": False}) - @patch('email_marketing.signals.crum.get_current_request') + @patch('lms.djangoapps.email_marketing.signals.crum.get_current_request') @patch('lms.djangoapps.email_marketing.tasks.update_user.delay') @ddt.data(('auth_userprofile', 'gender', 'f', True), ('auth_user', 'is_active', 1, True), @@ -505,10 +505,10 @@ class EmailMarketingTests(TestCase): email_marketing_user_field_changed(None, self.user, table=table, setting=setting, new_value=value) self.assertEqual(mock_update_user.called, result) - @patch('email_marketing.tasks.SailthruClient.api_post') - @patch('email_marketing.signals.third_party_auth.provider.Registry.get_from_pipeline') - @patch('email_marketing.signals.third_party_auth.pipeline.get') - @patch('email_marketing.signals.crum.get_current_request') + @patch('lms.djangoapps.email_marketing.tasks.SailthruClient.api_post') + @patch('lms.djangoapps.email_marketing.signals.third_party_auth.provider.Registry.get_from_pipeline') + @patch('lms.djangoapps.email_marketing.signals.third_party_auth.pipeline.get') + @patch('lms.djangoapps.email_marketing.signals.crum.get_current_request') @ddt.data(True, False) def test_modify_field_with_sso(self, send_welcome_email, mock_get_current_request, mock_pipeline_get, mock_registry_get_from_pipeline, mock_sailthru_post): @@ -632,7 +632,7 @@ class SailthruTests(TestCase): switch.return_value = True white_label_site = Site.objects.create(domain='testwhitelabel.com', name='White Label') site_dict = {'id': white_label_site.id, 'domain': white_label_site.domain, 'name': white_label_site.name} - with patch('email_marketing.signals._get_current_site') as mock_site_info: + with patch('lms.djangoapps.email_marketing.signals._get_current_site') as mock_site_info: mock_site_info.return_value = site_dict update_sailthru(None, self.user, 'audit', str(self.course_id)) self.assertFalse(mock_sailthru_purchase.called) diff --git a/lms/djangoapps/experiments/apps.py b/lms/djangoapps/experiments/apps.py new file mode 100644 index 0000000000..f1d2f0c691 --- /dev/null +++ b/lms/djangoapps/experiments/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig + + +class ExperimentsConfig(AppConfig): + """ + Application Configuration for experiments. + """ + name = u'lms.djangoapps.experiments' diff --git a/lms/djangoapps/experiments/tests/test_flags.py b/lms/djangoapps/experiments/tests/test_flags.py index 0fa0633113..556f92a684 100644 --- a/lms/djangoapps/experiments/tests/test_flags.py +++ b/lms/djangoapps/experiments/tests/test_flags.py @@ -40,7 +40,7 @@ class ExperimentWaffleFlagTests(SharedModuleStoreTestCase): self.flag = ExperimentWaffleFlag('experiments', 'test', __name__, num_buckets=2, experiment_id=0) self.key = CourseKey.from_string('a/b/c') - bucket_patch = patch('experiments.flags.stable_bucketing_hash_group', return_value=1) + bucket_patch = patch('lms.djangoapps.experiments.flags.stable_bucketing_hash_group', return_value=1) self.addCleanup(bucket_patch.stop) bucket_patch.start() @@ -110,7 +110,7 @@ class ExperimentWaffleFlagTests(SharedModuleStoreTestCase): def test_tracking(self): # Run twice, with same request - with patch('experiments.flags.segment') as segment_mock: + with patch('lms.djangoapps.experiments.flags.segment') as segment_mock: self.assertEqual(self.get_bucket(track=True), 1) RequestCache.clear_all_namespaces() # we want to force get_bucket to check session, not early exit self.assertEqual(self.get_bucket(track=True), 1) @@ -136,10 +136,10 @@ class ExperimentWaffleFlagTests(SharedModuleStoreTestCase): self.assertEqual(self.get_bucket(active=False), 1) # still returns 1! def test_is_enabled(self): - with patch('experiments.flags.ExperimentWaffleFlag.get_bucket', return_value=1): + with patch('lms.djangoapps.experiments.flags.ExperimentWaffleFlag.get_bucket', return_value=1): self.assertEqual(self.flag.is_enabled(self.key), True) self.assertEqual(self.flag.is_enabled(), True) - with patch('experiments.flags.ExperimentWaffleFlag.get_bucket', return_value=0): + with patch('lms.djangoapps.experiments.flags.ExperimentWaffleFlag.get_bucket', return_value=0): self.assertEqual(self.flag.is_enabled(self.key), False) self.assertEqual(self.flag.is_enabled(), False) @@ -207,7 +207,7 @@ class ExperimentWaffleFlagCourseAwarenessTest(SharedModuleStoreTestCase): # Use our custom fake `stable_bucketing_hash_group` implementation. stable_bucket_patcher = patch( - 'experiments.flags.stable_bucketing_hash_group', self._mock_stable_bucket + 'lms.djangoapps.experiments.flags.stable_bucketing_hash_group', self._mock_stable_bucket ) stable_bucket_patcher.start() self.addCleanup(stable_bucket_patcher.stop) diff --git a/lms/djangoapps/experiments/urls.py b/lms/djangoapps/experiments/urls.py index 37cad5e667..ec6af20e1a 100644 --- a/lms/djangoapps/experiments/urls.py +++ b/lms/djangoapps/experiments/urls.py @@ -5,7 +5,7 @@ Experimentation URLs from django.conf.urls import include, url -from experiments import routers, views, views_custom +from . import routers, views, views_custom router = routers.DefaultRouter() router.register(r'data', views.ExperimentDataViewSet, basename='data') diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index b2dbdef995..98a7563cf6 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -349,7 +349,7 @@ class TestEndpointHttpMethods(SharedModuleStoreTestCase, LoginEnrollmentTestCase ) -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Ensure that users cannot access endpoints they shouldn't be able to. @@ -3378,7 +3378,7 @@ class TestEntranceExamInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginE self.assertContains(response, message) -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class TestInstructorSendEmail(SiteMixin, SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Checks that only instructors have access to email endpoints, and that diff --git a/lms/djangoapps/instructor_task/tests/test_api.py b/lms/djangoapps/instructor_task/tests/test_api.py index 1e386aa20c..120844054d 100644 --- a/lms/djangoapps/instructor_task/tests/test_api.py +++ b/lms/djangoapps/instructor_task/tests/test_api.py @@ -189,7 +189,7 @@ class InstructorTaskModuleSubmitTest(InstructorTaskModuleTestCase): task_function(self.create_task_request(self.instructor), location, **params) -@patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) +@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) class InstructorTaskCourseSubmitTest(TestReportMixin, InstructorTaskCourseTestCase): """Tests API methods that involve the submission of course-based background tasks.""" diff --git a/lms/djangoapps/lti_provider/apps.py b/lms/djangoapps/lti_provider/apps.py index bb5a66f5ad..d2a01b0308 100644 --- a/lms/djangoapps/lti_provider/apps.py +++ b/lms/djangoapps/lti_provider/apps.py @@ -10,7 +10,7 @@ class LtiProviderConfig(AppConfig): """ Configuration class for the lti_provider Django application. """ - name = 'lti_provider' + name = 'lms.djangoapps.lti_provider' verbose_name = "LTI Provider" def ready(self): diff --git a/lms/djangoapps/lti_provider/tests/test_users.py b/lms/djangoapps/lti_provider/tests/test_users.py index 453ec1bd06..90401f2b28 100644 --- a/lms/djangoapps/lti_provider/tests/test_users.py +++ b/lms/djangoapps/lti_provider/tests/test_users.py @@ -12,8 +12,8 @@ from django.test.client import RequestFactory from mock import MagicMock, PropertyMock, patch from six.moves import range -import lti_provider.users as users -from lti_provider.models import LtiConsumer, LtiUser +from .. import users +from ..models import LtiConsumer, LtiUser from student.tests.factories import UserFactory @@ -45,9 +45,9 @@ class UserManagementHelperTest(TestCase): with self.assertRaises(PermissionDenied): users.switch_user(self.request, self.lti_user, self.lti_consumer) - @patch('lti_provider.users.login') + @patch('lms.djangoapps.lti_provider.users.login') def test_authenticate_called(self, _login_mock): - with patch('lti_provider.users.authenticate', return_value=self.new_user) as authenticate: + with patch('lms.djangoapps.lti_provider.users.authenticate', return_value=self.new_user) as authenticate: users.switch_user(self.request, self.lti_user, self.lti_consumer) authenticate.assert_called_with( username=self.new_user.username, @@ -55,9 +55,9 @@ class UserManagementHelperTest(TestCase): lti_consumer=self.lti_consumer ) - @patch('lti_provider.users.login') + @patch('lms.djangoapps.lti_provider.users.login') def test_login_called(self, login_mock): - with patch('lti_provider.users.authenticate', return_value=self.new_user): + with patch('lms.djangoapps.lti_provider.users.authenticate', return_value=self.new_user): users.switch_user(self.request, self.lti_user, self.lti_consumer) login_mock.assert_called_with(self.request, self.new_user) @@ -73,8 +73,8 @@ class UserManagementHelperTest(TestCase): ) -@patch('lti_provider.users.switch_user', autospec=True) -@patch('lti_provider.users.create_lti_user', autospec=True) +@patch('lms.djangoapps.lti_provider.users.switch_user', autospec=True) +@patch('lms.djangoapps.lti_provider.users.create_lti_user', autospec=True) class AuthenticateLtiUserTest(TestCase): """ Tests for the authenticate_lti_user function in users.py @@ -111,7 +111,7 @@ class AuthenticateLtiUserTest(TestCase): def test_authentication_with_new_user(self, _create_user, switch_user): lti_user = MagicMock() lti_user.edx_user_id = self.edx_user_id - with patch('lti_provider.users.create_lti_user', return_value=lti_user) as create_user: + with patch('lms.djangoapps.lti_provider.users.create_lti_user', return_value=lti_user) as create_user: users.authenticate_lti_user(self.request, self.lti_user_id, self.lti_consumer) create_user.assert_called_with(self.lti_user_id, self.lti_consumer) switch_user.assert_called_with(self.request, lti_user, self.lti_consumer) @@ -161,7 +161,7 @@ class CreateLtiUserTest(TestCase): self.assertEqual(User.objects.count(), 1) @patch('uuid.uuid4', return_value='random_uuid') - @patch('lti_provider.users.generate_random_edx_username', return_value='edx_id') + @patch('lms.djangoapps.lti_provider.users.generate_random_edx_username', return_value='edx_id') def test_create_lti_user_creates_correct_user(self, uuid_mock, _username_mock): users.create_lti_user('lti_user_id', self.lti_consumer) self.assertEqual(User.objects.count(), 1) @@ -169,7 +169,7 @@ class CreateLtiUserTest(TestCase): self.assertEqual(user.email, 'edx_id@lti.example.com') uuid_mock.assert_called_with() - @patch('lti_provider.users.generate_random_edx_username', side_effect=['edx_id', 'new_edx_id']) + @patch('lms.djangoapps.lti_provider.users.generate_random_edx_username', side_effect=['edx_id', 'new_edx_id']) def test_unique_username_created(self, username_mock): User(username='edx_id').save() users.create_lti_user('lti_user_id', self.lti_consumer) diff --git a/lms/djangoapps/lti_provider/tests/test_views.py b/lms/djangoapps/lti_provider/tests/test_views.py index 1dcece13c5..fe39e9e65a 100644 --- a/lms/djangoapps/lti_provider/tests/test_views.py +++ b/lms/djangoapps/lti_provider/tests/test_views.py @@ -71,7 +71,7 @@ class LtiTestMixin(object): super(LtiTestMixin, self).setUp() # Always accept the OAuth signature self.mock_verify = MagicMock(return_value=True) - patcher = patch('lti_provider.signature_validator.SignatureValidator.verify', self.mock_verify) + patcher = patch('lms.djangoapps.lti_provider.signature_validator.SignatureValidator.verify', self.mock_verify) patcher.start() self.addCleanup(patcher.stop) @@ -87,8 +87,8 @@ class LtiLaunchTest(LtiTestMixin, TestCase): """ Tests for the lti_launch view """ - @patch('lti_provider.views.render_courseware') - @patch('lti_provider.views.authenticate_lti_user') + @patch('lms.djangoapps.lti_provider.views.render_courseware') + @patch('lms.djangoapps.lti_provider.views.authenticate_lti_user') def test_valid_launch(self, _authenticate, render): """ Verifies that the LTI launch succeeds when passed a valid request. @@ -97,9 +97,9 @@ class LtiLaunchTest(LtiTestMixin, TestCase): views.lti_launch(request, six.text_type(COURSE_KEY), six.text_type(USAGE_KEY)) render.assert_called_with(request, USAGE_KEY) - @patch('lti_provider.views.render_courseware') - @patch('lti_provider.views.store_outcome_parameters') - @patch('lti_provider.views.authenticate_lti_user') + @patch('lms.djangoapps.lti_provider.views.render_courseware') + @patch('lms.djangoapps.lti_provider.views.store_outcome_parameters') + @patch('lms.djangoapps.lti_provider.views.authenticate_lti_user') def test_valid_launch_with_optional_params(self, _authenticate, store_params, _render): """ Verifies that the LTI launch succeeds when passed a valid request. @@ -112,9 +112,9 @@ class LtiLaunchTest(LtiTestMixin, TestCase): self.consumer ) - @patch('lti_provider.views.render_courseware') - @patch('lti_provider.views.store_outcome_parameters') - @patch('lti_provider.views.authenticate_lti_user') + @patch('lms.djangoapps.lti_provider.views.render_courseware') + @patch('lms.djangoapps.lti_provider.views.store_outcome_parameters') + @patch('lms.djangoapps.lti_provider.views.authenticate_lti_user') def test_outcome_service_registered(self, _authenticate, store_params, _render): """ Verifies that the LTI launch succeeds when passed a valid request. @@ -168,7 +168,7 @@ class LtiLaunchTest(LtiTestMixin, TestCase): self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403) - @patch('lti_provider.views.render_courseware') + @patch('lms.djangoapps.lti_provider.views.render_courseware') def test_lti_consumer_record_supplemented_with_guid(self, _render): self.mock_verify.return_value = False diff --git a/lms/djangoapps/rss_proxy/urls.py b/lms/djangoapps/rss_proxy/urls.py index 0e397c0f1c..c8b2432a94 100644 --- a/lms/djangoapps/rss_proxy/urls.py +++ b/lms/djangoapps/rss_proxy/urls.py @@ -5,7 +5,7 @@ URLs for the rss_proxy djangoapp. from django.conf.urls import url -from rss_proxy.views import proxy +from .views import proxy app_name = 'rss_proxy' urlpatterns = [ diff --git a/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource2.py b/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource2.py index 62606efaba..de691f96ec 100644 --- a/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource2.py +++ b/lms/djangoapps/shoppingcart/processors/tests/test_CyberSource2.py @@ -9,15 +9,15 @@ from django.conf import settings from django.test import TestCase from mock import patch -from shoppingcart.models import Order, OrderItem -from shoppingcart.processors.CyberSource2 import ( +from ...models import Order, OrderItem +from ..CyberSource2 import ( _get_processor_exception_html, get_signed_purchase_params, process_postpay_callback, processor_hash, render_purchase_form_html ) -from shoppingcart.processors.exceptions import ( +from ..exceptions import ( CCProcessorDataException, CCProcessorSignatureException, CCProcessorWrongAmountException diff --git a/lms/djangoapps/shoppingcart/tests/test_models.py b/lms/djangoapps/shoppingcart/tests/test_models.py index 09c00c1a3f..6de8006bac 100644 --- a/lms/djangoapps/shoppingcart/tests/test_models.py +++ b/lms/djangoapps/shoppingcart/tests/test_models.py @@ -84,7 +84,7 @@ class OrderTest(ModuleStoreTestCase): self.cost = 40 # Add mock tracker for event testing. - patcher = patch('shoppingcart.models.segment') + patcher = patch('lms.djangoapps.shoppingcart.models.segment') self.mock_tracker = patcher.start() self.addCleanup(patcher.stop) @@ -299,7 +299,7 @@ class OrderTest(ModuleStoreTestCase): # CertificateItem cart = Order.get_cart_for_user(user=self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') - with patch('shoppingcart.models.CertificateItem.save', side_effect=DatabaseError): + with patch('lms.djangoapps.shoppingcart.models.CertificateItem.save', side_effect=DatabaseError): with self.assertRaises(DatabaseError): cart.purchase() # verify that we rolled back the entire transaction @@ -315,15 +315,15 @@ class OrderTest(ModuleStoreTestCase): cart.purchase() self.assertEqual(len(mail.outbox), 1) - @patch('shoppingcart.models.log.error') + @patch('lms.djangoapps.shoppingcart.models.log.error') def test_purchase_item_email_smtp_failure(self, error_logger): cart = Order.get_cart_for_user(user=self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') - with patch('shoppingcart.models.EmailMessage.send', side_effect=smtplib.SMTPException): + with patch('lms.djangoapps.shoppingcart.models.EmailMessage.send', side_effect=smtplib.SMTPException): cart.purchase() self.assertTrue(error_logger.called) - @patch('shoppingcart.models.log.error') + @patch('lms.djangoapps.shoppingcart.models.log.error') def test_purchase_item_email_boto_failure(self, error_logger): cart = Order.get_cart_for_user(user=self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') @@ -348,7 +348,7 @@ class OrderTest(ModuleStoreTestCase): cardtype='001', ) - @patch('shoppingcart.models.render_to_string') + @patch('lms.djangoapps.shoppingcart.models.render_to_string') @patch.dict(settings.FEATURES, {'STORE_BILLING_INFO': True}) def test_billing_info_storage_on(self, render): cart = Order.get_cart_for_user(self.user) @@ -366,7 +366,7 @@ class OrderTest(ModuleStoreTestCase): ((_, context), _) = render.call_args self.assertTrue(context['has_billing_info']) - @patch('shoppingcart.models.render_to_string') + @patch('lms.djangoapps.shoppingcart.models.render_to_string') @patch.dict(settings.FEATURES, {'STORE_BILLING_INFO': False}) def test_billing_info_storage_off(self, render): cart = Order.get_cart_for_user(self.user) @@ -517,7 +517,7 @@ class CertificateItemTest(ModuleStoreTestCase): self.mock_tracker = patcher.start() self.addCleanup(patcher.stop) - analytics_patcher = patch('shoppingcart.models.segment') + analytics_patcher = patch('lms.djangoapps.shoppingcart.models.segment') self.mock_analytics_tracker = analytics_patcher.start() self.addCleanup(analytics_patcher.stop) @@ -657,7 +657,7 @@ class CertificateItemTest(ModuleStoreTestCase): mail.outbox = [] cutoff_date.return_value = datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=1) - with patch('shoppingcart.models.log.error') as mock_error_logger: + with patch('lms.djangoapps.shoppingcart.models.log.error') as mock_error_logger: CourseEnrollment.unenroll(self.user, course_key) self.assertFalse(mock_error_logger.called) self.assertEqual(len(mail.outbox), 1) @@ -666,7 +666,7 @@ class CertificateItemTest(ModuleStoreTestCase): self.assertIn('has requested a refund on Order', mail.outbox[0].body) @patch('student.models.CourseEnrollment.refund_cutoff_date') - @patch('shoppingcart.models.log.error') + @patch('lms.djangoapps.shoppingcart.models.log.error') def test_refund_cert_callback_before_expiration_email_error(self, error_logger, cutoff_date): # If there's an error sending an email to billing, we need to log this error many_days = datetime.timedelta(days=60) @@ -687,7 +687,7 @@ class CertificateItemTest(ModuleStoreTestCase): cart.purchase() cutoff_date.return_value = datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=1) - with patch('shoppingcart.models.send_mail', side_effect=smtplib.SMTPException): + with patch('lms.djangoapps.shoppingcart.models.send_mail', side_effect=smtplib.SMTPException): CourseEnrollment.unenroll(self.user, course_key) self.assertTrue(error_logger.call_args[0][0].startswith('Failed sending email')) diff --git a/lms/djangoapps/shoppingcart/tests/test_views.py b/lms/djangoapps/shoppingcart/tests/test_views.py index 79405d50a8..f4868d30ba 100644 --- a/lms/djangoapps/shoppingcart/tests/test_views.py +++ b/lms/djangoapps/shoppingcart/tests/test_views.py @@ -34,8 +34,8 @@ from course_modes.tests.factories import CourseModeFactory from lms.djangoapps.courseware.tests.factories import InstructorFactory from edxmako.shortcuts import render_to_response from openedx.core.djangoapps.embargo.test_utils import restrict_course -from shoppingcart.admin import SoftDeleteCouponAdmin -from shoppingcart.models import ( +from ..admin import SoftDeleteCouponAdmin +from ..models import ( CertificateItem, Coupon, CouponRedemption, @@ -46,10 +46,10 @@ from shoppingcart.models import ( PaidCourseRegistration, RegistrationCodeRedemption ) -from shoppingcart.processors import render_purchase_form_html -from shoppingcart.processors.CyberSource2 import sign -from shoppingcart.tests.payment_fake import PaymentFakeView -from shoppingcart.views import _can_download_report, _get_date_from_str, initialize_report +from ..processors import render_purchase_form_html +from ..processors.CyberSource2 import sign +from ..tests.payment_fake import PaymentFakeView +from ..views import _can_download_report, _get_date_from_str, initialize_report from student.models import CourseEnrollment from student.roles import CourseSalesAdminRole from student.tests.factories import AdminFactory, UserFactory @@ -204,7 +204,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): resp = self.client.post(reverse('add_course_to_cart', args=[text_type(self.course_key)])) self.assertEqual(resp.status_code, 403) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_billing_details(self): billing_url = reverse('billing_details') self.login_user() @@ -235,7 +235,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): resp = self.client.post(billing_url, data) self.assertEqual(resp.status_code, 200) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) @override_settings(PAID_COURSE_REGISTRATION_CURRENCY=['PKR', 'Rs']) def test_billing_details_with_override_currency_settings(self): billing_url = reverse('billing_details') @@ -668,7 +668,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): current_enrollment, __ = CourseEnrollment.enrollment_mode_for_user(self.user, self.course_key) self.assertEqual('verified', current_enrollment) - @patch('shoppingcart.views.log.debug') + @patch('lms.djangoapps.shoppingcart.views.log.debug') def test_non_existing_coupon_redemption_on_removing_item(self, debug_log): reg_item = self.add_course_to_user_cart(self.course_key) @@ -682,7 +682,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(resp.status_code, 200) self.assertEqual(self.cart.orderitem_set.count(), 0) - @patch('shoppingcart.views.log.info') + @patch('lms.djangoapps.shoppingcart.views.log.info') def test_existing_coupon_redemption_on_removing_item(self, info_log): self.add_coupon(self.course_key, True, self.coupon_code) @@ -703,7 +703,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): str(reg_item.id) ) - @patch('shoppingcart.views.log.info') + @patch('lms.djangoapps.shoppingcart.views.log.info') def test_reset_redemption_for_coupon(self, info_log): self.add_coupon(self.course_key, True, self.coupon_code) @@ -721,7 +721,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): reg_item.id ) - @patch('shoppingcart.views.log.info') + @patch('lms.djangoapps.shoppingcart.views.log.info') def test_coupon_discount_for_multiple_courses_in_cart(self, info_log): reg_item = self.add_course_to_user_cart(self.course_key) @@ -756,7 +756,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): str(reg_item.id) ) - @patch('shoppingcart.views.log.info') + @patch('lms.djangoapps.shoppingcart.views.log.info') def test_delete_certificate_item(self, info_log): self.add_course_to_user_cart(self.course_key) @@ -772,7 +772,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(self.cart.orderitem_set.count(), 1) info_log.assert_called_with(u"order item %s removed for user %s", str(cert_item.id), self.user) - @patch('shoppingcart.views.log.info') + @patch('lms.djangoapps.shoppingcart.views.log.info') def test_remove_coupon_redemption_on_clear_cart(self, info_log): reg_item = self.add_course_to_user_cart(self.course_key) @@ -815,8 +815,8 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(resp.status_code, 200) self.assertTrue(PaidCourseRegistration.contained_in_order(self.cart, self.course_key)) - @patch('shoppingcart.views.render_purchase_form_html', form_mock) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_purchase_form_html', form_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_cart(self): self.login_user() reg_item = PaidCourseRegistration.add_to_order( @@ -848,8 +848,8 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(context['currency'], 'usd') self.assertEqual(context['currency_symbol'], '$') - @patch('shoppingcart.views.render_purchase_form_html', form_mock) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_purchase_form_html', form_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) @override_settings(PAID_COURSE_REGISTRATION_CURRENCY=['PKR', 'Rs']) def test_show_cart_with_override_currency_settings(self): self.login_user() @@ -876,7 +876,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(resp.status_code, 200) self.assertEqual(self.cart.orderitem_set.count(), 0) - @patch('shoppingcart.views.log.exception') + @patch('lms.djangoapps.shoppingcart.views.log.exception') def test_remove_item(self, exception_log): self.login_user() reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key) @@ -906,7 +906,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): '-1' ) - @patch('shoppingcart.views.process_postpay_callback', postpay_mock) + @patch('lms.djangoapps.shoppingcart.views.process_postpay_callback', postpay_mock) def test_postpay_callback_success(self): postpay_mock.return_value = {'success': True, 'order': self.cart} self.login_user() @@ -915,8 +915,8 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(urlparse(resp.__getitem__('location')).path, reverse('shoppingcart.views.show_receipt', args=[self.cart.id])) - @patch('shoppingcart.views.process_postpay_callback', postpay_mock) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.process_postpay_callback', postpay_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_postpay_callback_failure(self): postpay_mock.return_value = {'success': False, 'order': self.cart, 'error_html': 'ERROR_TEST!!!'} self.login_user() @@ -977,7 +977,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): resp = self.client.get(url) self.assert_no_xss(resp, '') - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_reg_code_xss(self): self.add_reg_code(self.xss_course_key) @@ -1099,7 +1099,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(self.course_key) self.assertEqual(total_amount, 76) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_with_valid_coupon_code(self): self.add_course_to_user_cart(self.course_key) self.add_coupon(self.course_key, True, self.coupon_code) @@ -1112,7 +1112,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertContains(resp, 'FirstNameTesting123') self.assertContains(resp, str(self.get_discount(self.cost))) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_reg_code_and_course_registration_scenario(self): self.add_reg_code(self.course_key) @@ -1133,7 +1133,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): response = self.client.post(redeem_url) self.assertEqual(response.status_code, 200) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_reg_code_with_multiple_courses_and_checkout_scenario(self): self.add_reg_code(self.course_key) @@ -1182,7 +1182,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertIsNotNone(item2.course_enrollment) self.assertEqual(item2.course_enrollment.course_id, self.testing_course.id) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_with_valid_reg_code(self): self.add_course_to_user_cart(self.course_key) self.add_reg_code(self.course_key) @@ -1194,7 +1194,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): resp = self.client.get(reverse('shoppingcart.views.show_receipt', args=[self.cart.id])) self.assertContains(resp, '0.00') - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success(self): reg_item = PaidCourseRegistration.add_to_order( self.cart, @@ -1220,7 +1220,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(context['currency'], 'usd') @override_settings(PAID_COURSE_REGISTRATION_CURRENCY=['PKR', 'Rs']) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_with_override_currency_settings(self): reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key) cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor') @@ -1239,7 +1239,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertEqual(context['currency_symbol'], 'Rs') self.assertEqual(context['currency'], 'PKR') - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_with_upgrade(self): reg_item = PaidCourseRegistration.add_to_order( @@ -1268,7 +1268,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertIn(cert_item, context['shoppingcart_items'][1]) self.assertFalse(context['any_refunds']) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_refund(self): reg_item = PaidCourseRegistration.add_to_order( self.cart, @@ -1291,7 +1291,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin): self.assertIn(cert_item, context['shoppingcart_items'][1]) self.assertTrue(context['any_refunds']) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_custom_receipt_page(self): cert_item = CertificateItem.add_to_order(self.cart, self.course_key, self.cost, 'honor') self.cart.purchase() @@ -1432,7 +1432,7 @@ class ReceiptRedirectTest(SharedModuleStoreTestCase): self.cart.start_purchase() # Simulate hitting the post-pay callback - with patch('shoppingcart.views.process_postpay_callback') as mock_process: + with patch('lms.djangoapps.shoppingcart.views.process_postpay_callback') as mock_process: mock_process.return_value = {'success': True, 'order': self.cart} url = reverse('shoppingcart.views.postpay_callback') resp = self.client.post(url, follow=True) @@ -1510,7 +1510,7 @@ class ShoppingcartViewsClosedEnrollment(ModuleStoreTestCase): """ self.client.login(username=self.user.username, password="password") - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_to_check_that_cart_item_enrollment_is_closed(self): self.login_user() reg_item1 = PaidCourseRegistration.add_to_order(self.cart, self.course_key) @@ -1911,7 +1911,7 @@ class CSVReportViewsTest(SharedModuleStoreTestCase): response = self.client.put(reverse('payment_csv_report')) self.assertEqual(response.status_code, 400) - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_report_csv_get(self): self.login_user() self.add_to_download_group(self.user) @@ -1923,7 +1923,7 @@ class CSVReportViewsTest(SharedModuleStoreTestCase): self.assertFalse(context['date_fmt_error']) self.assertContains(response, "Download CSV Reports") - @patch('shoppingcart.views.render_to_response', render_mock) + @patch('lms.djangoapps.shoppingcart.views.render_to_response', render_mock) def test_report_csv_bad_date(self): self.login_user() self.add_to_download_group(self.user) diff --git a/lms/djangoapps/shoppingcart/urls.py b/lms/djangoapps/shoppingcart/urls.py index 55cfa48c30..b165a74df6 100644 --- a/lms/djangoapps/shoppingcart/urls.py +++ b/lms/djangoapps/shoppingcart/urls.py @@ -6,7 +6,7 @@ Defines the shoppingcart URLs from django.conf import settings from django.conf.urls import url -from shoppingcart import views +from . import views urlpatterns = [ # Both the ~accept and ~reject callback pages are handled here diff --git a/lms/djangoapps/support/tests/test_views.py b/lms/djangoapps/support/tests/test_views.py index ffc96a946c..bdd9bd64d9 100644 --- a/lms/djangoapps/support/tests/test_views.py +++ b/lms/djangoapps/support/tests/test_views.py @@ -430,7 +430,7 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase kwargs={'username_or_email': getattr(self.student, search_string_type)} ) - with patch('support.views.enrollments.get_credit_provider_attribute_values') as mock_method: + with patch('lms.djangoapps.support.views.enrollments.get_credit_provider_attribute_values') as mock_method: credit_provider = ( [u'Arizona State University'], 'You are now eligible for credit from Arizona State University' ) @@ -469,7 +469,7 @@ class SupportViewLinkProgramEnrollmentsTests(SupportViewTestCase): Tests for the link_program_enrollments support view. """ patch_render = patch( - 'support.views.program_enrollments.render_to_response', + 'lms.djangoapps.support.views.program_enrollments.render_to_response', return_value=HttpResponse(), autospec=True, ) @@ -537,7 +537,7 @@ class SupportViewLinkProgramEnrollmentsTests(SupportViewTestCase): '0001,learner-01,apple,orange\n0002,learner-02,purple', # extra fields '\t0001 , \t learner-01 \n 0002 , learner-02 ', # whitespace ) - @patch('support.views.program_enrollments.link_program_enrollments') + @patch('lms.djangoapps.support.views.program_enrollments.link_program_enrollments') def test_text(self, text, mocked_link): self.client.post(self.url, data={ 'program_uuid': self.program_uuid, @@ -638,7 +638,7 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase): View tests for Program Enrollments Inspector """ patch_render = patch( - 'support.views.program_enrollments.render_to_response', + 'lms.djangoapps.support.views.program_enrollments.render_to_response', return_value=HttpResponse(), autospec=True, ) diff --git a/lms/djangoapps/support/urls.py b/lms/djangoapps/support/urls.py index 5989aef98d..06554f4c01 100644 --- a/lms/djangoapps/support/urls.py +++ b/lms/djangoapps/support/urls.py @@ -5,15 +5,15 @@ URLs for the student support app. from django.conf.urls import url -from lms.djangoapps.support.views.contact_us import ContactUsView -from support.views.certificate import CertificatesSupportView -from support.views.course_entitlements import EntitlementSupportView -from support.views.enrollments import EnrollmentSupportListView, EnrollmentSupportView -from support.views.feature_based_enrollments import FeatureBasedEnrollmentsSupportView -from support.views.index import index -from support.views.manage_user import ManageUserDetailView, ManageUserSupportView -from support.views.program_enrollments import LinkProgramEnrollmentSupportView, ProgramEnrollmentsInspectorView -from support.views.sso_records import SsoView +from .views.contact_us import ContactUsView +from .views.certificate import CertificatesSupportView +from .views.course_entitlements import EntitlementSupportView +from .views.enrollments import EnrollmentSupportListView, EnrollmentSupportView +from .views.feature_based_enrollments import FeatureBasedEnrollmentsSupportView +from .views.index import index +from .views.manage_user import ManageUserDetailView, ManageUserSupportView +from .views.program_enrollments import LinkProgramEnrollmentSupportView, ProgramEnrollmentsInspectorView +from .views.sso_records import SsoView COURSE_ENTITLEMENTS_VIEW = EntitlementSupportView.as_view() diff --git a/lms/djangoapps/verify_student/tests/test_fake_software_secure.py b/lms/djangoapps/verify_student/tests/test_fake_software_secure.py index 01836bf320..ced1428482 100644 --- a/lms/djangoapps/verify_student/tests/test_fake_software_secure.py +++ b/lms/djangoapps/verify_student/tests/test_fake_software_secure.py @@ -16,7 +16,7 @@ class SoftwareSecureFakeViewTest(UrlResetMixin, TestCase): Base class to test the fake software secure view. """ - URLCONF_MODULES = ['verify_student.urls'] + URLCONF_MODULES = ['lms.djangoapps.verify_student.urls'] def setUp(self, **kwargs): enable_software_secure_fake = kwargs.get('enable_software_secure_fake', False) diff --git a/lms/envs/bok_choy.py b/lms/envs/bok_choy.py index 73ad1df276..cab4720a5f 100644 --- a/lms/envs/bok_choy.py +++ b/lms/envs/bok_choy.py @@ -21,6 +21,7 @@ from django.utils.translation import ugettext_lazy from path import Path as path from openedx.core.release import RELEASE_LINE +from xmodule.modulestore.modulestore_settings import update_module_store_settings CONFIG_ROOT = path(__file__).abspath().dirname() TEST_ROOT = CONFIG_ROOT.dirname().dirname() / "test_root" diff --git a/lms/envs/common.py b/lms/envs/common.py index 0aa55aafeb..6f6981ae6d 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -52,8 +52,6 @@ from openedx.core.djangoapps.theming.helpers_dirs import ( ) from openedx.core.lib.derived import derived, derived_collection_entry from openedx.core.release import doc_version -from xmodule.modulestore.modulestore_settings import update_module_store_settings -from xmodule.modulestore.edit_info import EditInfoMixin from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin ################################### FEATURES ################################### @@ -724,7 +722,7 @@ DATA_DIR = COURSES_ROOT # TODO: Remove the rest of the sys.path modification here and in cms/envs/common.py sys.path.append(REPO_ROOT) -sys.path.append(PROJECT_ROOT / 'djangoapps') +sys.path.append(REPO_ROOT / 'sys_path_hacks' / 'lms') sys.path.append(COMMON_ROOT / 'djangoapps') # For Node.js @@ -1169,9 +1167,12 @@ COURSE_LISTINGS = {} ############# XBlock Configuration ########## # Import after sys.path fixup +# pylint: disable=wrong-import-position +from xmodule.modulestore.edit_info import EditInfoMixin from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.modulestore import prefer_xmodules from xmodule.x_module import XModuleMixin +# pylint: enable=wrong-import-position # These are the Mixins that should be added to every XBlock. # This should be moved into an XBlock Runtime/Application object @@ -2483,26 +2484,26 @@ INSTALLED_APPS = [ # Our courseware 'lms.djangoapps.courseware', - 'coursewarehistoryextended', + 'lms.djangoapps.coursewarehistoryextended', 'student.apps.StudentConfig', - 'static_template_view', - 'staticbook', + 'lms.djangoapps.static_template_view', + 'lms.djangoapps.staticbook', 'track', 'eventtracking.django.apps.EventTrackingConfig', 'util', 'lms.djangoapps.certificates.apps.CertificatesConfig', - 'dashboard', + 'lms.djangoapps.dashboard', 'lms.djangoapps.instructor_task', 'openedx.core.djangoapps.course_groups', - 'bulk_email', - 'branding', + 'lms.djangoapps.bulk_email', + 'lms.djangoapps.branding', # New (Blockstore-based) XBlock runtime 'openedx.core.djangoapps.xblock.apps.LmsXBlockAppConfig', # Student support tools - 'support', + 'lms.djangoapps.support', # django-oauth-toolkit 'oauth2_provider', @@ -2518,7 +2519,7 @@ INSTALLED_APPS = [ # For the wiki 'wiki', # The new django-wiki from benjaoming 'django_notify', - 'course_wiki', # Our customizations + 'lms.djangoapps.course_wiki', # Our customizations 'mptt', 'sekizai', #'wiki.plugins.attachments', @@ -2527,18 +2528,18 @@ INSTALLED_APPS = [ # got tangled up during the Django 1.8 migration, so we are disabling it. # See TNL-3783 for details. #'wiki.plugins.notifications', - 'course_wiki.plugins.markdownedx', + 'lms.djangoapps.course_wiki.plugins.markdownedx', # For testing 'django.contrib.admin', # only used in DEBUG mode - 'debug', + 'lms.djangoapps.debug', 'openedx.core.djangoapps.util.apps.UtilConfig', # Discussion forums 'openedx.core.djangoapps.django_comment_common', # Notes - 'edxnotes', + 'lms.djangoapps.edxnotes', # Splash screen 'splash', @@ -2549,7 +2550,7 @@ INSTALLED_APPS = [ 'openedx.core.djangoapps.user_api', # Shopping cart - 'shoppingcart', + 'lms.djangoapps.shoppingcart', # Different Course Modes 'course_modes.apps.CourseModesConfig', @@ -2561,7 +2562,7 @@ INSTALLED_APPS = [ 'entitlements.apps.EntitlementsConfig', # Bulk Enrollment API - 'bulk_enroll', + 'lms.djangoapps.bulk_enroll', # Student Identity Verification 'lms.djangoapps.verify_student.apps.VerifyStudentConfig', @@ -2570,7 +2571,7 @@ INSTALLED_APPS = [ 'openedx.core.djangoapps.dark_lang', # RSS Proxy - 'rss_proxy', + 'lms.djangoapps.rss_proxy', # Country embargo support 'openedx.core.djangoapps.embargo', @@ -2649,7 +2650,7 @@ INSTALLED_APPS = [ 'learner_dashboard', # Needed whether or not enabled, due to migrations - 'badges.apps.BadgesConfig', + 'lms.djangoapps.badges.apps.BadgesConfig', # Enables default site and redirects 'django_sites_extensions', @@ -2690,7 +2691,7 @@ INSTALLED_APPS = [ 'openedx.features.content_type_gating', 'openedx.features.discounts', - 'experiments', + 'lms.djangoapps.experiments', # DRF filters 'django_filters', diff --git a/lms/envs/production.py b/lms/envs/production.py index fa53d7cd98..b238a3f2fb 100644 --- a/lms/envs/production.py +++ b/lms/envs/production.py @@ -771,8 +771,8 @@ CREDIT_PROVIDER_SECRET_KEYS = AUTH_TOKENS.get("CREDIT_PROVIDER_SECRET_KEYS", {}) ##################### LTI Provider ##################### if FEATURES.get('ENABLE_LTI_PROVIDER'): - INSTALLED_APPS.append('lti_provider.apps.LtiProviderConfig') - AUTHENTICATION_BACKENDS.append('lti_provider.users.LtiBackend') + INSTALLED_APPS.append('lms.djangoapps.lti_provider.apps.LtiProviderConfig') + AUTHENTICATION_BACKENDS.append('lms.djangoapps.lti_provider.users.LtiBackend') LTI_USER_EMAIL_DOMAIN = ENV_TOKENS.get('LTI_USER_EMAIL_DOMAIN', 'lti.example.com') diff --git a/lms/envs/test.py b/lms/envs/test.py index 88d41c03b9..ca267fd4e3 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -30,6 +30,7 @@ from six.moves import range from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType from openedx.core.lib.derived import derive_settings from openedx.core.lib.tempdir import mkdtemp_clean +from xmodule.modulestore.modulestore_settings import update_module_store_settings from .common import * diff --git a/lms/urls.py b/lms/urls.py index 93a00d1be3..462e7070cf 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -13,8 +13,8 @@ from edx_api_doc_tools import make_docs_urls from edx_django_utils.plugins import get_plugin_url_patterns from ratelimitbackend import admin -from branding import views as branding_views -from debug import views as debug_views +from lms.djangoapps.branding import views as branding_views +from lms.djangoapps.debug import views as debug_views from lms.djangoapps.certificates import views as certificates_views from lms.djangoapps.courseware.masquerade import MasqueradeView from lms.djangoapps.courseware.module_render import ( @@ -31,6 +31,8 @@ from lms.djangoapps.discussion.config.settings import is_forum_daily_digest_enab from lms.djangoapps.discussion.notification_prefs import views as notification_prefs_views from lms.djangoapps.instructor.views import instructor_dashboard as instructor_dashboard_views from lms.djangoapps.instructor_task import views as instructor_task_views +from lms.djangoapps.staticbook import views as staticbook_views +from lms.djangoapps.static_template_view import views as static_template_view_views from openedx.core.apidocs import api_info from openedx.core.djangoapps.auth_exchange.views import LoginWithAccessTokenView from openedx.core.djangoapps.catalog.models import CatalogIntegration @@ -49,8 +51,6 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_ from openedx.core.djangoapps.user_authn.views.login import redirect_to_lms_login from openedx.core.djangoapps.verified_track_content import views as verified_track_content_views from openedx.features.enterprise_support.api import enterprise_enabled -from static_template_view import views as static_template_view_views -from staticbook import views as staticbook_views from student import views as student_views from util import views as util_views @@ -159,7 +159,7 @@ urlpatterns = [ url(r'^api/course_modes/', include(('course_modes.rest_api.urls', 'common.djangoapps.course_mods'), namespace='course_modes_api')), - url(r'^verify_student/', include('verify_student.urls')), + url(r'^verify_student/', include('lms.djangoapps.verify_student.urls')), # URLs for managing dark launches of languages url(r'^update_lang/', include(('openedx.core.djangoapps.dark_lang.urls', 'openedx.core.djangoapps.dark_lang'), @@ -212,7 +212,7 @@ urlpatterns += [ # the custom tab catch-all) if settings.WIKI_ENABLED: from wiki.urls import get_pattern as wiki_pattern - from course_wiki import views as course_wiki_views + from lms.djangoapps.course_wiki import views as course_wiki_views from django_notify.urls import get_pattern as notify_pattern wiki_url_patterns, wiki_app_name = wiki_pattern() @@ -854,7 +854,7 @@ if settings.FEATURES.get('ENABLE_OAUTH2_PROVIDER'): # Certificates urlpatterns += [ - url(r'^certificates/', include('certificates.urls')), + url(r'^certificates/', include('lms.djangoapps.certificates.urls')), # Backwards compatibility with XQueue, which uses URLs that are not prefixed with /certificates/ url(r'^update_certificate$', certificates_views.update_certificate, name='update_certificate'), @@ -885,7 +885,7 @@ if settings.FEATURES.get('CUSTOM_COURSES_EDX'): # Access to courseware as an LTI provider if settings.FEATURES.get('ENABLE_LTI_PROVIDER'): urlpatterns += [ - url(r'^lti_provider/', include('lti_provider.urls')), + url(r'^lti_provider/', include('lms.djangoapps.lti_provider.urls')), ] urlpatterns += [ diff --git a/openedx/tests/settings.py b/openedx/tests/settings.py index 73ba9f1d71..133bb57178 100644 --- a/openedx/tests/settings.py +++ b/openedx/tests/settings.py @@ -13,7 +13,7 @@ from path import Path # TODO: Remove the rest of the sys.path modification here and in (cms|lms)/envs/common.py REPO_ROOT = Path(__file__).abspath().dirname().dirname().dirname() # /edx-platform/ sys.path.append(REPO_ROOT / 'common' / 'djangoapps') -sys.path.append(REPO_ROOT / 'lms' / 'djangoapps') +sys.path.append(REPO_ROOT / 'sys_path_hacks' / 'lms') ALL_LANGUAGES = [] @@ -90,7 +90,7 @@ INSTALLED_APPS = ( 'openedx.core.djangoapps.external_user_ids', 'openedx.core.djangoapps.demographics', - 'experiments', + 'lms.djangoapps.experiments', 'openedx.features.content_type_gating', 'openedx.features.course_duration_limits', 'openedx.features.discounts', diff --git a/sys_path_hacks/lms/courseware/management/commands/import.py b/sys_path_hacks/lms/courseware/management/commands/import.py deleted file mode 100644 index eda4034311..0000000000 --- a/sys_path_hacks/lms/courseware/management/commands/import.py +++ /dev/null @@ -1,4 +0,0 @@ -import warnings -warnings.warn("Importing courseware.management.commands.import instead of lms.djangoapps.courseware.management.commands.import is deprecated", stacklevel=2) - -from lms.djangoapps.courseware.management.commands.import import *