Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
89597f8
Reduce log level for asyncio.CancelledError exceptions
chillaq Aug 20, 2025
cc56af8
Merge pull request #593 from splitio/FME-8450-lower-log-sse-renew
chillaq Aug 20, 2025
caacb33
Updated Config and input validator
chillaq Aug 25, 2025
d9bbce4
Added FallbackTreatmentsConfiguration class
chillaq Aug 26, 2025
5da06df
added label prefix
chillaq Aug 26, 2025
5811d9c
Updated evaluator
chillaq Aug 26, 2025
34f66ae
clean up client
chillaq Aug 26, 2025
50f5b76
Update client class
chillaq Aug 28, 2025
b7391b4
Update factory and tests
chillaq Aug 29, 2025
0cfb0ef
updated regex
chillaq Sep 2, 2025
52a2967
Removed FallbackConfig object and updated config parameter name
chillaq Sep 2, 2025
ba443e5
Merge pull request #594 from splitio/FME-9614-fallback-config-validator
chillaq Sep 2, 2025
714b4ba
updated evaluator
chillaq Sep 2, 2025
65b97e8
Merge pull request #595 from splitio/FME-9615-fallback-evaluator
chillaq Sep 2, 2025
44110b0
polishing
chillaq Sep 2, 2025
c1fdc5f
Merge branch 'feature/fallback-treatment' into FME-9616-fallback-client
chillaq Sep 2, 2025
48e2aa9
Merge pull request #596 from splitio/FME-9616-fallback-client
chillaq Sep 2, 2025
48c3084
Added fallback calculator
chillaq Sep 10, 2025
02484d9
Merge pull request #597 from splitio/fallback-calculator
chillaq Sep 10, 2025
f3d1065
deprecate redis errors param
chillaq Sep 10, 2025
5e17009
polish
chillaq Sep 10, 2025
6b02164
polish
chillaq Sep 10, 2025
4fe9854
Restrict redis lib to below 7.0.0
chillaq Sep 10, 2025
210405b
Merge pull request #598 from splitio/deprecate-redis-errors
chillaq Sep 11, 2025
9685012
Updated version and changes
chillaq Sep 12, 2025
7c577f5
Merge pull request #599 from splitio/FME-9762-changes
chillaq Sep 12, 2025
392fa24
Merge branch 'development' into feature/fallback-treatment
chillaq Sep 12, 2025
0451cb1
polish tests
chillaq Sep 12, 2025
bfe6ee7
update tests
chillaq Sep 12, 2025
13edab5
update test
chillaq Sep 12, 2025
bcd67de
fix tests
chillaq Sep 15, 2025
6f2d224
update test
chillaq Sep 15, 2025
c838083
update test
chillaq Sep 15, 2025
0e2f13c
updated changes
chillaq Sep 15, 2025
1226d2b
polishing
chillaq Sep 15, 2025
3c99066
Merge pull request #600 from splitio/feature/fallback-treatment
chillaq Sep 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added FallbackTreatmentsConfiguration class
  • Loading branch information
chillaq committed Aug 26, 2025
commit d9bbce485fb84e376faa57cde473d37d1b87d4e2
57 changes: 34 additions & 23 deletions splitio/client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from splitio.engine.impressions import ImpressionsMode
from splitio.client.input_validator import validate_flag_sets, validate_fallback_treatment, validate_regex_name
from splitio.models.fallback_config import FallbackConfig
from splitio.models.fallback_config import FallbackConfig, FallbackTreatmentsConfiguration

_LOGGER = logging.getLogger(__name__)
DEFAULT_DATA_SAMPLING = 1
Expand Down Expand Up @@ -71,7 +71,7 @@ class AuthenticateScheme(Enum):
'httpAuthenticateScheme': AuthenticateScheme.NONE,
'kerberosPrincipalUser': None,
'kerberosPrincipalPassword': None,
'fallbackConfig': FallbackConfig(None, None)
'fallbackTreatmentsConfiguration': FallbackTreatmentsConfiguration(None)
}

def _parse_operation_mode(sdk_key, config):
Expand Down Expand Up @@ -170,26 +170,37 @@ def sanitize(sdk_key, config):
' Defaulting to `none` mode.')
processed["httpAuthenticateScheme"] = authenticate_scheme

if config.get('fallbackConfig') is not None:
if not isinstance(config['fallbackConfig'], FallbackConfig):
_LOGGER.warning('Config: fallbackConfig parameter should be of `FallbackConfig` structure.')
processed['fallbackConfig'] = FallbackConfig(None, None)
return processed

