forked from Unleash/unleash-client-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathloader.py
170 lines (140 loc) Β· 5.53 KB
/
loader.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
from typing import Optional
from UnleashClient.cache import BaseCache
from UnleashClient.constants import FAILED_STRATEGIES, FEATURES_URL
from UnleashClient.features.Feature import Feature
from UnleashClient.utils import LOGGER
from UnleashClient.variants.Variants import Variants
# pylint: disable=broad-except
def _create_strategies(
provisioning: dict,
strategy_mapping: dict,
cache: BaseCache,
global_segments: Optional[dict],
) -> list:
feature_strategies = []
for strategy in provisioning["strategies"]:
try:
if "parameters" in strategy.keys():
strategy_provisioning = strategy["parameters"]
else:
strategy_provisioning = {}
if "constraints" in strategy.keys():
constraint_provisioning = strategy["constraints"]
else:
constraint_provisioning = {}
if "segments" in strategy.keys():
segment_provisioning = strategy["segments"]
else:
segment_provisioning = []
if "variants" in strategy.keys():
variant_provisioning = strategy["variants"]
else:
variant_provisioning = []
feature_strategies.append(
strategy_mapping[strategy["name"]](
constraints=constraint_provisioning,
variants=variant_provisioning,
parameters=strategy_provisioning,
global_segments=global_segments,
segment_ids=segment_provisioning,
)
)
except Exception as excep:
strategies = cache.get(FAILED_STRATEGIES, [])
if strategy["name"] not in strategies:
LOGGER.warning(
"Failed to load strategy. This may be a problem with a custom strategy. Exception: %s",
excep,
)
strategies.append(strategy["name"])
cache.set(FAILED_STRATEGIES, strategies)
return feature_strategies
def _create_feature(
provisioning: dict,
strategy_mapping: dict,
cache: BaseCache,
global_segments: Optional[dict],
) -> Feature:
if "strategies" in provisioning.keys():
parsed_strategies = _create_strategies(
provisioning, strategy_mapping, cache, global_segments
)
else:
parsed_strategies = []
if "variants" in provisioning:
variant = Variants(provisioning["variants"], provisioning["name"])
else:
variant = None
return Feature(
name=provisioning["name"],
enabled=provisioning["enabled"],
strategies=parsed_strategies,
variants=variant,
impression_data=provisioning.get("impressionData", False),
dependencies=provisioning.get("dependencies", []),
)
def load_features(
cache: BaseCache,
feature_toggles: dict,
strategy_mapping: dict,
global_segments: Optional[dict] = None,
) -> None:
"""
Caching
:param cache: Should be the cache class variable from UnleashClient
:param feature_toggles: Should be the features class variable from UnleashClient
:param strategy_mapping:
:return:
"""
# Pull raw provisioning from cache.
feature_provisioning = cache.get(FEATURES_URL)
if not feature_provisioning:
LOGGER.warning(
"Unleash client does not have cached features. "
"Please make sure client can communicate with Unleash server!"
)
return
# Parse provisioning
parsed_features = {}
feature_names = [d["name"] for d in feature_provisioning["features"]]
if "segments" in feature_provisioning.keys():
segments = feature_provisioning["segments"]
global_segments = {segment["id"]: segment for segment in segments}
else:
global_segments = {}
for provisioning in feature_provisioning["features"]:
parsed_features[provisioning["name"]] = provisioning
# Delete old features/cache
for feature in list(feature_toggles.keys()):
if feature not in feature_names:
del feature_toggles[feature]
# Update existing objects
for feature in feature_toggles.keys():
feature_for_update = feature_toggles[feature]
strategies = parsed_features[feature]["strategies"]
feature_for_update.enabled = parsed_features[feature]["enabled"]
if strategies:
parsed_strategies = _create_strategies(
parsed_features[feature], strategy_mapping, cache, global_segments
)
feature_for_update.strategies = parsed_strategies
if "variants" in parsed_features[feature]:
feature_for_update.variants = Variants(
parsed_features[feature]["variants"], parsed_features[feature]["name"]
)
feature_for_update.impression_data = parsed_features[feature].get(
"impressionData", False
)
feature_for_update.dependencies = parsed_features[feature].get(
"dependencies", []
)
# If the feature had previously been added to the features list only for
# tracking, indicate that it is now a real feature that should be
# evaluated properly.
feature_for_update.only_for_metrics = False
# Handle creation or deletions
new_features = list(set(feature_names) - set(feature_toggles.keys()))
for feature in new_features:
feature_toggles[feature] = _create_feature(
parsed_features[feature], strategy_mapping, cache, global_segments
)