growthbook 2.1.1__py2.py3-none-any.whl → 2.1.3__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
growthbook/__init__.py CHANGED
@@ -18,5 +18,5 @@ from .plugins import (
18
18
  )
19
19
 
20
20
  # x-release-please-start-version
21
- __version__ = "2.1.1"
21
+ __version__ = "2.1.3"
22
22
  # x-release-please-end
growthbook/core.py CHANGED
@@ -50,47 +50,48 @@ def isOperatorObject(obj: Any) -> bool:
50
50
  return False
51
51
  return True
52
52
 
53
- def getType(attributeValue) -> str:
54
- t = type(attributeValue)
53
+ def _is_numeric(v: Any) -> bool:
54
+ return isinstance(v, (int, float)) and not isinstance(v, bool)
55
55
 
56
+ def getType(attributeValue) -> str:
56
57
  if attributeValue is None:
57
58
  return "null"
58
- if t is int or t is float:
59
+ if isinstance(attributeValue, bool):
60
+ return "boolean"
61
+ if _is_numeric(attributeValue):
59
62
  return "number"
60
- if t is str:
63
+ if isinstance(attributeValue, str):
61
64
  return "string"
62
- if t is list or t is set:
65
+ if isinstance(attributeValue, (list, set)):
63
66
  return "array"
64
- if t is dict:
67
+ if isinstance(attributeValue, dict):
65
68
  return "object"
66
- if t is bool:
67
- return "boolean"
68
69
  return "unknown"
69
70
 
70
71
  def getPath(attributes, path):
71
72
  current = attributes
72
73
  for segment in path.split("."):
73
- if type(current) is dict and segment in current:
74
+ if isinstance(current, dict) and segment in current:
74
75
  current = current[segment]
75
76
  else:
76
77
  return None
77
78
  return current
78
79
 
79
80
  def evalConditionValue(conditionValue, attributeValue, savedGroups, insensitive: bool = False) -> bool:
80
- if type(conditionValue) is dict and isOperatorObject(conditionValue):
81
+ if isinstance(conditionValue, dict) and isOperatorObject(conditionValue):
81
82
  for key, value in conditionValue.items():
82
83
  if not evalOperatorCondition(key, attributeValue, value, savedGroups):
83
84
  return False
84
85
  return True
85
86
 
86
87
  # Simple equality comparison with optional case-insensitivity
87
- if insensitive and type(conditionValue) is str and type(attributeValue) is str:
88
+ if insensitive and isinstance(conditionValue, str) and isinstance(attributeValue, str):
88
89
  return conditionValue.lower() == attributeValue.lower()
89
90
 
90
91
  return bool(conditionValue == attributeValue)
91
92
 
92
93
  def elemMatch(condition, attributeValue, savedGroups) -> bool:
93
- if not type(attributeValue) is list:
94
+ if not isinstance(attributeValue, list):
94
95
  return False
95
96
 
96
97
  for item in attributeValue:
@@ -104,13 +105,13 @@ def elemMatch(condition, attributeValue, savedGroups) -> bool:
104
105
  return False
105
106
 
106
107
  def compare(val1, val2) -> int:
107
- if (type(val1) is int or type(val1) is float) and not (type(val2) is int or type(val2) is float):
108
+ if _is_numeric(val1) and not _is_numeric(val2):
108
109
  if (val2 is None):
109
110
  val2 = 0
110
111
  else:
111
112
  val2 = float(val2)
112
113
 
113
- if (type(val2) is int or type(val2) is float) and not (type(val1) is int or type(val1) is float):
114
+ if _is_numeric(val2) and not _is_numeric(val1):
114
115
  if (val1 is None):
115
116
  val1 = 0
116
117
  else:
@@ -166,13 +167,13 @@ def evalOperatorCondition(operator, attributeValue, conditionValue, savedGroups)
166
167
  elif operator == "$vgte":
167
168
  return paddedVersionString(attributeValue) >= paddedVersionString(conditionValue)
168
169
  elif operator == "$inGroup":
169
- if not type(conditionValue) is str:
170
+ if not isinstance(conditionValue, str):
170
171
  return False
171
172
  if not conditionValue in savedGroups:
172
173
  return False
173
174
  return isIn(savedGroups[conditionValue] or [], attributeValue)
174
175
  elif operator == "$notInGroup":