if config['fallbackConfig'].global_fallback_treatment is not None and not validate_fallback_treatment(config['fallbackConfig'].global_fallback_treatment):
_LOGGER.warning('Config: global fallbacktreatment parameter is discarded.')
processed['fallbackConfig'].global_fallback_treatment = None
return processed

if config['fallbackConfig'].by_flag_fallback_treatment is not None:
sanitized_flag_fallback_treatments = {}
for feature_name in config['fallbackConfig'].by_flag_fallback_treatment.keys():
if not validate_regex_name(feature_name) or not validate_fallback_treatment(config['fallbackConfig'].by_flag_fallback_treatment[feature_name]):
_LOGGER.warning('Config: fallback treatment parameter for feature flag %s is discarded.', feature_name)
continue

sanitized_flag_fallback_treatments[feature_name] = config['fallbackConfig'].by_flag_fallback_treatment[feature_name]

processed['fallbackConfig'] = FallbackConfig(config['fallbackConfig'].global_fallback_treatment, sanitized_flag_fallback_treatments)
processed = _sanitize_fallback_config(config, processed)

return processed

def _sanitize_fallback_config(config, processed):
if config.get('fallbackTreatmentsConfiguration') is not None:
if not isinstance(config['fallbackTreatmentsConfiguration'], FallbackTreatmentsConfiguration):
_LOGGER.warning('Config: fallbackTreatmentsConfiguration parameter should be of `FallbackTreatmentsConfiguration` class.')
processed['fallbackTreatmentsConfiguration'] = FallbackTreatmentsConfiguration(None)
return processed

if config['fallbackTreatmentsConfiguration'].fallback_config != None:
if not isinstance(config['fallbackTreatmentsConfiguration'].fallback_config, FallbackConfig):
_LOGGER.warning('Config: fallback_config parameter should be of `FallbackConfig` class.')
processed['fallbackTreatmentsConfiguration'].fallback_config = FallbackConfig(None, None)
return processed

