Skip to content

Commit 2dc1298

Browse files
authored
Bump version to 2.0.0 and add breaking changes changelog (#69)
1 parent 2c6b675 commit 2dc1298

File tree

6 files changed

+151
-21
lines changed

6 files changed

+151
-21
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
## 2.0.0 - 2022-08-02
2+
3+
Breaking changes:
4+
5+
1. The minimum version requirement for PostHog servers is now 1.38. If you're using PostHog Cloud, you satisfy this requirement automatically.
6+
2. Feature flag defaults apply only when there's an error fetching feature flag results. Earlier, if the default was set to `True`, even if a flag resolved to `False`, the default would override this.
7+
3. Feature flag remote evaluation doesn't require a personal API key.
8+
9+
New Changes:
10+
11+
1. You can now evaluate feature flags locally (i.e. without sending a request to your PostHog servers) by setting a personal API key, and passing in groups and person properties to `is_feature_enabled` and `get_feature_flag` calls.
12+
2. Introduces a `get_all_flags` method that returns all feature flags. This is useful for when you want to seed your frontend with some initial flags, given a user ID.
13+
14+
15+
116
## 1.4.9 - 2022-06-13
217
- Support for sending feature flags with capture calls
318

example.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import posthog
77

8+
# posthog.debug = True
9+
810
# You can find this key on the /setup page in PostHog
911
posthog.project_api_key = ""
1012
posthog.personal_api_key = ""
@@ -20,7 +22,7 @@
2022
print(posthog.feature_enabled("beta-feature", "distinct_id", groups={"company": "id:5"}))
2123

2224
print("sleeping")
23-
time.sleep(5)
25+
# time.sleep(5)
2426

2527
print(posthog.feature_enabled("beta-feature", "distinct_id"))
2628

@@ -42,7 +44,7 @@
4244
# properties set only once to the person
4345
posthog.set_once("new_distinct_id", {"self_serve_signup": True})
4446

45-
time.sleep(3)
47+
# time.sleep(3)
4648

4749
posthog.set_once(
4850
"new_distinct_id", {"self_serve_signup": False}

posthog/client.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424

2525
ID_TYPES = (numbers.Number, string_types, UUID)
26-
MAX_DICT_SIZE = 100_000
26+
MAX_DICT_SIZE = 50_000
2727

2828

2929
class Client(object):
@@ -75,7 +75,11 @@ def __init__(
7575
self.personal_api_key = personal_api_key
7676

7777
if debug:
78-
self.log.setLevel(logging.DEBUG)
78+
# Ensures that debug level messages are logged when debug mode is on.
79+
# Otherwise, defaults to WARNING level. See https://docs.python.org/3/howto/logging.html#what-happens-if-no-configuration-is-provided
80+
logging.basicConfig(level=logging.DEBUG)
81+
else:
82+
logging.basicConfig(level=logging.WARNING)
7983

8084
if sync_mode:
8185
self.consumers = None
@@ -359,8 +363,8 @@ def _load_feature_flags(self):
359363
response = get(
360364
self.personal_api_key, f"/api/feature_flag/local_evaluation/?token={self.api_key}", self.host
361365
)
362-
self.feature_flags = [flag for flag in response["flags"] if flag["active"]]
363-
self.group_type_mapping = response["group_type_mapping"]
366+
self.feature_flags = response["flags"] or []
367+
self.group_type_mapping = response["group_type_mapping"] or {}
364368

365369
except APIError as e:
366370
if e.status == 401:
@@ -397,6 +401,9 @@ def _compute_flag_locally(self, feature_flag, distinct_id, *, groups={}, person_
397401
if feature_flag.get("ensure_experience_continuity", False):
398402
raise InconclusiveMatchError("Flag has experience continuity enabled")
399403

404+
if not feature_flag.get("active"):
405+
return False
406+
400407
flag_filters = feature_flag.get("filters") or {}
401408
aggregation_group_type_index = flag_filters.get("aggregation_group_type_index")
402409
if aggregation_group_type_index is not None:
@@ -457,11 +464,12 @@ def get_feature_flag(
457464
person_properties=person_properties,
458465
group_properties=group_properties,
459466
)
467+
self.log.debug(f"Successfully computed flag locally: {key} -> {response}")
460468
except InconclusiveMatchError as e:
461-
# No need to log this, since it's just telling us to fall back to `/decide`
469+
self.log.debug(f"Failed to compute flag {key} locally: {e}")
462470
continue
463471
except Exception as e:
464-
self.log.exception(f"[FEATURE FLAGS] Error while computing variant: {e}")
472+
self.log.exception(f"[FEATURE FLAGS] Error while computing variant locally: {e}")
465473
continue
466474

467475
if response is None:
@@ -470,8 +478,9 @@ def get_feature_flag(
470478
distinct_id, groups=groups, person_properties=person_properties, group_properties=group_properties
471479
)
472480
response = feature_flags.get(key)
481+
self.log.debug(f"Successfully computed flag remotely: #{key} -> #{response}")
473482
except Exception as e:
474-
self.log.exception(f"[FEATURE FLAGS] Unable to get feature variants: {e}")
483+
self.log.exception(f"[FEATURE FLAGS] Unable to get flag remotely: {e}")
475484
response = default
476485

477486
if key not in self.distinct_ids_feature_flags_reported[distinct_id]:

posthog/feature_flags.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ def _hash(key, distinct_id, salt=""):
2121

2222

2323
def get_matching_variant(flag, distinct_id):
24+
hash_value = _hash(flag["key"], distinct_id, salt="variant")
2425
for variant in variant_lookup_table(flag):
25-
if (
26-
_hash(flag["key"], distinct_id, salt="variant") >= variant["value_min"]
27-
and _hash(flag["key"], distinct_id, salt="variant") < variant["value_max"]
28-
):
26+
if hash_value >= variant["value_min"] and hash_value < variant["value_max"]:
2927
return variant["key"]
3028
return None
3129

0 commit comments

Comments
 (0)