diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d867954e..2b5b6fb3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,34 @@ Change Log .. There should always be an "Unreleased" section for changes pending release. +[2.0.0] - 2020-11-05 +~~~~~~~~~~~~~~~~~~~~ + +* BREAKING CHANGE: The ``WaffleFlagNamespace`` and ``WaffleSwitchNamespace`` classes have been removed. You can either rename to ``LegacyWaffleFlagNamespace`` and ``LegacyWaffleSwitchNamespace``, which are deprecated, or you can move to the newer waffle classes that no longer use these Namespace classes (see below). +* BREAKING CHANGE: The ``WaffleFlag`` and ``WaffleSwitch`` classes exposed in ``toggles`` no longer use the Namespace classes and are now the classes which were previously only available in ``toggles.__future__``. + + * If you were importing from ``edx_toggles.toggles.__future__`` before, then you simply need to import from ``edx_toggles.toggles``. Importing from ``__future__`` will continue to work but will trigger a deprecation warning. + * If you were importing from ``edx_toggles.toggles``, then you either need to: + + * Migrate your legacy namespaced classes to the new-style classes (see the new behaviour below), or + * Import ``LegacyWaffleFlag`` instead of ``WaffleFlag`` and ``LegacyWaffleSwitch`` instead of ``WaffleSwitch``. Note that these classes will be removed soon, so it's preferable to migrate to the new classes already. + + * The new Waffle classes introduce the following changes: + + * They no longer use Namespace classes like ``WaffleSwitchNamespace`` or ``WaffleFlagNamespace``. + * The ``WaffleSwitchNamespace._namespaced_name`` and ``WaffleFlagNamespace._namespaced_name`` methods are replaced by the ``WaffleSwitch.name`` and ``WaffleFlag.name`` attributes. + * The ``WaffleSwitchNamespace.is_enabled`` method is replaced by the ``WaffleSwitch.is_enabled`` method. + * The ``WaffleSwitchNamespace.set_request_cache_with_short_name`` method has no replacement because an alternative solution should be found. You could (but really shouldn't) use the ``WaffleSwitch._cached_switches`` property. + * The ``WaffleSwitch.switch_name`` attribute is deprecated: switches should only ever be referred to using their fully namespaced names. + * The ``WaffleSwitch.switch_name`` attribute no longer exists. Switches should only ever be referred to using their fully namespaced names. If you need the non-namespaced name, it must be parsed from the namespaced name. + * The ``WaffleFlagNamespace.is_flag_active`` method is replaced by ``WaffleFlag.is_enabled``. + * The ``WaffleFlagNamespace._monitor_value`` method is replaced by ``WaffleFlag.set_monitor_value``. + * The ``WaffleFlagNamespace._cached_flags`` attribute is replaced by the ``WaffleFlag.cached_flags`` method. + * The ``WaffleFlag`` and ``WaffleSwitch`` ``module_name`` constructor argument is now mandatory. + * The ``WaffleFlag.flag_name`` attribute is deprecated. + * The ``WaffleFlag.flag_name`` attribute no longer exists. Flags should only ever be referred to using their fully namespaced names. If you need the non-namespaced name, it must be parsed from the namespaced name. + * The ``WaffleFlag.waffle_namespace`` attribute no longer exists, since there is no longer a separate namespace object. + [1.2.2] - 2020-12-22 ~~~~~~~~~~~~~~~~~~~~ @@ -25,7 +53,6 @@ More improvements to monitoring of legacy waffle class imports. * Improve monitoring of legacy Waffle class imports. We should watch for "edx_toggles.toggles.internal.waffle.legacy.WaffleSwitch" custom attributes. - [1.2.0] - 2020-11-05 ~~~~~~~~~~~~~~~~~~~~ diff --git a/edx_toggles/__init__.py b/edx_toggles/__init__.py index 64811c38..a70922f5 100644 --- a/edx_toggles/__init__.py +++ b/edx_toggles/__init__.py @@ -2,6 +2,6 @@ Library and utilities for feature toggles. """ -__version__ = '1.2.2' +__version__ = '2.0.0' default_app_config = 'edx_toggles.apps.TogglesConfig' # pylint: disable=invalid-name diff --git a/edx_toggles/tests/test_testutils.py b/edx_toggles/tests/test_testutils.py index 40c92b02..cecb192f 100644 --- a/edx_toggles/tests/test_testutils.py +++ b/edx_toggles/tests/test_testutils.py @@ -8,9 +8,7 @@ from django.test.client import RequestFactory from edx_django_utils.cache import RequestCache -# TODO import from edx_toggles.toggles once we remove the legacy classes from the exposed API -from edx_toggles.toggles.internal.waffle.flag import WaffleFlag -from edx_toggles.toggles.internal.waffle.switch import WaffleSwitch +from edx_toggles.toggles import WaffleFlag, WaffleSwitch from edx_toggles.toggles.testutils import override_waffle_flag, override_waffle_switch diff --git a/edx_toggles/tests/test_waffle.py b/edx_toggles/tests/test_waffle.py index 587d70fe..7f6992be 100644 --- a/edx_toggles/tests/test_waffle.py +++ b/edx_toggles/tests/test_waffle.py @@ -4,10 +4,8 @@ from django.test import TestCase +from edx_toggles.toggles import NonNamespacedWaffleFlag, NonNamespacedWaffleSwitch, WaffleFlag, WaffleSwitch from edx_toggles.toggles.internal.waffle.base import BaseWaffle -# TODO import from edx_toggles.toggles once we remove the legacy classes from the exposed API -from edx_toggles.toggles.internal.waffle.flag import NonNamespacedWaffleFlag, WaffleFlag -from edx_toggles.toggles.internal.waffle.switch import NonNamespacedWaffleSwitch, WaffleSwitch class NaiveWaffle(BaseWaffle): diff --git a/edx_toggles/toggles/__future__.py b/edx_toggles/toggles/__future__.py index ae4d1bfe..20cfee84 100644 --- a/edx_toggles/toggles/__future__.py +++ b/edx_toggles/toggles/__future__.py @@ -1,8 +1,15 @@ """ -Expose new-style waffle classes. In the future, these imports will be moved to edx_toggles.toggles. Applications that -want to migrate to the new-style API can do so right now by importing from this module. +This module had been created to expose new-style waffle classes. These are now available from edx_toggles.toggles. """ -# pylint: disable=unused-import -from .internal.setting_toggle import SettingDictToggle, SettingToggle -from .internal.waffle.flag import NonNamespacedWaffleFlag, WaffleFlag -from .internal.waffle.switch import NonNamespacedWaffleSwitch, WaffleSwitch +import warnings + +from . import * # pylint: disable=unused-import,wildcard-import + +warnings.warn( + ( + "Importing from edx_toggles.toggles.__future__ is now deprecated." + " You should import from edx_toggles.toggles instead." + ), + DeprecationWarning, + stacklevel=2, +) diff --git a/edx_toggles/toggles/__init__.py b/edx_toggles/toggles/__init__.py index 6d22fb19..5405edce 100644 --- a/edx_toggles/toggles/__init__.py +++ b/edx_toggles/toggles/__init__.py @@ -2,27 +2,31 @@ Expose public feature toggle API. """ from .internal.setting_toggle import SettingDictToggle, SettingToggle -from .internal.waffle.legacy import WaffleFlag, WaffleFlagNamespace, WaffleSwitch, WaffleSwitchNamespace +from .internal.waffle.flag import NonNamespacedWaffleFlag, WaffleFlag +from .internal.waffle.legacy import WaffleFlag as _LegacyWaffleFlag +from .internal.waffle.legacy import WaffleFlagNamespace as _LegacyWaffleFlagNamespace +from .internal.waffle.legacy import WaffleSwitch as _LegacyWaffleSwitch +from .internal.waffle.legacy import WaffleSwitchNamespace as _LegacyWaffleSwitchNamespace +from .internal.waffle.switch import NonNamespacedWaffleSwitch, WaffleSwitch -# Create waffle aliases for forward compatibility -# We create new classes instead of using `LegacyClass = Class` statements +# We create new classes instead of simply importing the legacy classes # for better monitoring of legacy class usage. -class LegacyWaffleFlag(WaffleFlag): +class LegacyWaffleFlag(_LegacyWaffleFlag): def _get_legacy_custom_attribute_name(self): - return 'deprecated_compatible_legacy_waffle_class' + return "deprecated_compatible_legacy_waffle_class" -class LegacyWaffleFlagNamespace(WaffleFlagNamespace): +class LegacyWaffleFlagNamespace(_LegacyWaffleFlagNamespace): def _get_legacy_custom_attribute_name(self): - return 'deprecated_compatible_legacy_waffle_class' + return "deprecated_compatible_legacy_waffle_class" -class LegacyWaffleSwitch(WaffleSwitch): +class LegacyWaffleSwitch(_LegacyWaffleSwitch): def _get_legacy_custom_attribute_name(self): - return 'deprecated_compatible_legacy_waffle_class' + return "deprecated_compatible_legacy_waffle_class" -class LegacyWaffleSwitchNamespace(WaffleSwitchNamespace): +class LegacyWaffleSwitchNamespace(_LegacyWaffleSwitchNamespace): def _get_legacy_custom_attribute_name(self): - return 'deprecated_compatible_legacy_waffle_class' + return "deprecated_compatible_legacy_waffle_class" diff --git a/edx_toggles/toggles/internal/waffle/legacy.py b/edx_toggles/toggles/internal/waffle/legacy.py index 57567fb7..cb6595d4 100644 --- a/edx_toggles/toggles/internal/waffle/legacy.py +++ b/edx_toggles/toggles/internal/waffle/legacy.py @@ -4,24 +4,24 @@ To upgrade your code, use the following guidelines. Where previously you had:: - from edx_toggles.toggles import WaffleSwitch, WaffleSwitchNamespace - SOME_NAMESPACE = WaffleSwitchNamespace("some_namespace") - SOME_SWITCH = WaffleSwitch(SOME_NAMESPACE, "some_switch", module_name=__name__) + 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.__future__ import WaffleSwitch + 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 WaffleFlag, WaffleFlagNamespace - SOME_NAMESPACE = WaffleFlagNamespace("some_namespace", log_prefix="some_namespace") - SOME_FLAG = WaffleFlag(SOME_NAMESPACE, "some_flag", module_name=__name__) + 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.__future__ import WaffleFlag + from edx_toggles.toggles import WaffleFlag SOME_FLAG = WaffleFlag("some_namespace.some_flag", module_name=__name__, log_prefix="some_namespace") """ from abc import ABC