From fedeafb072e104318b98157417004f67b6b32b24 Mon Sep 17 00:00:00 2001 From: Eugene Dyudyunov Date: Wed, 11 May 2022 22:02:02 +0300 Subject: [PATCH] feat!: remove legacy waffle flags (#211) This is a part of https://github.com/openedx/public-engineering/issues/28 BREAKING CHANGE: Removed LegacyWaffle* classes. Although this is a breaking change, all known uses have already been fixed. --- CHANGELOG.rst | 4 + .../documenting_new_feature_toggles.rst | 6 - edx_toggles/__init__.py | 2 +- edx_toggles/tests/test_legacy_waffle.py | 51 ------ edx_toggles/toggles/__init__.py | 6 - edx_toggles/toggles/internal/waffle/legacy.py | 166 ------------------ 6 files changed, 5 insertions(+), 230 deletions(-) delete mode 100644 edx_toggles/tests/test_legacy_waffle.py delete mode 100644 edx_toggles/toggles/internal/waffle/legacy.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3616d61c..32f5e0c9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,10 @@ Change Log Unreleased ~~~~~~~~~~ +[5.0.0] - 2022-04-22 +-------------------- + +* BREAKING CHANGE: Removed LegacyWaffle* classes. Although this is a breaking change, all known uses have already been fixed. * Handle the case where certain toggle names come in as ``None`` when generating summary reports. * Add ADR for updating annotations for toggle life expectancy and use cases. diff --git a/docs/how_to/documenting_new_feature_toggles.rst b/docs/how_to/documenting_new_feature_toggles.rst index 52db036d..9e70cac0 100644 --- a/docs/how_to/documenting_new_feature_toggles.rst +++ b/docs/how_to/documenting_new_feature_toggles.rst @@ -196,12 +196,6 @@ Refactor to use new toggle setting classes Undocumented boolean Django Setting toggles defined in the Open edX codebase are probably not yet defined using a ``SettingToggle`` or ``SettingDictToggle``. Read about implementing these toggle classes in :doc:`implement_the_right_toggle_type`. -Refactor LegacyWaffle classes ------------------------------- - -* Import ``WaffleFlag`` instead of ``LegacyWaffleFlag`` or ``WaffleSwitch`` instead of ``LegacyWaffleSwitch``. -* Initialize these new classes with a single string that includes the fully namespaced toggle name, including the period. - Refactor direct waffle usage ---------------------------- diff --git a/edx_toggles/__init__.py b/edx_toggles/__init__.py index e42081ee..6af2b020 100644 --- a/edx_toggles/__init__.py +++ b/edx_toggles/__init__.py @@ -2,6 +2,6 @@ Library and utilities for feature toggles. """ -__version__ = '4.3.1' +__version__ = '5.0.0' default_app_config = 'edx_toggles.apps.TogglesConfig' # pylint: disable=invalid-name diff --git a/edx_toggles/tests/test_legacy_waffle.py b/edx_toggles/tests/test_legacy_waffle.py deleted file mode 100644 index 9409d17a..00000000 --- a/edx_toggles/tests/test_legacy_waffle.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Unit tests for legacy waffle objects. These tests should be moved to test_waffle.py once the legacy classes are removed. -""" -from django.test import TestCase - -from edx_toggles.toggles.internal.waffle.legacy import ( - LegacyWaffleFlag, - LegacyWaffleFlagNamespace, - LegacyWaffleSwitch, - LegacyWaffleSwitchNamespace -) - - -class TestLegacyWaffleSwitch(TestCase): - """ - Tests the LegacyWaffleSwitch. - """ - - def test_default_value(self): - namespace = LegacyWaffleSwitchNamespace("test_namespace") - switch = LegacyWaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation - namespace, "test_switch_name", module_name="module1" - ) - self.assertFalse(switch.is_enabled()) - self.assertFalse(namespace.is_enabled("test_switch_name")) - - # pylint: disable=protected-access - def test_set_request_cache_with_short_name(self): - namespace = LegacyWaffleSwitchNamespace("test_namespace") - switch = LegacyWaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation - namespace, "test_switch_name", module_name="module1" - ) - self.assertFalse(switch._cached_switches.get("test_namespace.test_switch_name")) - namespace.set_request_cache_with_short_name("test_switch_name", True) - self.assertTrue(switch._cached_switches.get("test_namespace.test_switch_name")) - self.assertTrue(switch.is_enabled()) - namespace.set_request_cache_with_short_name("test_switch_name", False) - self.assertFalse(switch._cached_switches.get("test_namespace.test_switch_name")) - self.assertFalse(switch.is_enabled()) - - -class TestLegacyWaffleFlag(TestCase): - """ - Legacy waffle flag tests. - """ - - def test_default_value(self): - namespace = LegacyWaffleFlagNamespace("namespace") - flag = LegacyWaffleFlag(namespace, "flag") # lint-amnesty, pylint: disable=toggle-missing-annotation - self.assertFalse(flag.is_enabled()) - self.assertFalse(namespace.is_flag_active("flag")) diff --git a/edx_toggles/toggles/__init__.py b/edx_toggles/toggles/__init__.py index 3fc5d770..7f338fd2 100644 --- a/edx_toggles/toggles/__init__.py +++ b/edx_toggles/toggles/__init__.py @@ -3,10 +3,4 @@ """ from .internal.setting_toggle import SettingDictToggle, SettingToggle from .internal.waffle.flag import NonNamespacedWaffleFlag, WaffleFlag -from .internal.waffle.legacy import ( - LegacyWaffleFlag, - LegacyWaffleFlagNamespace, - LegacyWaffleSwitch, - LegacyWaffleSwitchNamespace -) from .internal.waffle.switch import NonNamespacedWaffleSwitch, WaffleSwitch diff --git a/edx_toggles/toggles/internal/waffle/legacy.py b/edx_toggles/toggles/internal/waffle/legacy.py deleted file mode 100644 index 78766946..00000000 --- a/edx_toggles/toggles/internal/waffle/legacy.py +++ /dev/null @@ -1,166 +0,0 @@ -""" -This module contains legacy code for backward compatibility. Waffle flag and switch objects previously required the -creation of namespace objects. The namespace features were all moved to the WaffleSwitch/Flag classes. - -To upgrade your code, use the following guidelines. Where previously you had:: - - from edx_toggles.toggles import LegacyWaffleSwitch, LegacyWaffleSwitchNamespace - SOME_NAMESPACE = LegacyWaffleSwitchNamespace("some_namespace") - SOME_SWITCH = LegacyWaffleSwitch(SOME_NAMESPACE, "some_switch", module_name=__name__) - -You should now write:: - - from edx_toggles.toggles import WaffleSwitch - SOME_SWITCH = WaffleSwitch("some_namespace.some_switch", module_name=__name__) - -And similarly for waffle flags, replace:: - - from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace - SOME_NAMESPACE = LegacyWaffleFlagNamespace("some_namespace", log_prefix="some_namespace") - SOME_FLAG = LegacyWaffleFlag(SOME_NAMESPACE, "some_flag", module_name=__name__) - -by:: - - from edx_toggles.toggles import WaffleFlag - SOME_FLAG = WaffleFlag("some_namespace.some_flag", module_name=__name__, log_prefix="some_namespace") -""" -from abc import ABC - -from edx_django_utils.monitoring import set_custom_attribute - -from .flag import WaffleFlag -from .switch import WaffleSwitch - - -class BaseNamespace(ABC): - """ - A base class for a request cached namespace for waffle flags/switches. - - An instance of this class represents a single namespace - (e.g. "course_experience"), and can be used to work with a set of - flags or switches that will all share this namespace. - """ - - def __init__(self, name, log_prefix=None): - """ - Initializes the waffle namespace instance. - - Arguments: - name (String): Namespace string appended to start of all waffle - flags and switches (e.g. "grades") - log_prefix (String): Optional string to be appended to log messages - (e.g. "Grades: "). Defaults to ''. - - """ - assert name, "The name is required." - self.name = name - self.log_prefix = log_prefix if log_prefix else "" - set_custom_attribute( - "deprecated_legacy_waffle_class", - "{}.{}[{}]".format( - self.__class__.__module__, self.__class__.__name__, self.name - ), - ) - - def _namespaced_name(self, toggle_name): - """ - Returns the namespaced name of the waffle switch/flag. - - For example, the namespaced name of a waffle switch/flag would be: - my_namespace.my_toggle_name - - Arguments: - toggle_name (String): The name of the flag or switch. - """ - return f"{self.name}.{toggle_name}" - - -class LegacyWaffleSwitchNamespace(BaseNamespace): - """ - Legacy waffle switch namespace class. - """ - - def is_enabled(self, switch_name): - """ - Returns whether or not the switch is enabled. - """ - return WaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation - self._namespaced_name(switch_name), __name__ - ).is_enabled() - - def set_request_cache_with_short_name(self, switch_name, value): - """ - Explicitly set request cache value for the (non-namespaced) switch name. You should avoid using this method as - much as possible as it may have unexpected side-effects. - """ - namespaced_name = self._namespaced_name(switch_name) - # pylint: disable=protected-access - WaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation - namespaced_name, __name__ - )._cached_switches[ - namespaced_name - ] = value - - -class LegacyWaffleSwitch(WaffleSwitch): - """ - Represents a single waffle switch, enhanced with request level caching. - """ - - def __init__(self, waffle_namespace, switch_name, module_name=None): - if not isinstance(waffle_namespace, str): - waffle_namespace = waffle_namespace.name - - self._switch_name = switch_name - name = f"{waffle_namespace}.{switch_name}" - super().__init__(name, module_name=module_name) - set_custom_attribute( - "deprecated_legacy_waffle_class", - "{}.{}[{}]".format( - self.__class__.__module__, self.__class__.__name__, self.name - ), - ) - - -class LegacyWaffleFlagNamespace(BaseNamespace): - """ - Legacy namespace class preserved for backward compatibility. - """ - - def is_flag_active(self, flag_name): - """ - Returns and caches whether the provided flag is active. - """ - return WaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation - self._namespaced_name(flag_name), module_name=__name__ - ).is_enabled() - - @property - def _cached_flags(self): - """ - Legacy property used by CourseWaffleFlag. - """ - return WaffleFlag.cached_flags() - - -class LegacyWaffleFlag(WaffleFlag): - """ - Legacy namespaced waffle flag preserved for backward compatibility. - """ - - def __init__(self, waffle_namespace, flag_name, module_name=None): - log_prefix = "" - if not isinstance(waffle_namespace, str): - log_prefix = waffle_namespace.log_prefix or log_prefix - waffle_namespace = waffle_namespace.name - - # Non-namespaced flag_name attribute preserved for backward compatibility - self._flag_name = flag_name - name = f"{waffle_namespace}.{flag_name}" - super().__init__(name, module_name=module_name, log_prefix=log_prefix) - set_custom_attribute( - "deprecated_legacy_waffle_class", - "{}.{}[{}]".format( - self.__class__.__module__, self.__class__.__name__, self.name - ), - )