Skip to content

Commit 90ef85f

Browse files
committed
Added EvaluationOption tuple class
1 parent 81780a4 commit 90ef85f

File tree

4 files changed

+54
-53
lines changed

4 files changed

+54
-53
lines changed

splitio/client/client.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""A module for Split.io SDK API clients."""
22
import logging
33
import json
4+
from collections import namedtuple
45

56
from splitio.engine.evaluator import Evaluator, CONTROL, EvaluationDataFactory, AsyncEvaluationDataFactory
67
from splitio.engine.splitters import Splitter
@@ -12,6 +13,7 @@
1213

1314

1415
_LOGGER = logging.getLogger(__name__)
16+
EvaluationOptions = namedtuple('EvaluationOptions', ['properties'])
1517

1618

1719
class ClientBase(object): # pylint: disable=too-many-instance-attributes
@@ -124,10 +126,11 @@ def _validate_treatment_options(method_name, evaluation_options=None):
124126
if evaluation_options == None:
125127
return None
126128

127-
if evaluation_options["properties"] is not None:
128-
valid, evaluation_options["properties"], size = input_validator.valid_properties(evaluation_options["properties"], method_name)
129+
if evaluation_options.properties is not None:
130+
valid, properties, size = input_validator.valid_properties(evaluation_options.properties, method_name)
129131
if not valid:
130-
evaluation_options["properties"] = None
132+
evaluation_options = EvaluationOptions(None)
133+
evaluation_options = EvaluationOptions(properties)
131134
return evaluation_options
132135

133136
def _build_impression(self, key, bucketing, feature, result, properties=None):
@@ -198,7 +201,7 @@ def _validate_track(self, key, traffic_type, event_type, value=None, properties=
198201
return True, event, size
199202

200203
def _get_properties(self, evaluation_options):
201-
return evaluation_options["properties"] if evaluation_options != None and evaluation_options.get("properties") != None else None
204+
return evaluation_options.properties if evaluation_options != None else None
202205

203206

204207
class Client(ClientBase): # pylint: disable=too-many-instance-attributes

splitio/client/input_validator.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import inspect
77

88
from splitio.client.key import Key
9+
from splitio.client import client
910
from splitio.engine.evaluator import CONTROL
1011

1112

@@ -542,12 +543,8 @@ def validate_evaluation_options(evaluation_options, method_name):
542543
if evaluation_options == None:
543544
return None
544545

545-
if not isinstance(evaluation_options, dict):
546-
_LOGGER.error("%s: evaluaiton option should be dictionary, setting its value to None.", method_name)
547-
return None
548-
549-
if evaluation_options.get("properties") == None:
550-
_LOGGER.error("%s: evaluaiton option must have `properties` key, setting its value to None.", method_name)
546+
if not isinstance(evaluation_options, client.EvaluationOptions):
547+
_LOGGER.error("%s: evaluaiton option should be an instance of EvaluationOptions, setting its value to None.", method_name)
551548
return None
552549

553550
return evaluation_options

tests/client/test_client.py

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import time
88
import pytest
99

10-
from splitio.client.client import Client, _LOGGER as _logger, CONTROL, ClientAsync
10+
from splitio.client.client import Client, _LOGGER as _logger, CONTROL, ClientAsync, EvaluationOptions
1111
from splitio.client.factory import SplitFactory, Status as FactoryStatus, SplitFactoryAsync
1212
from splitio.models.impressions import Impression, Label
1313
from splitio.models.events import Event, EventWrapper
@@ -1327,52 +1327,52 @@ def synchronize_config(*_):
13271327

13281328
_logger = mocker.Mock()
13291329
mocker.patch('splitio.client.input_validator._LOGGER', new=_logger)
1330-
assert client.get_treatment('some_key', 'SPLIT_2', evaluation_options={"properties":{"prop": "value"}}) == 'on'
1330+
assert client.get_treatment('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions({"prop": "value"})) == 'on'
13311331
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13321332

1333-
assert client.get_treatment('some_key', 'SPLIT_2', evaluation_options=12) == 'on'
1333+
assert client.get_treatment('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions(12)) == 'on'
13341334
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, None)]
1335-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatment')]
1335+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatment')]
13361336

13371337
_logger.reset_mock()
1338-
assert client.get_treatment('some_key', 'SPLIT_2', evaluation_options='12') == 'on'
1338+
assert client.get_treatment('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions('12')) == 'on'
13391339
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
1340-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatment')]
1340+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatment')]
13411341

1342-
_logger.reset_mock()
1343-
assert client.get_treatment('some_key', 'SPLIT_2', evaluation_options={"property":{"prop": "value"}}) == 'on'
1344-
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
1345-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option must have `properties` key, setting its value to None.', 'get_treatment')]
1346-
1347-
assert client.get_treatment_with_config('some_key', 'SPLIT_2', evaluation_options={"properties":{"prop": "value"}}) == ('on', None)
1342+
assert client.get_treatment_with_config('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions({"prop": "value"})) == ('on', None)
13481343
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13491344

1350-
assert client.get_treatments('some_key', ['SPLIT_2'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': 'on'}
1345+
assert client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': 'on'}
13511346
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13521347

13531348
_logger.reset_mock()
1354-
assert client.get_treatments('some_key', ['SPLIT_2'], evaluation_options="prop") == {'SPLIT_2': 'on'}
1349+
assert client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions("prop")) == {'SPLIT_2': 'on'}
1350+
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
1351+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatments')]
1352+
1353+
_logger.reset_mock()
1354+
assert client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions(123)) == {'SPLIT_2': 'on'}
13551355
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
1356-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatments')]
1356+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatments')]
13571357

13581358
_logger.reset_mock()
13591359
assert client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=123) == {'SPLIT_2': 'on'}
13601360
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
1361-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatments')]
1361+
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be an instance of EvaluationOptions, setting its value to None.', 'get_treatments')]
13621362

1363-
assert client.get_treatments_with_config('some_key', ['SPLIT_2'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': ('on', None)}
1363+
assert client.get_treatments_with_config('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': ('on', None)}
13641364
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13651365

1366-
assert client.get_treatments_by_flag_set('some_key', 'set_1', evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': 'on'}
1366+
assert client.get_treatments_by_flag_set('some_key', 'set_1', evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': 'on'}
13671367
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13681368

1369-
assert client.get_treatments_by_flag_sets('some_key', ['set_1'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': 'on'}
1369+
assert client.get_treatments_by_flag_sets('some_key', ['set_1'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': 'on'}
13701370
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13711371

1372-
assert client.get_treatments_with_config_by_flag_set('some_key', 'set_1', evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': ('on', None)}
1372+
assert client.get_treatments_with_config_by_flag_set('some_key', 'set_1', evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': ('on', None)}
13731373
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13741374

1375-
assert client.get_treatments_with_config_by_flag_sets('some_key', ['set_1'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': ('on', None)}
1375+
assert client.get_treatments_with_config_by_flag_sets('some_key', ['set_1'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': ('on', None)}
13761376
assert impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
13771377

13781378
class ClientAsyncTests(object): # pylint: disable=too-few-public-methods
@@ -2538,50 +2538,50 @@ async def synchronize_config(*_):
25382538

25392539
_logger = mocker.Mock()
25402540
mocker.patch('splitio.client.input_validator._LOGGER', new=_logger)
2541-
assert await client.get_treatment('some_key', 'SPLIT_2', evaluation_options={"properties":{"prop": "value"}}) == 'on'
2541+
assert await client.get_treatment('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions({"prop": "value"})) == 'on'
25422542
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
25432543

2544-
assert await client.get_treatment('some_key', 'SPLIT_2', evaluation_options=12) == 'on'
2544+
assert await client.get_treatment('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions(12)) == 'on'
25452545
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, None)]
2546-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatment')]
2546+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatment')]
25472547

25482548
_logger.reset_mock()
2549-
assert await client.get_treatment('some_key', 'SPLIT_2', evaluation_options='12') == 'on'
2549+
assert await client.get_treatment('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions('12')) == 'on'
25502550
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
2551-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatment')]
2551+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatment')]
25522552

2553-
_logger.reset_mock()
2554-
assert await client.get_treatment('some_key', 'SPLIT_2', evaluation_options={"property":{"prop": "value"}}) == 'on'
2555-
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
2556-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option must have `properties` key, setting its value to None.', 'get_treatment')]
2557-
2558-
assert await client.get_treatment_with_config('some_key', 'SPLIT_2', evaluation_options={"properties":{"prop": "value"}}) == ('on', None)
2553+
assert await client.get_treatment_with_config('some_key', 'SPLIT_2', evaluation_options=EvaluationOptions({"prop": "value"})) == ('on', None)
25592554
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
25602555

2561-
assert await client.get_treatments('some_key', ['SPLIT_2'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': 'on'}
2556+
assert await client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': 'on'}
25622557
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
25632558

25642559
_logger.reset_mock()
2565-
assert await client.get_treatments('some_key', ['SPLIT_2'], evaluation_options="prop") == {'SPLIT_2': 'on'}
2560+
assert await client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions("prop")) == {'SPLIT_2': 'on'}
2561+
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
2562+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatments')]
2563+
2564+
_logger.reset_mock()
2565+
assert await client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions(123)) == {'SPLIT_2': 'on'}
25662566
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
2567-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatments')]
2567+
assert _logger.error.mock_calls == [mocker.call('%s: properties must be of type dictionary.', 'get_treatments')]
25682568

25692569
_logger.reset_mock()
25702570
assert await client.get_treatments('some_key', ['SPLIT_2'], evaluation_options=123) == {'SPLIT_2': 'on'}
25712571
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, 1000, None)]
2572-
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be dictionary, setting its value to None.', 'get_treatments')]
2572+
assert _logger.error.mock_calls == [mocker.call('%s: evaluaiton option should be an instance of EvaluationOptions, setting its value to None.', 'get_treatments')]
25732573

2574-
assert await client.get_treatments_with_config('some_key', ['SPLIT_2'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': ('on', None)}
2574+
assert await client.get_treatments_with_config('some_key', ['SPLIT_2'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': ('on', None)}
25752575
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
25762576

2577-
assert await client.get_treatments_by_flag_set('some_key', 'set_1', evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': 'on'}
2577+
assert await client.get_treatments_by_flag_set('some_key', 'set_1', evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': 'on'}
25782578
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
25792579

2580-
assert await client.get_treatments_by_flag_sets('some_key', ['set_1'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': 'on'}
2580+
assert await client.get_treatments_by_flag_sets('some_key', ['set_1'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': 'on'}
25812581
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
25822582

2583-
assert await client.get_treatments_with_config_by_flag_set('some_key', 'set_1', evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': ('on', None)}
2583+
assert await client.get_treatments_with_config_by_flag_set('some_key', 'set_1', evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': ('on', None)}
25842584
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]
25852585

2586-
assert await client.get_treatments_with_config_by_flag_sets('some_key', ['set_1'], evaluation_options={"properties":{"prop": "value"}}) == {'SPLIT_2': ('on', None)}
2586+
assert await client.get_treatments_with_config_by_flag_sets('some_key', ['set_1'], evaluation_options=EvaluationOptions({"prop": "value"})) == {'SPLIT_2': ('on', None)}
25872587
assert await impression_storage.pop_many(100) == [Impression('some_key', 'SPLIT_2', 'on', 'some_label', 123, None, 1000, None, '{"prop": "value"}')]

tests/integration/test_client_e2e.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from splitio.exceptions import TimeoutException
1414
from splitio.client.factory import get_factory, SplitFactory, get_factory_async, SplitFactoryAsync
1515
from splitio.client.util import SdkMetadata
16+
from splitio.client.config import DEFAULT_CONFIG
17+
from splitio.client.client import EvaluationOptions
1618
from splitio.storage.inmemmory import InMemoryEventStorage, InMemoryImpressionStorage, \
1719
InMemorySegmentStorage, InMemorySplitStorage, InMemoryTelemetryStorage, InMemorySplitStorageAsync,\
1820
InMemoryEventStorageAsync, InMemoryImpressionStorageAsync, InMemorySegmentStorageAsync, \
@@ -35,7 +37,6 @@
3537
from splitio.engine.impressions.manager import Counter as ImpressionsCounter
3638
from splitio.engine.impressions.unique_keys_tracker import UniqueKeysTracker, UniqueKeysTrackerAsync
3739
from splitio.recorder.recorder import StandardRecorder, PipelinedRecorder, StandardRecorderAsync, PipelinedRecorderAsync
38-
from splitio.client.config import DEFAULT_CONFIG
3940
from splitio.sync.synchronizer import SplitTasks, SplitSynchronizers, Synchronizer, RedisSynchronizer, SynchronizerAsync,\
4041
RedisSynchronizerAsync
4142
from splitio.sync.manager import Manager, RedisManager, ManagerAsync, RedisManagerAsync
@@ -122,7 +123,7 @@ def _get_treatment(factory, skip_rbs=False):
122123
except:
123124
pass
124125

125-
assert client.get_treatment('user1', 'sample_feature', evaluation_options={"properties":{"prop": "value"}}) == 'on'
126+
assert client.get_treatment('user1', 'sample_feature', evaluation_options=EvaluationOptions({"prop": "value"})) == 'on'
126127
if not isinstance(factory._recorder._impressions_manager._strategy, StrategyNoneMode):
127128
_validate_last_impressions(client, ('sample_feature', 'user1', 'on', '{"prop": "value"}'))
128129

0 commit comments

Comments
 (0)