175
- if not type(conditionValue) is str:
176
+ if not isinstance(conditionValue, str):
176
177
  return False
177
178
  if not conditionValue in savedGroups:
178
179
  return True
@@ -202,33 +203,33 @@ def evalOperatorCondition(operator, attributeValue, conditionValue, savedGroups)
202
203
  except Exception:
203
204
  return False
204
205
  elif operator == "$in":
205
- if not type(conditionValue) is list:
206
+ if not isinstance(conditionValue, list):
206
207
  return False
207
208
  return isIn(conditionValue, attributeValue)
208
209
  elif operator == "$nin":
209
- if not type(conditionValue) is list:
210
+ if not isinstance(conditionValue, list):
210
211
  return False
211
212
  return not isIn(conditionValue, attributeValue)
212
213
  elif operator == "$ini":
213
- if not type(conditionValue) is list:
214
+ if not isinstance(conditionValue, list):
214
215
  return False
215
216
  return isIn(conditionValue, attributeValue, insensitive=True)
216
217
  elif operator == "$nini":
217
- if not type(conditionValue) is list:
218
+ if not isinstance(conditionValue, list):
218
219
  return False
219
220
  return not isIn(conditionValue, attributeValue, insensitive=True)
220
221
  elif operator == "$elemMatch":
221
222
  return elemMatch(conditionValue, attributeValue, savedGroups)
222
223
  elif operator == "$size":
223
- if not (type(attributeValue) is list):
224
+ if not isinstance(attributeValue, list):
224
225
  return False
225
226
  return evalConditionValue(conditionValue, len(attributeValue), savedGroups)
226
227
  elif operator == "$all":
227
- if not type(conditionValue) is list:
228
+ if not isinstance(conditionValue, list):
228
229
  return False
229
230
  return isInAll(conditionValue, attributeValue, savedGroups, insensitive=False)
230
231
  elif operator == "$alli":
231
- if not type(conditionValue) is list:
232
+ if not isinstance(conditionValue, list):
232
233
  return False
233
234
  return isInAll(conditionValue, attributeValue, savedGroups, insensitive=True)
234
235
  elif operator == "$exists":
@@ -243,10 +244,10 @@ def evalOperatorCondition(operator, attributeValue, conditionValue, savedGroups)
243
244
 
244
245
  def paddedVersionString(input) -> str:
245
246
  # If input is a number, convert to a string
246
- if type(input) is int or type(input) is float:
247
+ if _is_numeric(input):
247
248
  input = str(input)
248
249
 
249
- if not input or type(input) is not str:
250
+ if not input or not isinstance(input, str):
250
251
  input = "0"
251
252
 
252
253
  # Remove build info and leading `v` if any
@@ -268,10 +269,10 @@ def isIn(conditionValue, attributeValue, insensitive: bool = False) -> bool:
268
269
  if insensitive:
269
270
  # Helper function to case-fold values (lowercase for strings)
270
271
  def case_fold(val):
271
- return val.lower() if type(val) is str else val
272
+ return val.lower() if isinstance(val, str) else val
272
273
 
273
274
  # Do an intersection if attribute is an array (insensitive)
