From 2d82d9027970178ca5e52d2f080ccfcbc5b6e536 Mon Sep 17 00:00:00 2001 From: Akanshu Aich Date: Tue, 20 Jan 2026 22:25:26 +0530 Subject: [PATCH] refactor: migrated FEATURES dict settings to top-level in core files and fixed related test files. (#37389) * refactor: moved remaining feature dicts settings into top-level settings. * refactor: moved remaining feature dicts settings into top-level settings. * fix: fixed the test files * fix: fixed tehe pylint errors * fix: fixation of the cms ci failure * fix: fixed remaining feature settings for cms * fix: added fix for requirements * fix: added fix for lms tests * fix: resolved the test views issue * fix: configured views file and test_views * fix: fixed lint errors and assertion issues * fix: added fix for base url issue in test view * fix: added fix for base_url and assertion issue * fix: added configurations for base utl fix * fix: handled none issue for mfe config * fix: corrected override settings in test views * fix: added getattr defensive technique for view settings * fix: reverted views and test_views file * fix: added settings in views file * fix: added with patch within functions in test view * fix: rearranged the features in default_legacy_config * fix: fixing the tests with clearing cache * fix: reverted test views to verify the CI check * fix: added cache clear in mfe config test * fix: fixed the patch toggles to override settings * fix: fixed the lint errors * fix: changed patch toggle to override settings --- .../tests/test_course_settings.py | 21 ++++++++++--------- .../contentstore/tests/test_utils.py | 4 ++-- cms/djangoapps/contentstore/toggles.py | 18 ++++++++-------- .../views/tests/test_entrance_exam.py | 6 +++--- .../contentstore/views/tests/test_library.py | 2 +- common/djangoapps/util/milestones_helpers.py | 8 +++---- .../util/tests/test_milestones_helpers.py | 11 +++++----- .../courseware/tests/test_access.py | 3 ++- .../courseware/tests/test_entrance_exam.py | 5 +++-- lms/djangoapps/courseware/tests/test_tabs.py | 5 +++-- lms/djangoapps/instructor/tests/test_api.py | 6 +++--- .../mfe_config_api/tests/test_views.py | 2 ++ .../mobile_api/tests/test_milestones.py | 10 ++++++--- lms/djangoapps/teams/tests/test_views.py | 5 +++-- lms/djangoapps/teams/toggles.py | 10 ++++----- .../core/djangoapps/credentials/helpers.py | 10 ++++----- .../credentials/tests/test_tasks.py | 2 +- .../models/tests/test_course_details.py | 6 +----- .../waffle_utils/tests/test_views.py | 6 +++--- openedx/core/toggles.py | 10 ++++----- xmodule/course_block.py | 10 ++++----- xmodule/seq_block.py | 8 +++---- xmodule/tests/test_course_block.py | 4 +--- 23 files changed, 88 insertions(+), 84 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index 7f2e8a151d..876bb37ee7 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -388,15 +388,15 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): (True, True, True), ) @override_waffle_flag(toggles.LEGACY_STUDIO_SCHEDULE_DETAILS, True) + @override_settings(MILESTONES_APP=False) def test_visibility_of_entrance_exam_section(self, feature_flags): """ Tests entrance exam section is available if ENTRANCE_EXAMS feature is enabled no matter any other feature is enabled or disabled i.e ENABLE_PUBLISHER. """ with patch.dict("django.conf.settings.FEATURES", { - 'ENTRANCE_EXAMS': feature_flags[0], 'ENABLE_PUBLISHER': feature_flags[1] - }): + }), override_settings(ENTRANCE_EXAMS=feature_flags[0]): course_details_url = get_url(self.course.id) resp = self.client.get_html(course_details_url) self.assertEqual( @@ -405,14 +405,15 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): ) @override_waffle_flag(toggles.LEGACY_STUDIO_SCHEDULE_DETAILS, True) + @override_settings(MILESTONES_APP=False) + @override_settings(ENTRANCE_EXAMS=False) def test_marketing_site_fetch(self): settings_details_url = get_url(self.course.id) with mock.patch.dict('django.conf.settings.FEATURES', { 'ENABLE_PUBLISHER': True, 'ENABLE_MKTG_SITE': True, - 'ENTRANCE_EXAMS': False, - 'ENABLE_PREREQUISITE_COURSES': False + 'ENABLE_PREREQUISITE_COURSES': False, }): response = self.client.get_html(settings_details_url) self.assertNotContains(response, "Course Summary Page") @@ -1128,7 +1129,7 @@ class CourseMetadataEditingTest(CourseTestCase): self.assertIn('showanswer', test_model, 'showanswer field ') self.assertIn('xqa_key', test_model, 'xqa_key field ') - @patch.dict(settings.FEATURES, {'ENABLE_EXPORT_GIT': True}) + @override_settings(ENABLE_EXPORT_GIT=True) def test_fetch_giturl_present(self): """ If feature flag ENABLE_EXPORT_GIT is on, show the setting as a non-deprecated Advanced Setting. @@ -1136,7 +1137,7 @@ class CourseMetadataEditingTest(CourseTestCase): test_model = CourseMetadata.fetch(self.fullcourse) self.assertIn('giturl', test_model) - @patch.dict(settings.FEATURES, {'ENABLE_EXPORT_GIT': False}) + @override_settings(ENABLE_EXPORT_GIT=False) def test_fetch_giturl_not_present(self): """ If feature flag ENABLE_EXPORT_GIT is off, don't show the setting at all on the Advanced Settings page. @@ -1172,7 +1173,7 @@ class CourseMetadataEditingTest(CourseTestCase): test_model = CourseMetadata.fetch(self.fullcourse) self.assertNotIn('proctoring_escalation_email', test_model) - @patch.dict(settings.FEATURES, {'ENABLE_EXPORT_GIT': False}) + @override_settings(ENABLE_EXPORT_GIT=False) def test_validate_update_filtered_off(self): """ If feature flag is off, then giturl must be filtered. @@ -1187,7 +1188,7 @@ class CourseMetadataEditingTest(CourseTestCase): ) self.assertNotIn('giturl', test_model) - @patch.dict(settings.FEATURES, {'ENABLE_EXPORT_GIT': True}) + @override_settings(ENABLE_EXPORT_GIT=True) def test_validate_update_filtered_on(self): """ If feature flag is on, then giturl must not be filtered. @@ -1202,7 +1203,7 @@ class CourseMetadataEditingTest(CourseTestCase): ) self.assertIn('giturl', test_model) - @patch.dict(settings.FEATURES, {'ENABLE_EXPORT_GIT': True}) + @override_settings(ENABLE_EXPORT_GIT=True) def test_update_from_json_filtered_on(self): """ If feature flag is on, then giturl must be updated. @@ -1216,7 +1217,7 @@ class CourseMetadataEditingTest(CourseTestCase): ) self.assertIn('giturl', test_model) - @patch.dict(settings.FEATURES, {'ENABLE_EXPORT_GIT': False}) + @override_settings(ENABLE_EXPORT_GIT=False) def test_update_from_json_filtered_off(self): """ If feature flag is on, then giturl must not be updated. diff --git a/cms/djangoapps/contentstore/tests/test_utils.py b/cms/djangoapps/contentstore/tests/test_utils.py index df55e2dde9..c529410cd1 100644 --- a/cms/djangoapps/contentstore/tests/test_utils.py +++ b/cms/djangoapps/contentstore/tests/test_utils.py @@ -892,8 +892,8 @@ class UpdateCourseDetailsTests(ModuleStoreTestCase): @patch.dict("django.conf.settings.FEATURES", { "ENABLE_PREREQUISITE_COURSES": False, - "ENTRANCE_EXAMS": False, }) + @override_settings(ENTRANCE_EXAMS=False) @patch("cms.djangoapps.contentstore.utils.CourseDetails.update_from_json") def test_update_course_details_self_paced(self, mock_update): """ @@ -918,8 +918,8 @@ class UpdateCourseDetailsTests(ModuleStoreTestCase): @patch.dict("django.conf.settings.FEATURES", { "ENABLE_PREREQUISITE_COURSES": False, - "ENTRANCE_EXAMS": False, }) + @override_settings(ENTRANCE_EXAMS=False) @patch("cms.djangoapps.contentstore.utils.CourseDetails.update_from_json") def test_update_course_details_instructor_paced(self, mock_update): """ diff --git a/cms/djangoapps/contentstore/toggles.py b/cms/djangoapps/contentstore/toggles.py index 9601d118fc..5462a28bae 100644 --- a/cms/djangoapps/contentstore/toggles.py +++ b/cms/djangoapps/contentstore/toggles.py @@ -1,13 +1,13 @@ """ CMS feature toggles. """ -from edx_toggles.toggles import SettingDictToggle, WaffleFlag +from edx_toggles.toggles import SettingToggle, WaffleFlag from openedx.core.djangoapps.content.search import api as search_api from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag -# .. toggle_name: FEATURES['ENABLE_EXPORT_GIT'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: ENABLE_EXPORT_GIT +# .. toggle_implementation: SettingToggle # .. toggle_default: False # .. toggle_description: When enabled, a "Export to Git" menu item is added to the course studio for courses that have a # valid "giturl" attribute. Exporting a course to git causes the course to be exported in the directory indicated by @@ -17,8 +17,8 @@ from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag # existing directory. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2014-02-13 -EXPORT_GIT = SettingDictToggle( - "FEATURES", "ENABLE_EXPORT_GIT", default=False, module_name=__name__ +EXPORT_GIT = SettingToggle( + "ENABLE_EXPORT_GIT", default=False, module_name=__name__ ) # Namespace for studio dashboard waffle flags. @@ -406,8 +406,8 @@ def default_enable_flexible_peer_openassessments(course_key): return DEFAULT_ENABLE_FLEXIBLE_PEER_OPENASSESSMENTS.is_enabled(course_key) -# .. toggle_name: FEATURES['ENABLE_CONTENT_LIBRARIES'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: ENABLE_CONTENT_LIBRARIES +# .. toggle_implementation: SettingToggle # .. toggle_default: True # .. toggle_description: Enables use of the legacy and v2 libraries waffle flags. # Note that legacy content libraries are only supported in courses using split mongo. @@ -416,8 +416,8 @@ def default_enable_flexible_peer_openassessments(course_key): # .. toggle_target_removal_date: 2025-04-09 # .. toggle_warning: This flag is deprecated in Sumac, and will be removed in favor of the disable_legacy_libraries and # disable_new_libraries waffle flags. -ENABLE_CONTENT_LIBRARIES = SettingDictToggle( - "FEATURES", "ENABLE_CONTENT_LIBRARIES", default=True, module_name=__name__ +ENABLE_CONTENT_LIBRARIES = SettingToggle( + "ENABLE_CONTENT_LIBRARIES", default=True, module_name=__name__ ) # .. toggle_name: contentstore.new_studio_mfe.disable_legacy_libraries diff --git a/cms/djangoapps/contentstore/views/tests/test_entrance_exam.py b/cms/djangoapps/contentstore/views/tests/test_entrance_exam.py index a2cb570cf7..dea52cbe7b 100644 --- a/cms/djangoapps/contentstore/views/tests/test_entrance_exam.py +++ b/cms/djangoapps/contentstore/views/tests/test_entrance_exam.py @@ -4,9 +4,9 @@ Test module for Entrance Exams AJAX callback handler workflows import json -from unittest.mock import patch from django.conf import settings +from django.test import override_settings from django.test.client import RequestFactory from milestones.tests.utils import MilestonesTestCaseMixin from opaque_keys.edx.keys import UsageKey @@ -30,7 +30,7 @@ from cms.djangoapps.contentstore.helpers import GRADER_TYPES from cms.djangoapps.contentstore.xblock_storage_handlers.create_xblock import create_xblock -@patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True}) +@override_settings(ENTRANCE_EXAMS=True) class EntranceExamHandlerTests(CourseTestCase, MilestonesTestCaseMixin): """ Base test class for create, save, and delete @@ -319,7 +319,7 @@ class EntranceExamHandlerTests(CourseTestCase, MilestonesTestCaseMixin): resp = create_entrance_exam(request, self.course.id, None) self.assertEqual(resp.status_code, 201) - @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': False}) + @override_settings(ENTRANCE_EXAMS=False) def test_entrance_exam_feature_flag_gating(self): user = UserFactory() user.is_staff = True diff --git a/cms/djangoapps/contentstore/views/tests/test_library.py b/cms/djangoapps/contentstore/views/tests/test_library.py index b6c5765c51..fd62faa56d 100644 --- a/cms/djangoapps/contentstore/views/tests/test_library.py +++ b/cms/djangoapps/contentstore/views/tests/test_library.py @@ -161,7 +161,7 @@ class UnitTestLibraries(CourseTestCase): self.assertEqual(get_response.status_code, 200) self.assertEqual(post_response.status_code, 403) - @mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_CONTENT_LIBRARIES': False}) + @override_settings(ENABLE_CONTENT_LIBRARIES=False) def test_with_libraries_disabled(self): """ The library URLs should return 404 if libraries are disabled. diff --git a/common/djangoapps/util/milestones_helpers.py b/common/djangoapps/util/milestones_helpers.py index f7909a0863..94ec358f92 100644 --- a/common/djangoapps/util/milestones_helpers.py +++ b/common/djangoapps/util/milestones_helpers.py @@ -3,7 +3,7 @@ Utility library for working with the edx-milestones app """ from django.conf import settings from django.utils.translation import gettext as _ -from edx_toggles.toggles import SettingDictToggle +from edx_toggles.toggles import SettingToggle from milestones import api as milestones_api from milestones.exceptions import InvalidMilestoneRelationshipTypeException, InvalidUserException from milestones.models import MilestoneRelationshipType @@ -23,15 +23,15 @@ NAMESPACE_CHOICES = { REQUEST_CACHE_NAME = "milestones" # TODO this should be moved to edx/edx-milestones -# .. toggle_name: FEATURES['MILESTONES_APP'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: MILESTONES_APP +# .. toggle_implementation: SettingToggle # .. toggle_default: False # .. toggle_description: Enable the milestones application, which manages significant Course and/or Student events in # the Open edX platform. (see https://github.com/openedx/edx-milestones) Note that this feature is required to enable # course pre-requisites. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2014-11-21 -ENABLE_MILESTONES_APP = SettingDictToggle("FEATURES", "MILESTONES_APP", default=False, module_name=__name__) +ENABLE_MILESTONES_APP = SettingToggle("MILESTONES_APP", default=False, module_name=__name__) def get_namespace_choices(): diff --git a/common/djangoapps/util/tests/test_milestones_helpers.py b/common/djangoapps/util/tests/test_milestones_helpers.py index 3ff758dd44..efff367d75 100644 --- a/common/djangoapps/util/tests/test_milestones_helpers.py +++ b/common/djangoapps/util/tests/test_milestones_helpers.py @@ -5,8 +5,8 @@ from unittest.mock import patch import ddt import pytest -from django.conf import settings from django.contrib.auth.models import AnonymousUser +from django.test import override_settings from milestones import api as milestones_api from milestones.exceptions import InvalidCourseKeyException, InvalidUserException from milestones.models import MilestoneRelationshipType @@ -16,7 +16,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-a from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order -@patch.dict(settings.FEATURES, {'MILESTONES_APP': False}) +@override_settings(MILESTONES_APP=False) @ddt.ddt class MilestonesHelpersTestCase(ModuleStoreTestCase): """ @@ -61,8 +61,7 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): with patch.dict("django.conf.settings.FEATURES", { 'ENABLE_PREREQUISITE_COURSES': feature_flags[0], - 'MILESTONES_APP': feature_flags[1] - }): + }), override_settings(MILESTONES_APP=feature_flags[1]): assert feature_flags[2] == milestones_helpers.is_prerequisite_courses_enabled() def test_add_milestone_returns_none_when_app_disabled(self): @@ -123,7 +122,7 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): response = milestones_helpers.get_service() assert response is None - @patch.dict(settings.FEATURES, {'MILESTONES_APP': True}) + @override_settings(MILESTONES_APP=True) def test_any_unfulfilled_milestones(self): """ Tests any_unfulfilled_milestones for invalid arguments with the app enabled. @@ -137,7 +136,7 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase): with pytest.raises(InvalidUserException): milestones_helpers.any_unfulfilled_milestones(self.course.id, None) - @patch.dict(settings.FEATURES, {'MILESTONES_APP': True}) + @override_settings(MILESTONES_APP=True) def test_get_required_content_with_anonymous_user(self): course = CourseFactory() diff --git a/lms/djangoapps/courseware/tests/test_access.py b/lms/djangoapps/courseware/tests/test_access.py index c763a7577a..4e97e09c83 100644 --- a/lms/djangoapps/courseware/tests/test_access.py +++ b/lms/djangoapps/courseware/tests/test_access.py @@ -681,7 +681,8 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes assert access._has_access_course(staff, 'see_in_catalog', course) assert access._has_access_course(staff, 'see_about_page', course) - @patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True}) + @patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True}) + @override_settings(MILESTONES_APP=True) def test_access_on_course_with_pre_requisites(self): """ Test course access when a course has pre-requisite course yet to be completed diff --git a/lms/djangoapps/courseware/tests/test_entrance_exam.py b/lms/djangoapps/courseware/tests/test_entrance_exam.py index 338a7bedfc..2a17a0f87b 100644 --- a/lms/djangoapps/courseware/tests/test_entrance_exam.py +++ b/lms/djangoapps/courseware/tests/test_entrance_exam.py @@ -5,6 +5,7 @@ Tests use cases related to LMS Entrance Exam behavior, such as gated content acc from unittest.mock import patch from crum import set_current_request +from django.test import override_settings from django.urls import reverse from milestones.tests.utils import MilestonesTestCaseMixin from lms.djangoapps.courseware.entrance_exams import ( @@ -36,7 +37,7 @@ from common.djangoapps.util.milestones_helpers import ( ) -@patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True}) +@override_settings(ENTRANCE_EXAMS=True) class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTestCaseMixin): """ Check that content is properly gated. @@ -44,7 +45,7 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest Creates a test course from scratch. The tests below are designed to execute workflows regardless of the feature flag settings. """ - @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True}) + @override_settings(ENTRANCE_EXAMS=True) def setUp(self): """ Test case scaffolding diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index 6ad7ef73de..841b0ffe53 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -8,6 +8,7 @@ import pytest from crum import set_current_request from django.contrib.auth.models import AnonymousUser from django.http import Http404 +from django.test import override_settings from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_flag from milestones.tests.utils import MilestonesTestCaseMixin @@ -333,12 +334,12 @@ class StaticTabDateTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): self.assertContains(resp, self.xml_data) -@patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True}) +@override_settings(ENTRANCE_EXAMS=True) class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTestCaseMixin): """ Validate tab behavior when dealing with Entrance Exams """ - @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True}) + @override_settings(ENTRANCE_EXAMS=True) def setUp(self): """ Test case scaffolding diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index d54da21353..4d9f6f83b9 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -3368,7 +3368,7 @@ class TestInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTes assert response.status_code == 200 assert act.called - @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True}) + @override_settings(ENTRANCE_EXAMS=True) def test_course_has_entrance_exam_in_student_attempts_reset(self): """ Test course has entrance exam id set while resetting attempts""" url = reverse('reset_student_attempts_for_entrance_exam', @@ -3379,7 +3379,7 @@ class TestInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTes }) assert response.status_code == 400 - @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True}) + @override_settings(ENTRANCE_EXAMS=True) def test_rescore_entrance_exam_with_invalid_exam(self): """ Test course has entrance exam id set while re-scoring. """ url = reverse('rescore_entrance_exam', kwargs={'course_id': str(self.course.id)}) @@ -3389,7 +3389,7 @@ class TestInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTes assert response.status_code == 400 -@patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True}) +@override_settings(ENTRANCE_EXAMS=True) @ddt.ddt class TestEntranceExamInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ diff --git a/lms/djangoapps/mfe_config_api/tests/test_views.py b/lms/djangoapps/mfe_config_api/tests/test_views.py index fcf1f1ad29..0dfc63e827 100644 --- a/lms/djangoapps/mfe_config_api/tests/test_views.py +++ b/lms/djangoapps/mfe_config_api/tests/test_views.py @@ -5,6 +5,7 @@ Test the use cases of the views of the mfe api. from unittest.mock import call, patch import ddt +from django.core.cache import cache from django.conf import settings from django.test import override_settings from django.urls import reverse @@ -30,6 +31,7 @@ class MFEConfigTestCase(APITestCase): def setUp(self): self.mfe_config_api_url = reverse("mfe_config_api:config") + cache.clear() return super().setUp() @patch("lms.djangoapps.mfe_config_api.views.configuration_helpers") diff --git a/lms/djangoapps/mobile_api/tests/test_milestones.py b/lms/djangoapps/mobile_api/tests/test_milestones.py index 12de519b04..2ecd7a0e38 100644 --- a/lms/djangoapps/mobile_api/tests/test_milestones.py +++ b/lms/djangoapps/mobile_api/tests/test_milestones.py @@ -7,6 +7,7 @@ from unittest.mock import patch from crum import set_current_request from django.conf import settings +from django.test import override_settings from common.djangoapps.util.milestones_helpers import add_prerequisite_course, fulfill_course_milestone from lms.djangoapps.courseware.access_response import MilestoneAccessError @@ -56,7 +57,8 @@ class MobileAPIMilestonesMixin: self.init_course_access() self.api_response() - @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True, 'ENABLE_MKTG_SITE': True}) + @override_settings(ENTRANCE_EXAMS=True) + @patch.dict(settings.FEATURES, {'ENABLE_MKTG_SITE': True}) def test_unpassed_entrance_exam(self): """ Tests the case where the user has not passed the entrance exam @@ -65,7 +67,8 @@ class MobileAPIMilestonesMixin: self.init_course_access() self._verify_unfulfilled_milestone_response() - @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True, 'ENABLE_MKTG_SITE': True}) + @override_settings(ENTRANCE_EXAMS=True) + @patch.dict(settings.FEATURES, {'ENABLE_MKTG_SITE': True}) def test_unpassed_entrance_exam_for_staff(self): self._add_entrance_exam() self.user.is_staff = True @@ -73,7 +76,8 @@ class MobileAPIMilestonesMixin: self.init_course_access() self.api_response() - @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True, 'ENABLE_MKTG_SITE': True}) + @override_settings(ENTRANCE_EXAMS=True) + @patch.dict(settings.FEATURES, {'ENABLE_MKTG_SITE': True}) def test_passed_entrance_exam(self): """ Tests access when user has passed the entrance exam diff --git a/lms/djangoapps/teams/tests/test_views.py b/lms/djangoapps/teams/tests/test_views.py index 6eaa1bdb68..9c4ca5feab 100644 --- a/lms/djangoapps/teams/tests/test_views.py +++ b/lms/djangoapps/teams/tests/test_views.py @@ -16,6 +16,7 @@ from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.core.files.uploadedfile import SimpleUploadedFile from django.db.models.signals import post_save +from django.test import override_settings from django.urls import reverse from django.utils import translation from elasticsearch.exceptions import ConnectionError # lint-amnesty, pylint: disable=redefined-builtin @@ -1673,7 +1674,7 @@ class TestUpdateTeamAPI(EventTestMixin, TeamAPITestCase): assert team['name'] == 'foo' -@patch.dict(settings.FEATURES, {'ENABLE_ORA_TEAM_SUBMISSIONS': True}) +@override_settings(ENABLE_ORA_TEAM_SUBMISSIONS=True) @ddt.ddt class TestTeamAssignmentsView(TeamAPITestCase): """ Tests for the TeamAssignmentsView """ @@ -1756,7 +1757,7 @@ class TestTeamAssignmentsView(TeamAPITestCase): expected_status = 404 self.get_team_assignments(team_id, expected_status, user=user) - @patch.dict(settings.FEATURES, {'ENABLE_ORA_TEAM_SUBMISSIONS': False}) + @override_settings(ENABLE_ORA_TEAM_SUBMISSIONS=False) def test_get_assignments_feature_not_enabled(self): # Given the team submissions feature is not enabled user = 'student_enrolled' diff --git a/lms/djangoapps/teams/toggles.py b/lms/djangoapps/teams/toggles.py index 5ce8fd08ce..0f1c56c20f 100644 --- a/lms/djangoapps/teams/toggles.py +++ b/lms/djangoapps/teams/toggles.py @@ -1,7 +1,7 @@ """ Togglable settings for Teams behavior """ -from edx_toggles.toggles import SettingDictToggle +from edx_toggles.toggles import SettingToggle from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag @@ -9,8 +9,8 @@ from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag WAFFLE_NAMESPACE = "openresponseassessment" TEAM_SUBMISSIONS_FLAG = "team_submissions" -# .. toggle_name: FEATURES['ENABLE_ORA_TEAM_SUBMISSIONS'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: ENABLE_ORA_TEAM_SUBMISSIONS +# .. toggle_implementation: SettingToggle # .. toggle_default: False # .. toggle_description: Set to True to enable team-based ORA submissions. # .. toggle_use_cases: temporary @@ -20,8 +20,8 @@ TEAM_SUBMISSIONS_FLAG = "team_submissions" # .. toggle_warning: This temporary feature toggle does not have a target removal date. This can be overridden by a # course waffle flags or a waffle switch with identical name. # TODO: this should be moved to edx/edx-ora2 -TEAM_SUBMISSIONS_FEATURE = SettingDictToggle( - "FEATURES", "ENABLE_ORA_TEAM_SUBMISSIONS", default=False, module_name=__name__ +TEAM_SUBMISSIONS_FEATURE = SettingToggle( + "ENABLE_ORA_TEAM_SUBMISSIONS", default=False, module_name=__name__ ) diff --git a/openedx/core/djangoapps/credentials/helpers.py b/openedx/core/djangoapps/credentials/helpers.py index b654a8cb92..9dba4ac9c9 100644 --- a/openedx/core/djangoapps/credentials/helpers.py +++ b/openedx/core/djangoapps/credentials/helpers.py @@ -2,12 +2,12 @@ Helpers for the credentials service. """ -from edx_toggles.toggles import SettingDictToggle +from edx_toggles.toggles import SettingToggle from openedx.core.djangoapps.site_configuration import helpers as config_helpers -# .. toggle_name: FEATURES['ENABLE_LEARNER_RECORDS'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: ENABLE_LEARNER_RECORDS +# .. toggle_implementation: SettingToggle # .. toggle_default: True # .. toggle_description: Enable learner records for the whole platform. This setting may be overridden by site- and # org-specific site configurations with the same name. @@ -15,8 +15,8 @@ from openedx.core.djangoapps.site_configuration import helpers as config_helpers # setting. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-10-01 -ENABLE_LEARNER_RECORDS = SettingDictToggle( - "FEATURES", "ENABLE_LEARNER_RECORDS", default=True, module_name=__name__ +ENABLE_LEARNER_RECORDS = SettingToggle( + "ENABLE_LEARNER_RECORDS", default=True, module_name=__name__ ) diff --git a/openedx/core/djangoapps/credentials/tests/test_tasks.py b/openedx/core/djangoapps/credentials/tests/test_tasks.py index 68aea792be..6fb752302b 100644 --- a/openedx/core/djangoapps/credentials/tests/test_tasks.py +++ b/openedx/core/djangoapps/credentials/tests/test_tasks.py @@ -549,7 +549,7 @@ class TestSendGradeIfInteresting(TestCase): _mock_is_learner_issuance_enabled ): assert is_learner_records_enabled() - with override_settings(FEATURES={"ENABLE_LEARNER_RECORDS": False}): + with override_settings(ENABLE_LEARNER_RECORDS=False): assert not is_learner_records_enabled() tasks.send_grade_if_interesting(self.user, self.key, 'verified', 'downloadable', None, None) assert not mock_send_grade_to_credentials.delay.called diff --git a/openedx/core/djangoapps/models/tests/test_course_details.py b/openedx/core/djangoapps/models/tests/test_course_details.py index b23b56c88a..769499bf23 100644 --- a/openedx/core/djangoapps/models/tests/test_course_details.py +++ b/openedx/core/djangoapps/models/tests/test_course_details.py @@ -9,7 +9,6 @@ import pytest import ddt from zoneinfo import ZoneInfo -from django.conf import settings from xmodule.modulestore import ModuleStoreEnum from xmodule.data import CertificatesDisplayBehaviors from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, ModuleStoreTestCase @@ -33,10 +32,7 @@ class CourseDetailsTestCase(ModuleStoreTestCase): @ddt.data(True, False) def test_virgin_fetch(self, should_have_default_enroll_start): - features = settings.FEATURES.copy() - features['CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE'] = should_have_default_enroll_start - - with override_settings(FEATURES=features): + with override_settings(CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE=should_have_default_enroll_start): course = CourseFactory.create(default_enrollment_start=should_have_default_enroll_start) details = CourseDetails.fetch(course.id) wrong_enrollment_start_msg = ( diff --git a/openedx/core/djangoapps/waffle_utils/tests/test_views.py b/openedx/core/djangoapps/waffle_utils/tests/test_views.py index 496b7c6d0b..126d65d300 100644 --- a/openedx/core/djangoapps/waffle_utils/tests/test_views.py +++ b/openedx/core/djangoapps/waffle_utils/tests/test_views.py @@ -25,13 +25,13 @@ class ToggleStateViewTests(TestCase): # lint-amnesty, pylint: disable=missing-c response = get_toggle_state_response(is_staff=False) assert response.status_code == 403 - def test_response_with_existing_setting_dict_toggle(self): + def test_response_with_existing_setting_toggle(self): response = get_toggle_state_response() assert { - "name": "FEATURES['MILESTONES_APP']", + "name": "MILESTONES_APP", "is_active": True, "module": "common.djangoapps.util.milestones_helpers", - "class": "SettingDictToggle", + "class": "SettingToggle", } in response.data["django_settings"] def test_response_with_course_override(self): diff --git a/openedx/core/toggles.py b/openedx/core/toggles.py index b3ef6e507e..b4f704dca2 100644 --- a/openedx/core/toggles.py +++ b/openedx/core/toggles.py @@ -2,16 +2,16 @@ Feature toggles used across the platform. Toggles should only be added to this module if we don't have a better place for them. Generally speaking, they should be added to the most appropriate app or repo. """ -from edx_toggles.toggles import SettingDictToggle +from edx_toggles.toggles import SettingToggle -# .. toggle_name: FEATURES['ENTRANCE_EXAMS'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: ENTRANCE_EXAMS +# .. toggle_implementation: SettingToggle # .. toggle_default: False # .. toggle_description: Enable entrance exams feature. When enabled, students see an exam xblock as the first unit # of the course. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2015-12-01 # .. toggle_tickets: https://openedx.atlassian.net/browse/SOL-40 -ENTRANCE_EXAMS = SettingDictToggle( - "FEATURES", "ENTRANCE_EXAMS", default=False, module_name=__name__ +ENTRANCE_EXAMS = SettingToggle( + "ENTRANCE_EXAMS", default=False, module_name=__name__ ) diff --git a/xmodule/course_block.py b/xmodule/course_block.py index f9b0df7801..17dc4d877b 100644 --- a/xmodule/course_block.py +++ b/xmodule/course_block.py @@ -12,7 +12,7 @@ import dateutil.parser import requests from django.conf import settings from django.core.validators import validate_email -from edx_toggles.toggles import SettingDictToggle +from edx_toggles.toggles import SettingToggle from lazy import lazy from lxml import etree from path import Path as path @@ -59,8 +59,8 @@ COURSE_VISIBILITY_PRIVATE = 'private' COURSE_VISIBILITY_PUBLIC_OUTLINE = 'public_outline' COURSE_VISIBILITY_PUBLIC = 'public' -# .. toggle_name: FEATURES['CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE +# .. toggle_implementation: SettingToggle # .. toggle_default: False # .. toggle_description: The default behavior, when this is disabled, is that a newly created course has no # enrollment_start date set. When the feature is enabled - the newly created courses will have the @@ -71,8 +71,8 @@ COURSE_VISIBILITY_PUBLIC = 'public' # the newly created (empty) course from appearing in the course listing. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2023-06-22 -CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE = SettingDictToggle( - "FEATURES", "CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE", default=False, module_name=__name__ +CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE = SettingToggle( + "CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE", default=False, module_name=__name__ ) diff --git a/xmodule/seq_block.py b/xmodule/seq_block.py index c374ca3562..5c35316102 100644 --- a/xmodule/seq_block.py +++ b/xmodule/seq_block.py @@ -23,7 +23,7 @@ from xblock.exceptions import NoSuchServiceError from xblock.fields import Boolean, Date, Integer, List, Scope, String from xblock.progress import Progress -from edx_toggles.toggles import WaffleFlag, SettingDictToggle +from edx_toggles.toggles import WaffleFlag, SettingToggle from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment from xmodule.x_module import ( ResourceTemplates, @@ -54,14 +54,14 @@ TIMED_EXAM_GATING_WAFFLE_FLAG = WaffleFlag( # lint-amnesty, pylint: disable=tog 'xmodule.rev_1377_rollout', __name__ ) -# .. toggle_name: FEATURES['SHOW_PROGRESS_BAR'] -# .. toggle_implementation: SettingDictToggle +# .. toggle_name: SHOW_PROGRESS_BAR +# .. toggle_implementation: SettingToggle # .. toggle_default: False # .. toggle_description: Set to True to show progress bar. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2022-02-09 # .. toggle_target_removal_date: None -SHOW_PROGRESS_BAR = SettingDictToggle("FEATURES", "SHOW_PROGRESS_BAR", default=False, module_name=__name__) +SHOW_PROGRESS_BAR = SettingToggle("SHOW_PROGRESS_BAR", default=False, module_name=__name__) class SequenceFields: # lint-amnesty, pylint: disable=missing-class-docstring diff --git a/xmodule/tests/test_course_block.py b/xmodule/tests/test_course_block.py index 68b46bf3d8..a7ef4181a2 100644 --- a/xmodule/tests/test_course_block.py +++ b/xmodule/tests/test_course_block.py @@ -42,9 +42,7 @@ class CourseFieldsTestCase(unittest.TestCase): # lint-amnesty, pylint: disable= @ddt.data(True, False) def test_default_enrollment_start_date(self, should_have_default_enroll_start): - features = settings.FEATURES.copy() - features['CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE'] = should_have_default_enroll_start - with override_settings(FEATURES=features): + with override_settings(CREATE_COURSE_WITH_DEFAULT_ENROLLMENT_START_DATE=should_have_default_enroll_start): # reimport, so settings override could take effect del sys.modules['xmodule.course_block'] import xmodule.course_block # lint-amnesty, pylint: disable=redefined-outer-name, reimported