growthbook 1.4.8__py2.py3-none-any.whl → 1.4.10__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 +1 -1
- growthbook/growthbook.py +36 -4
- growthbook/growthbook_client.py +11 -2
- {growthbook-1.4.8.dist-info → growthbook-1.4.10.dist-info}/METADATA +1 -1
- growthbook-1.4.10.dist-info/RECORD +15 -0
- growthbook-1.4.8.dist-info/RECORD +0 -15
- {growthbook-1.4.8.dist-info → growthbook-1.4.10.dist-info}/WHEEL +0 -0
- {growthbook-1.4.8.dist-info → growthbook-1.4.10.dist-info}/licenses/LICENSE +0 -0
- {growthbook-1.4.8.dist-info → growthbook-1.4.10.dist-info}/top_level.txt +0 -0
growthbook/__init__.py
CHANGED
growthbook/growthbook.py
CHANGED
|
@@ -139,6 +139,7 @@ class SSEClient:
|
|
|
139
139
|
self.headers = {
|
|
140
140
|
"Accept": "application/json; q=0.5, text/event-stream",
|
|
141
141
|
"Cache-Control": "no-cache",
|
|
142
|
+
"Accept-Encoding": "gzip, deflate, br",
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
if headers:
|
|
@@ -408,15 +409,35 @@ class FeatureRepository(object):
|
|
|
408
409
|
self._notify_feature_update_callbacks(res)
|
|
409
410
|
return res
|
|
410
411
|
return cached
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def user_agent_suffix(self) -> Optional[str]:
|
|
415
|
+
return getattr(self, "_user_agent_suffix", None)
|
|
416
|
+
|
|
417
|
+
@user_agent_suffix.setter
|
|
418
|
+
def user_agent_suffix(self, value: Optional[str]) -> None:
|
|
419
|
+
self._user_agent_suffix = value
|
|
411
420
|
|
|
412
421
|
# Perform the GET request (separate method for easy mocking)
|
|
413
422
|
def _get(self, url: str, headers: Optional[Dict[str, str]] = None):
|
|
414
423
|
self.http = self.http or PoolManager()
|
|
415
424
|
return self.http.request("GET", url, headers=headers or {})
|
|
425
|
+
|
|
426
|
+
def _get_headers(self, client_key: str, existing_headers: Dict[str, str] = None) -> Dict[str, str]:
|
|
427
|
+
headers = existing_headers or {}
|
|
428
|
+
headers['Accept-Encoding'] = "gzip, deflate"
|
|
429
|
+
|
|
430
|
+
# Add User-Agent with optional suffix
|
|
431
|
+
ua = "Gb-Python"
|
|
432
|
+
ua += f"-{self.user_agent_suffix}" if self.user_agent_suffix else f"-{client_key[-4:]}"
|
|
433
|
+
headers['User-Agent'] = ua
|
|
434
|
+
|
|
435
|
+
return headers
|
|
416
436
|
|
|
417
437
|
def _fetch_and_decode(self, api_host: str, client_key: str) -> Optional[Dict]:
|
|
418
438
|
url = self._get_features_url(api_host, client_key)
|
|
419
|
-
headers
|
|
439
|
+
headers = self._get_headers(client_key)
|
|
440
|
+
logger.debug(f"Fetching features from {url} with headers {headers}")
|
|
420
441
|
|
|
421
442
|
# Check if we have a cached ETag for this URL
|
|
422
443
|
cached_etag = None
|
|
@@ -471,12 +492,13 @@ class FeatureRepository(object):
|
|
|
471
492
|
|
|
472
493
|
return decoded # type: ignore[no-any-return]
|
|
473
494
|
except Exception as e:
|
|
474
|
-
logger.
|
|
495
|
+
logger.error(f"Failed to decode feature JSON from GrowthBook API: {e}")
|
|
475
496
|
return None
|
|
476
497
|
|
|
477
498
|
async def _fetch_and_decode_async(self, api_host: str, client_key: str) -> Optional[Dict]:
|
|
478
499
|
url = self._get_features_url(api_host, client_key)
|
|
479
|
-
headers
|
|
500
|
+
headers = self._get_headers(client_key=client_key)
|
|
501
|
+
logger.debug(f"[Async] Fetching features from {url} with headers {headers}")
|
|
480
502
|
|
|
481
503
|
# Check if we have a cached ETag for this URL
|
|
482
504
|
cached_etag = None
|
|
@@ -532,7 +554,7 @@ class FeatureRepository(object):
|
|
|
532
554
|
logger.warning(f"HTTP request failed: {e}")
|
|
533
555
|
return None
|
|
534
556
|
except Exception as e:
|
|
535
|
-
logger.
|
|
557
|
+
logger.error(f"Failed to decode feature JSON from GrowthBook API: {e}")
|
|
536
558
|
return None
|
|
537
559
|
|
|
538
560
|
def decrypt_response(self, data, decryption_key: str):
|
|
@@ -1131,6 +1153,16 @@ class GrowthBook(object):
|
|
|
1131
1153
|
except Exception as e:
|
|
1132
1154
|
logger.error(f"Failed to initialize plugin {plugin}: {e}")
|
|
1133
1155
|
|
|
1156
|
+
@property
|
|
1157
|
+
def user_agent_suffix(self) -> Optional[str]:
|
|
1158
|
+
"""Get the suffix appended to the User-Agent header"""
|
|
1159
|
+
return feature_repo.user_agent_suffix
|
|
1160
|
+
|
|
1161
|
+
@user_agent_suffix.setter
|
|
1162
|
+
def user_agent_suffix(self, value: Optional[str]) -> None:
|
|
1163
|
+
"""Set a suffix to be appended to the User-Agent header"""
|
|
1164
|
+
feature_repo.user_agent_suffix = value
|
|
1165
|
+
|
|
1134
1166
|
def _cleanup_plugins(self) -> None:
|
|
1135
1167
|
"""Cleanup all initialized plugins."""
|
|
1136
1168
|
for plugin in self._initialized_plugins:
|
growthbook/growthbook_client.py
CHANGED
|
@@ -9,7 +9,7 @@ import asyncio
|
|
|
9
9
|
import threading
|
|
10
10
|
import traceback
|
|
11
11
|
from datetime import datetime
|
|
12
|
-
from growthbook import FeatureRepository
|
|
12
|
+
from growthbook import FeatureRepository, feature_repo
|
|
13
13
|
from contextlib import asynccontextmanager
|
|
14
14
|
|
|
15
15
|
from .core import eval_feature as core_eval_feature, run_experiment
|
|
@@ -569,7 +569,6 @@ class GrowthBookClient:
|
|
|
569
569
|
self._tracked.clear()
|
|
570
570
|
with self._subscriptions_lock:
|
|
571
571
|
self._subscriptions.clear()
|
|
572
|
-
|
|
573
572
|
# Clear context
|
|
574
573
|
async with self._context_lock:
|
|
575
574
|
self._global_context = None
|
|
@@ -577,6 +576,16 @@ class GrowthBookClient:
|
|
|
577
576
|
# Cleanup plugins
|
|
578
577
|
self._cleanup_plugins()
|
|
579
578
|
|
|
579
|
+
@property
|
|
580
|
+
def user_agent_suffix(self) -> Optional[str]:
|
|
581
|
+
"""Get the suffix appended to the User-Agent header"""
|
|
582
|
+
return feature_repo.user_agent_suffix
|
|
583
|
+
|
|
584
|
+
@user_agent_suffix.setter
|
|
585
|
+
def user_agent_suffix(self, value: Optional[str]) -> None:
|
|
586
|
+
"""Set a suffix to be appended to the User-Agent header"""
|
|
587
|
+
feature_repo.user_agent_suffix = value
|
|
588
|
+
|
|
580
589
|
def _initialize_plugins(self) -> None:
|
|
581
590
|
"""Initialize all tracking plugins with this GrowthBookClient instance."""
|
|
582
591
|
for plugin in self._tracking_plugins:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
growthbook/__init__.py,sha256=UisD9HLBgfbN9HN7bKSmt9-KIulTfmU1XojdFC-lOZw,445
|
|
2
|
+
growthbook/common_types.py,sha256=YKUmmYfzgrzLQ7kp2IPLc8QBA-B0QbnbF5viekNiTpw,15703
|
|
3
|
+
growthbook/core.py,sha256=C1Nes_AiEuu6ypPghKuIeM2F22XUsLK1KrLW0xDwLYU,35963
|
|
4
|
+
growthbook/growthbook.py,sha256=xHrc_wgrfl9oTbAxIDSpFet7Wb8diW4Fetv02Cpc4aA,47829
|
|
5
|
+
growthbook/growthbook_client.py,sha256=dN7BSWJ2RDNIWLnHh8tYKedOc6FzdecvkG88YzHESto,25082
|
|
6
|
+
growthbook/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
growthbook/plugins/__init__.py,sha256=y2eAV1sA041XWcftBVTDH0t-ggy9r2C5oKRYRF6XR6s,602
|
|
8
|
+
growthbook/plugins/base.py,sha256=PWBXUBj62hi25Y5Eif9WmEWagWdkwGXHi2dMtn44bo8,3637
|
|
9
|
+
growthbook/plugins/growthbook_tracking.py,sha256=lWO9ErUSrnqhcpWLp03XIrh45-BdBssdmLDVvaGvulY,11317
|
|
10
|
+
growthbook/plugins/request_context.py,sha256=WzoGxalxPfrsN3RzfkvVYaUGat1A3N4AErnaS9IZ48Y,13005
|
|
11
|
+
growthbook-1.4.10.dist-info/licenses/LICENSE,sha256=D-TcBckB0dTPUlNJ8jBiTIJIj1ekHLB1CY7HJtJKhMY,1069
|
|
12
|
+
growthbook-1.4.10.dist-info/METADATA,sha256=TzLKYNF9RfuJDh-iOFKOF-e95s9U9l3N5cSo4Otmghg,22727
|
|
13
|
+
growthbook-1.4.10.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
|
14
|
+
growthbook-1.4.10.dist-info/top_level.txt,sha256=dzfRQFGYejCIUstRSrrRVTMlxf7pBqASTI5S8gGRlXw,11
|
|
15
|
+
growthbook-1.4.10.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
growthbook/__init__.py,sha256=BwGsRsv5njoTII6ZRvPJZg96aPrOC4s0KFJbGbWI5m0,444
|
|
2
|
-
growthbook/common_types.py,sha256=YKUmmYfzgrzLQ7kp2IPLc8QBA-B0QbnbF5viekNiTpw,15703
|
|
3
|
-
growthbook/core.py,sha256=C1Nes_AiEuu6ypPghKuIeM2F22XUsLK1KrLW0xDwLYU,35963
|
|
4
|
-
growthbook/growthbook.py,sha256=CzBahR87qYySyWT2-JLmmWtb70Xr9PtknVorPtfHftw,46479
|
|
5
|
-
growthbook/growthbook_client.py,sha256=ZzdeNZ1a9N78ISbj2BKN9Xmyt05VlPVNjMyh9E1eA0E,24679
|
|
6
|
-
growthbook/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
growthbook/plugins/__init__.py,sha256=y2eAV1sA041XWcftBVTDH0t-ggy9r2C5oKRYRF6XR6s,602
|
|
8
|
-
growthbook/plugins/base.py,sha256=PWBXUBj62hi25Y5Eif9WmEWagWdkwGXHi2dMtn44bo8,3637
|
|
9
|
-
growthbook/plugins/growthbook_tracking.py,sha256=lWO9ErUSrnqhcpWLp03XIrh45-BdBssdmLDVvaGvulY,11317
|
|
10
|
-
growthbook/plugins/request_context.py,sha256=WzoGxalxPfrsN3RzfkvVYaUGat1A3N4AErnaS9IZ48Y,13005
|
|
11
|
-
growthbook-1.4.8.dist-info/licenses/LICENSE,sha256=D-TcBckB0dTPUlNJ8jBiTIJIj1ekHLB1CY7HJtJKhMY,1069
|
|
12
|
-
growthbook-1.4.8.dist-info/METADATA,sha256=ogrwnsEpsEZfwGsT3WtnMNbxecVH8abUWlXA2svIQOc,22726
|
|
13
|
-
growthbook-1.4.8.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
|
14
|
-
growthbook-1.4.8.dist-info/top_level.txt,sha256=dzfRQFGYejCIUstRSrrRVTMlxf7pBqASTI5S8gGRlXw,11
|
|
15
|
-
growthbook-1.4.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|