if config['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment is not None and not validate_fallback_treatment(config['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment):
_LOGGER.warning('Config: global fallbacktreatment parameter is discarded.')
processed['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment = None
return processed

if config['fallbackTreatmentsConfiguration'].fallback_config.by_flag_fallback_treatment is not None:
sanitized_flag_fallback_treatments = {}
for feature_name in config['fallbackTreatmentsConfiguration'].fallback_config.by_flag_fallback_treatment.keys():
if not validate_regex_name(feature_name) or not validate_fallback_treatment(config['fallbackTreatmentsConfiguration'].fallback_config.by_flag_fallback_treatment[feature_name]):
_LOGGER.warning('Config: fallback treatment parameter for feature flag %s is discarded.', feature_name)
continue

sanitized_flag_fallback_treatments[feature_name] = config['fallbackTreatmentsConfiguration'].fallback_config.by_flag_fallback_treatment[feature_name]

processed['fallbackTreatmentsConfiguration'].fallback_config = FallbackConfig(config['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment, sanitized_flag_fallback_treatments)

return processed
31 changes: 28 additions & 3 deletions splitio/models/fallback_config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
"""Segment module."""

class FallbackTreatmentsConfiguration(object):
"""FallbackConfiguration object class."""

def __init__(self, fallback_config):
"""
Class constructor.

:param fallback_config: fallback config object.
:type fallback_config: FallbackConfig

:param by_flag_fallback_treatment: Dict of flags and their fallback treatment
:type by_flag_fallback_treatment: {str: FallbackTreatment}
"""
self._fallback_config = fallback_config

@property
def fallback_config(self):
"""Return fallback config."""
return self._fallback_config

@fallback_config.setter
def fallback_config(self, new_value):
"""Set fallback config."""
self._fallback_config = new_value

class FallbackConfig(object):
"""Segment object class."""
"""FallbackConfig object class."""

def __init__(self, global_fallback_treatment=None, by_flag_fallback_treatment=None):
"""
Expand All @@ -23,7 +48,7 @@ def global_fallback_treatment(self):

@global_fallback_treatment.setter
def global_fallback_treatment(self, new_value):
"""Return global fallback treatment."""
"""Set global fallback treatment."""
self._global_fallback_treatment = new_value

@property
Expand All @@ -33,5 +58,5 @@ def by_flag_fallback_treatment(self):

@by_flag_fallback_treatment.setter
def by_flag_fallback_treatment(self, new_value):
"""Return global fallback treatment."""
"""Set global fallback treatment."""
self.by_flag_fallback_treatment = new_value
40 changes: 22 additions & 18 deletions tests/client/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from splitio.client import config
from splitio.engine.impressions.impressions import ImpressionsMode
from splitio.models.fallback_treatment import FallbackTreatment
from splitio.models.fallback_config import FallbackConfig
from splitio.models.fallback_config import FallbackConfig, FallbackTreatmentsConfiguration

class ConfigSanitizationTests(object):
"""Inmemory storage-based integration tests."""
Expand Down Expand Up @@ -92,28 +92,32 @@ def test_sanitize(self, mocker):
assert processed['httpAuthenticateScheme'] is config.AuthenticateScheme.NONE

_logger.reset_mock()
processed = config.sanitize('some', {'fallbackConfig': 'NONE'})
assert processed['fallbackConfig'].global_fallback_treatment == None
assert processed['fallbackConfig'].by_flag_fallback_treatment == None
assert _logger.warning.mock_calls[1] == mocker.call("Config: fallbackConfig parameter should be of `FallbackConfig` structure.")
processed = config.sanitize('some', {'fallbackTreatmentsConfiguration': 'NONE'})
assert processed['fallbackTreatmentsConfiguration'].fallback_config == None
assert _logger.warning.mock_calls[1] == mocker.call("Config: fallbackTreatmentsConfiguration parameter should be of `FallbackTreatmentsConfiguration` class.")

_logger.reset_mock()
processed = config.sanitize('some', {'fallbackConfig': FallbackConfig(FallbackTreatment("123"))})
assert processed['fallbackConfig'].global_fallback_treatment == None
processed = config.sanitize('some', {'fallbackTreatmentsConfiguration': FallbackTreatmentsConfiguration(123)})
assert processed['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment == None
assert _logger.warning.mock_calls[1] == mocker.call("Config: fallback_config parameter should be of `FallbackConfig` class.")

_logger.reset_mock()
processed = config.sanitize('some', {'fallbackTreatmentsConfiguration': FallbackTreatmentsConfiguration(FallbackConfig(FallbackTreatment("123")))})
assert processed['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment == None
assert _logger.warning.mock_calls[1] == mocker.call("Config: global fallbacktreatment parameter is discarded.")

fb = FallbackConfig(FallbackTreatment('on'))
processed = config.sanitize('some', {'fallbackConfig': fb})
assert processed['fallbackConfig'].global_fallback_treatment.treatment == fb.global_fallback_treatment.treatment
fb = FallbackTreatmentsConfiguration(FallbackConfig(FallbackTreatment('on')))
processed = config.sanitize('some', {'fallbackTreatmentsConfiguration': fb})
assert processed['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment.treatment == fb.fallback_config.global_fallback_treatment.treatment

fb = FallbackConfig(FallbackTreatment('on'), {"flag": FallbackTreatment("off")})
processed = config.sanitize('some', {'fallbackConfig': fb})
assert processed['fallbackConfig'].global_fallback_treatment.treatment == fb.global_fallback_treatment.treatment
assert processed['fallbackConfig'].by_flag_fallback_treatment["flag"] == fb.by_flag_fallback_treatment["flag"]
fb = FallbackTreatmentsConfiguration(FallbackConfig(FallbackTreatment('on'), {"flag": FallbackTreatment("off")}))
processed = config.sanitize('some', {'fallbackTreatmentsConfiguration': fb})
assert processed['fallbackTreatmentsConfiguration'].fallback_config.global_fallback_treatment.treatment == fb.fallback_config.global_fallback_treatment.treatment
assert processed['fallbackTreatmentsConfiguration'].fallback_config.by_flag_fallback_treatment["flag"] == fb.fallback_config.by_flag_fallback_treatment["flag"]

_logger.reset_mock()
fb = FallbackConfig(None, {"flag#%": FallbackTreatment("off"), "flag2": FallbackTreatment("on")})
processed = config.sanitize('some', {'fallbackConfig': fb})
assert len(processed['fallbackConfig'].by_flag_fallback_treatment) == 1
assert processed['fallbackConfig'].by_flag_fallback_treatment.get("flag2") == fb.by_flag_fallback_treatment["flag2"]
fb = FallbackTreatmentsConfiguration(FallbackConfig(None, {"flag#%": FallbackTreatment("off"), "flag2": FallbackTreatment("on")}))
processed = config.sanitize('some', {'fallbackTreatmentsConfiguration': fb})
assert len(processed['fallbackTreatmentsConfiguration'].fallback_config.by_flag_fallback_treatment) == 1
assert processed['fallbackTreatmentsConfiguration'].fallback_config.by_flag_fallback_treatment.get("flag2") == fb.fallback_config.by_flag_fallback_treatment["flag2"]
assert _logger.warning.mock_calls[1] == mocker.call('Config: fallback treatment parameter for feature flag %s is discarded.', 'flag#%')