Skip to content

Commit b00b128

Browse files
authored
Merge pull request #2 from featbit/feature/1.0.1
feature/1.0.1
2 parents 65a5255 + a04bb17 commit b00b128

File tree

11 files changed

+292
-348
lines changed

11 files changed

+292
-348
lines changed

fbclient/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from fbclient.event_processor import DefaultEventProcessor, NullEventProcessor
1414
from fbclient.event_types import FlagEvent, Metric, MetricEvent, UserEvent
1515
from fbclient.interfaces import DataUpdateStatusProvider
16-
from fbclient.status import DataUpdateStatusProviderIml
16+
from fbclient.status import DataUpdateStatusProviderImpl
1717
from fbclient.status_types import State
1818
from fbclient.streaming import Streaming, _data_to_dict
1919
from fbclient.update_processor import NullUpdateProcessor
@@ -79,7 +79,7 @@ def __init__(self, config: Config, start_wait: float = 15.):
7979
self._evaluator = Evaluator(lambda key: self._data_storage.get(FEATURE_FLAGS, key),
8080
lambda key: self._data_storage.get(SEGMENTS, key))
8181
# data updator and status provider
82-
self._update_status_provider = DataUpdateStatusProviderIml(config.data_storage)
82+
self._update_status_provider = DataUpdateStatusProviderImpl(config.data_storage)
8383
# update processor
8484
update_processor_ready = threading.Event()
8585
self._update_processor = self._build_update_processor(config, self._update_status_provider,

fbclient/common_types.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def __init__(self, key: Optional[str], name: Optional[str], **kwargs):
3838
self._customs = {}
3939
if len(kwargs) > 0:
4040
self._customs \
41-
.update(dict((k, str(v)) for k, v in kwargs.items() if isinstance(k, str) and k.lower() not in __BUILTINS_MAPING__.keys() and (isinstance(v, str) or is_numeric(v))))
41+
.update(dict((k, str(v)) for k, v in kwargs.items() if isinstance(k, str) and k.lower() not in __BUILTINS_MAPING__.keys()
42+
and (isinstance(v, str) or is_numeric(v) or isinstance(v, bool))))
4243

4344
@staticmethod
4445
def from_dict(user: Dict[str, Any]) -> "FBUser":

fbclient/evaluator.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import base64
21
import json
32
import re
4-
from typing import Callable, Iterable, Optional
3+
from typing import Callable, Optional
54

65
from fbclient.common_types import FBEvent, FBUser, _EvalResult
76
from fbclient.event_types import FlagEventVariation
@@ -67,6 +66,8 @@
6766

6867
__NOT_IN_SEGMENT_CLAUSE__ = 'User is not in segment'
6968

69+
__EXPT_KEY_PREFIX__ = "expt"
70+
7071

7172
class Evaluator:
7273
def __init__(self,
@@ -127,23 +128,19 @@ def _match_condition_user_variation(self, flag: dict, user: FBUser) -> Optional[
127128
for rule in flag['rules']:
128129
if self._match_any_rule(user, rule):
129130
return self._get_rollout_variation_option(flag,
130-
rule['variations'],
131+
rule,
131132
user,
132133
REASON_RULE_MATCH,
133-
flag['exptIncludeAllTargets'],
134-
rule['includedInExpt'],
135134
flag['key'],
136135
flag['name'])
137136
return None
138137

139138
# get value from default rule
140139
def _match_default_user_variation(self, flag: dict, user: FBUser) -> Optional[_EvalResult]:
141140
return self._get_rollout_variation_option(flag,
142-
flag['fallthrough']['variations'],
141+
flag['fallthrough'],
143142
user,
144143
REASON_FALLTHROUGH,
145-
flag['exptIncludeAllTargets'],
146-
flag['fallthrough']['includedInExpt'],
147144
flag['key'],
148145
flag['name'])
149146

@@ -264,15 +261,13 @@ def match_segment(user: FBUser, segment: Optional[dict]) -> bool:
264261

265262
def _get_rollout_variation_option(self,
266263
flag: dict,
267-
rollouts: Iterable[dict],
264+
rollout_variations: dict,
268265
user: FBUser,
269266
reason: str,
270-
expt_include_all_targets: bool,
271-
rule_inclued_in_expt: bool,
272267
key_name: str,
273268
name: str) -> Optional[_EvalResult]:
274269

275-
def is_send_to_expt(user_key: str,
270+
def is_send_to_expt(dispatch_key: str,
276271
rollout: dict,
277272
expt_include_all_targets: bool,
278273
rule_inclued_in_expt: bool) -> bool:
@@ -288,14 +283,16 @@ def is_send_to_expt(user_key: str,
288283
upper_bound = send_to_expt_percentage / splitting_percentage
289284
if upper_bound > 1:
290285
upper_bound = 1
291-
new_user_key = base64.b64encode(user_key.encode()).decode()
292-
return VariationSplittingAlgorithm(new_user_key, [0, upper_bound]).is_key_belongs_to_percentage()
286+
new_dispatch_key = "".join((__EXPT_KEY_PREFIX__, dispatch_key))
287+
return VariationSplittingAlgorithm(new_dispatch_key, [0, upper_bound]).is_key_belongs_to_percentage()
293288
return False
294289

295-
user_key = user.get('keyid')
296-
for rollout in rollouts:
297-
if VariationSplittingAlgorithm(user_key, rollout['rollout']).is_key_belongs_to_percentage(): # type: ignore
298-
send_to_expt = is_send_to_expt(user_key, rollout, expt_include_all_targets, rule_inclued_in_expt) # type: ignore
290+
dispatch_key = rollout_variations.get('dispatchKey')
291+
dispatch_key = dispatch_key if dispatch_key else 'keyid'
292+
dispatch_key_value = "".join((flag['key'], user.get(dispatch_key, ""))) # type: ignore
293+
for rollout in rollout_variations['variations']:
294+
if VariationSplittingAlgorithm(dispatch_key_value, rollout['rollout']).is_key_belongs_to_percentage(): # type: ignore
295+
send_to_expt = is_send_to_expt(dispatch_key_value, rollout, flag['exptIncludeAllTargets'], rollout_variations['includedInExpt']) # type: ignore
299296
return _EvalResult(rollout['id'],
300297
flag['variationMap'][rollout['id']],
301298
reason,

fbclient/status.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from fbclient.utils import log
1010

1111

12-
class DataUpdateStatusProviderIml(DataUpdateStatusProvider):
12+
class DataUpdateStatusProviderImpl(DataUpdateStatusProvider):
1313

1414
def __init__(self, storage: DataStorage):
1515
self.__storage = storage

fbclient/utils/__init__.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,15 @@ def cast_variation_by_flag_type(flag_type: Optional[str], variation: Optional[st
133133

134134

135135
def simple_type_inference(value: Any) -> Optional[str]:
136-
try:
137-
if isinstance(value, bool):
138-
return 'boolean'
139-
elif isinstance(value, str):
140-
return 'string'
141-
elif isinstance(value, Iterable) or isinstance(value, Mapping):
142-
return 'json'
143-
elif is_numeric(str(value)):
144-
return 'number'
145-
else:
146-
return None
147-
except:
136+
if isinstance(value, bool):
137+
return 'boolean'
138+
elif isinstance(value, str):
139+
return 'string'
140+
elif isinstance(value, Iterable) or isinstance(value, Mapping):
141+
return 'json'
142+
elif is_numeric(value):
143+
return 'number'
144+
elif value is None:
148145
return None
146+
else:
147+
raise ValueError("value type is not supported")

fbclient/utils/exceptions.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

fbclient/utils/variation_splitting_algorithm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ def is_key_belongs_to_percentage(self) -> bool:
2020
return False
2121

2222
def __percentage_of_key(self) -> float:
23-
digest = hashlib.md5(self.__key.encode(encoding='ascii')).digest()
23+
digest = hashlib.md5(self.__key.encode(encoding='utf-8')).digest()
2424
magic_num = int.from_bytes(digest[:4], byteorder='little', signed=True)
2525
return abs(magic_num / __MIN_INT__)

fbclient/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = "1.0.0"
1+
VERSION = "1.0.1"

0 commit comments

Comments
 (0)