diff --git a/CHANGES.txt b/CHANGES.txt index 58205457..e080bbd6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +10.5.1 (Oct 15, 2025) +- Added using String only parameter for treatments in FallbackTreatmentConfiguration class. + 10.5.0 (Sep 15, 2025) - Changed the log level from error to debug when renewing the token for Streaming service in asyncio mode. - Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs. diff --git a/splitio/models/fallback_config.py b/splitio/models/fallback_config.py index aba7ad7b..ca021bf7 100644 --- a/splitio/models/fallback_config.py +++ b/splitio/models/fallback_config.py @@ -15,8 +15,8 @@ def __init__(self, global_fallback_treatment=None, by_flag_fallback_treatment=No :param by_flag_fallback_treatment: Dict of flags and their fallback treatment :type by_flag_fallback_treatment: {str: FallbackTreatment} """ - self._global_fallback_treatment = global_fallback_treatment - self._by_flag_fallback_treatment = by_flag_fallback_treatment + self._global_fallback_treatment = self._build_global_fallback(global_fallback_treatment) + self._by_flag_fallback_treatment = self._build_by_flag_fallback(by_flag_fallback_treatment) @property def global_fallback_treatment(self): @@ -37,7 +37,26 @@ def by_flag_fallback_treatment(self): def by_flag_fallback_treatment(self, new_value): """Set global fallback treatment.""" self.by_flag_fallback_treatment = new_value - + + def _build_global_fallback(self, global_fallback_treatment): + if isinstance(global_fallback_treatment, str): + return FallbackTreatment(global_fallback_treatment) + + return global_fallback_treatment + + def _build_by_flag_fallback(self, by_flag_fallback_treatment): + if not isinstance(by_flag_fallback_treatment, dict): + return by_flag_fallback_treatment + + parsed_by_flag_fallback = {} + for key, value in by_flag_fallback_treatment.items(): + if isinstance(value, str): + parsed_by_flag_fallback[key] = FallbackTreatment(value) + else: + parsed_by_flag_fallback[key] = value + + return parsed_by_flag_fallback + class FallbackTreatmentCalculator(object): """FallbackTreatmentCalculator object class.""" diff --git a/splitio/version.py b/splitio/version.py index 780d6251..ea7d787e 100644 --- a/splitio/version.py +++ b/splitio/version.py @@ -1 +1 @@ -__version__ = '10.5.0' \ No newline at end of file +__version__ = '10.5.1' \ No newline at end of file diff --git a/tests/integration/test_client_e2e.py b/tests/integration/test_client_e2e.py index 9e7c614e..194d86f1 100644 --- a/tests/integration/test_client_e2e.py +++ b/tests/integration/test_client_e2e.py @@ -1393,6 +1393,27 @@ def test_localhost_e2e(self): factory.destroy(event) event.wait() + def test_fallback_treatments(self): + """Instantiate a client with a JSON file and issue get_treatment() calls.""" + self._update_temp_file(splits_json['splitChange2_1']) + filename = os.path.join(os.path.dirname(__file__), 'files', 'split_changes_temp.json') + factory = get_factory('localhost', + config={ + 'splitFile': filename, + 'fallbackTreatments': FallbackTreatmentsConfiguration("on-global", {'fallback_feature': "on-local"}) + } + ) + factory.block_until_ready(1) + client = factory.client() + + assert client.get_treatment("key", "feature") == "on-global" + assert client.get_treatment("key", "fallback_feature") == "on-local" + + event = threading.Event() + factory.destroy(event) + event.wait() + + class PluggableIntegrationTests(object): """Pluggable storage-based integration tests.""" @@ -3335,6 +3356,23 @@ async def test_localhost_e2e(self): assert split.configs == {} await factory.destroy() + @pytest.mark.asyncio + async def test_fallback_treatments(self): + """Instantiate a client with a JSON file and issue get_treatment() calls.""" + self._update_temp_file(splits_json['splitChange2_1']) + filename = os.path.join(os.path.dirname(__file__), 'files', 'split_changes_temp.json') + factory = await get_factory_async('localhost', + config={ + 'splitFile': filename, + 'fallbackTreatments': FallbackTreatmentsConfiguration("on-global", {'fallback_feature': "on-local"}) + } + ) + await factory.block_until_ready(1) + client = factory.client() + + assert await client.get_treatment("key", "feature") == "on-global" + assert await client.get_treatment("key", "fallback_feature") == "on-local" + await factory.destroy() class PluggableIntegrationAsyncTests(object): """Pluggable storage-based integration tests.""" diff --git a/tests/models/test_fallback.py b/tests/models/test_fallback.py index 4dfdf79e..aadb6007 100644 --- a/tests/models/test_fallback.py +++ b/tests/models/test_fallback.py @@ -28,6 +28,13 @@ def test_working(self): fallback_config.by_flag_fallback_treatment["flag2"] = flag_fb assert fallback_config.by_flag_fallback_treatment == {"flag1": flag_fb, "flag2": flag_fb} + + fallback_config = FallbackTreatmentsConfiguration("on", {"flag1": "off"}) + assert isinstance(fallback_config.global_fallback_treatment, FallbackTreatment) + assert fallback_config.global_fallback_treatment.treatment == "on" + + assert isinstance(fallback_config.by_flag_fallback_treatment["flag1"], FallbackTreatment) + assert fallback_config.by_flag_fallback_treatment["flag1"].treatment == "off" class FallbackTreatmentCalculatorTests(object):