274
- if type(attributeValue) is list:
275
+ if isinstance(attributeValue, list):
275
276
  return any(
276
277
  case_fold(el) == case_fold(exp)
277
278
  for el in attributeValue
@@ -280,13 +281,13 @@ def isIn(conditionValue, attributeValue, insensitive: bool = False) -> bool:
280
281
  return any(case_fold(attributeValue) == case_fold(exp) for exp in conditionValue)
281
282
 
282
283
  # Case-sensitive behavior (original)
283
- if type(attributeValue) is list:
284
+ if isinstance(attributeValue, list):
284
285
  return bool(set(conditionValue) & set(attributeValue))
285
286
  return attributeValue in conditionValue
286
287
 
287
288
  def isInAll(conditionValue, attributeValue, savedGroups, insensitive: bool = False) -> bool:
288
289
  """Check if attributeValue (array) contains all elements in conditionValue"""
289
- if not type(attributeValue) is list:
290
+ if not isinstance(attributeValue, list):
290
291
  return False
291
292
 
292
293
  for cond in conditionValue:
@@ -90,8 +90,8 @@ class FeatureCache:
90
90
  def update(self, features: Dict[str, Any], saved_groups: Dict[str, Any]) -> None:
91
91
  """Simple thread-safe update of cache with new API data"""
92
92
  with self._lock:
93
- self._cache['features'].update(features)
94
- self._cache['savedGroups'].update(saved_groups)
93
+ self._cache['features'] = dict(features)
94
+ self._cache['savedGroups'] = dict(saved_groups)
95
95
 
96
96
  def get_current_state(self) -> Dict[str, Any]:
97
97
  """Get current cache state"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: growthbook
3
- Version: 2.1.1
3
+ Version: 2.1.3
4
4
  Summary: Powerful Feature flagging and A/B testing for Python apps
5
5
  Home-page: https://github.com/growthbook/growthbook-python
6
6
  Author: GrowthBook
@@ -1,15 +1,15 @@
1
- growthbook/__init__.py,sha256=fGRXWdeBsaPrFwuv84wVuuuafTILYbkv7EwyR9yKqa4,444
1
+ growthbook/__init__.py,sha256=Ruoqw2MnuEXLWduM7wtAINQjemYc3AEzdtGUSXGthWA,444
2
2
  growthbook/common_types.py,sha256=YKUmmYfzgrzLQ7kp2IPLc8QBA-B0QbnbF5viekNiTpw,15703
3
- growthbook/core.py,sha256=f23Dzo5itM3xK6WevkjllJ5rg1h8DgGuqWtldBOjpq4,38312
3
+ growthbook/core.py,sha256=bxvzu_YhuSZzQpEgdR4uArl8ruNsmBZN3maURd8V65E,38425
4
4
  growthbook/growthbook.py,sha256=Ee6-jWPtvlgRvxRbsX-ZhrMV-8_F2T78Q7P30DVMsQM,47833
5
- growthbook/growthbook_client.py,sha256=YnbKGbO2taWZXtlutuTf_ZSkL_WmhYLhr39fB6BFIcw,27578
5
+ growthbook/growthbook_client.py,sha256=rIjIoWu4L-kwpBDSJrQxEX2hJ7Gdk3yR5lzMmqW6F-4,27578
6
6
  growthbook/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  growthbook/plugins/__init__.py,sha256=y2eAV1sA041XWcftBVTDH0t-ggy9r2C5oKRYRF6XR6s,602
8
8
  growthbook/plugins/base.py,sha256=PWBXUBj62hi25Y5Eif9WmEWagWdkwGXHi2dMtn44bo8,3637
9
9
  growthbook/plugins/growthbook_tracking.py,sha256=yN2xOHtRNsJuxkm16wY0YBQFxjEXDKnKcup7C9bQwe4,11351
10
10
  growthbook/plugins/request_context.py,sha256=WzoGxalxPfrsN3RzfkvVYaUGat1A3N4AErnaS9IZ48Y,13005
11
- growthbook-2.1.1.dist-info/licenses/LICENSE,sha256=D-TcBckB0dTPUlNJ8jBiTIJIj1ekHLB1CY7HJtJKhMY,1069
12
- growthbook-2.1.1.dist-info/METADATA,sha256=xu4GvzLkoLNvb8jgtS3BnaRdvp32o_UFz3AcmGjjvxE,22726
13
- growthbook-2.1.1.dist-info/WHEEL,sha256=Mk1ST5gDzEO5il5kYREiBnzzM469m5sI8ESPl7TRhJY,110
14
- growthbook-2.1.1.dist-info/top_level.txt,sha256=dzfRQFGYejCIUstRSrrRVTMlxf7pBqASTI5S8gGRlXw,11
15
- growthbook-2.1.1.dist-info/RECORD,,
11
+ growthbook-2.1.3.dist-info/licenses/LICENSE,sha256=D-TcBckB0dTPUlNJ8jBiTIJIj1ekHLB1CY7HJtJKhMY,1069
12
+ growthbook-2.1.3.dist-info/METADATA,sha256=9xHr31IEdPDrsDwkIZV4ybzXAkqoex0QU6EMVz9ZnFY,22726
13
+ growthbook-2.1.3.dist-info/WHEEL,sha256=Mk1ST5gDzEO5il5kYREiBnzzM469m5sI8ESPl7TRhJY,110
14
+ growthbook-2.1.3.dist-info/top_level.txt,sha256=dzfRQFGYejCIUstRSrrRVTMlxf7pBqASTI5S8gGRlXw,11
15
+ growthbook-2.1.3.dist-info/RECORD,,