growthbook 1.4.9__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 CHANGED
@@ -18,5 +18,5 @@ from .plugins import (
18
18
  )
19
19
 
20
20
  # x-release-please-start-version
21
- __version__ = "1.4.9"
21
+ __version__ = "1.4.10"
22
22
  # x-release-please-end
growthbook/growthbook.py CHANGED
@@ -409,16 +409,35 @@ class FeatureRepository(object):
409
409
  self._notify_feature_update_callbacks(res)
410
410
  return res
411
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
412
420
 
413
421
  # Perform the GET request (separate method for easy mocking)
414
422
  def _get(self, url: str, headers: Optional[Dict[str, str]] = None):
415
423
  self.http = self.http or PoolManager()
416
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
417
436
 
418
437
  def _fetch_and_decode(self, api_host: str, client_key: str) -> Optional[Dict]:
419
438
  url = self._get_features_url(api_host, client_key)
420
- headers: Dict[str, str] = {}
421
- headers['Accept-Encoding'] = "gzip, deflate, br"
439
+ headers = self._get_headers(client_key)
440
+ logger.debug(f"Fetching features from {url} with headers {headers}")
422
441
 
423
442
  # Check if we have a cached ETag for this URL
424
443
  cached_etag = None
@@ -473,13 +492,13 @@ class FeatureRepository(object):
473
492
 
474
493
  return decoded # type: ignore[no-any-return]
475
494
  except Exception as e:
476
- logger.warning(f"Failed to decode feature JSON from GrowthBook API: {e}")
495
+ logger.error(f"Failed to decode feature JSON from GrowthBook API: {e}")
477
496
  return None
478
497
 
479
498
  async def _fetch_and_decode_async(self, api_host: str, client_key: str) -> Optional[Dict]:
480
499
  url = self._get_features_url(api_host, client_key)
481
- headers: Dict[str, str] = {}
482
- headers['Accept-Encoding'] = "gzip, deflate, br"
500
+ headers = self._get_headers(client_key=client_key)
501
+ logger.debug(f"[Async] Fetching features from {url} with headers {headers}")
483
502
 
484
503
  # Check if we have a cached ETag for this URL
485
504
  cached_etag = None
@@ -535,7 +554,7 @@ class FeatureRepository(object):
535
554
  logger.warning(f"HTTP request failed: {e}")
536
555
  return None
537
556
  except Exception as e:
538
- logger.warning("Failed to decode feature JSON from GrowthBook API: %s", e)
557
+ logger.error(f"Failed to decode feature JSON from GrowthBook API: {e}")
539
558
  return None
540
559
 
541
560
  def decrypt_response(self, data, decryption_key: str):
@@ -1134,6 +1153,16 @@ class GrowthBook(object):
1134
1153
  except Exception as e:
1135
1154
  logger.error(f"Failed to initialize plugin {plugin}: {e}")
1136
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
+
1137
1166
  def _cleanup_plugins(self) -> None:
1138
1167
  """Cleanup all initialized plugins."""
1139
1168
  for plugin in self._initialized_plugins:
@@ -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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: growthbook
3
- Version: 1.4.9
3
+ Version: 1.4.10
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
@@ -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=rS8Pbu4YzSoxgDLLEOGAQ8LBKOmI1OoTTpcEDleWr-g,444
2
- growthbook/common_types.py,sha256=YKUmmYfzgrzLQ7kp2IPLc8QBA-B0QbnbF5viekNiTpw,15703
3
- growthbook/core.py,sha256=C1Nes_AiEuu6ypPghKuIeM2F22XUsLK1KrLW0xDwLYU,35963
4
- growthbook/growthbook.py,sha256=DNvkUyWkpWqYt1d73XyzfgXTFqmzIUWOcBueEIgVu_k,46645
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.9.dist-info/licenses/LICENSE,sha256=D-TcBckB0dTPUlNJ8jBiTIJIj1ekHLB1CY7HJtJKhMY,1069
12
- growthbook-1.4.9.dist-info/METADATA,sha256=USHNtbSqd4Wic7sVYdEkoGJ_wzhs58L7dbi96msdv4A,22726
13
- growthbook-1.4.9.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
14
- growthbook-1.4.9.dist-info/top_level.txt,sha256=dzfRQFGYejCIUstRSrrRVTMlxf7pBqASTI5S8gGRlXw,11
15
- growthbook-1.4.9.dist-info/RECORD,,