Skip to content

Commit 6d70ba8

Browse files
committed
formatting
1 parent eaecd9b commit 6d70ba8

File tree

3 files changed

+105
-89
lines changed

3 files changed

+105
-89
lines changed

posthog/client.py

Lines changed: 90 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from posthog.exception_utils import exc_info_from_error, exceptions_from_error_tuple, handle_in_app
2020
from posthog.feature_flags import InconclusiveMatchError, match_feature_flag_properties
2121
from posthog.poller import Poller
22-
from posthog.request import DEFAULT_HOST, APIError, batch_post, decide, determine_server_host, get, flags, remote_config
22+
from posthog.request import DEFAULT_HOST, APIError, batch_post, decide, determine_server_host, get, flags, remote_config
2323
from posthog.types import (
2424
FlagsResponse,
2525
FeatureFlag,
@@ -45,72 +45,74 @@
4545

4646
# TODO: Get rid of these when you're done rolling out `/flags` to all customers
4747
ROLLOUT_PERCENTAGE = 0.1
48-
INCLUDED_HASHES = set({'c4c6803067869081a8c4686780f32de979ade862c6af9ff9ebe5b7161e18362f'}) # this is PostHog's API key
48+
INCLUDED_HASHES = set({"c4c6803067869081a8c4686780f32de979ade862c6af9ff9ebe5b7161e18362f"}) # this is PostHog's API key
4949
# Explicitly excluding all the API tokens associated with the top 10 customers; we'll get to them soon, but don't want to rollout to them just yet
50-
EXCLUDED_HASHES = set({
51-
'5fbb169efa185c2a78d43574b01b56c66d7bb594b310f72702e1f167e4e283a9',
52-
'374be8e6556709787d472e276ebe3c46c0ab4b868ec99f4c96168a44df8307df',
53-
'6c8a2d5e9dbd4c71854aebca3026fe50045b05e19a16780dccea5439625ee1b4',
54-
'c4c6803067869081a8c4686780f32de979ade862c6af9ff9ebe5b7161e18362f',
55-
'0f1fa079412bb39b5fce8d96af3539925ede61cbc561ffcd38e27c8e8ae64edb',
56-
'e3bdce3350e62638ffbf79872c2fd69ef6cbbd35712d9faf735f874cf77ccbfc',
57-
'f96fe01cdf22f1ec75bc7c897e9605e6431fb5d8f6a8bb9d0e8fce2b0a1384a6',
58-
'6859b51ac773ea98e146bae47e98759f97ec64c253b9c0524ab56793cc5b6c75',
59-
'06b28c04e490ce1c9c017396b8b8e16fce1176a8b5de131a99d9af4df1d0fbc9',
60-
'd9c0afa45a34c9f3c1e615bfa77394b79ad7b434ea46856e3503445d5974d640',
61-
'320eb50509e2c58a50d80fac848ee0b86290c848a173a0402abdbb760b794595',
62-
'7380abb65605420dd6e61534c8eecaa6f14d25a6f90ec2edba811f7383123ded',
63-
'3182881fa027d1c8e4eea108df66dcb0387e375d1e4b551c3a3579fdb1e696d1',
64-
'd685aeb7d02ec757c4cbe591050a168d34be2f5305d9071d9695ed773057ef16',
65-
'875ab92bec4da51cf229145565364e98347fafaa2316a4a8e20f5d852bc95aed',
66-
'4a0d726e4b56d6f6d0407faf5396847146084bbabd042ca0dedba2873d8f9236',
67-
'a9dc6415c1ccd1874ed1cd303e3d5bf92ddb17ac2af968abed14a51dfb0c53be',
68-
'5f10a055c9e379869a159306b1d7242fec25584ce895f677f82a13133741c7f1',
69-
'e3e7608bbda7c15bf82fd7e2945ca74052f8b99e2090962318b6ef983c0ddb16',
70-
'7f0cbd50e11b475f6c2ed50e620c473e4bfc8df1f4c5174b49ecee1fcec6853e',
71-
'03004fb2209e6e4186c4364c71e5abc9cf272caf83cf58fb538c42684fd42fb0',
72-
'8721e8bf608c5eb4d74eeaf26fe588b4e5414742e0494ca7e67a89e1a297332b',
73-
'ac0d5c7daee8d2f89d5b3861fba0b9a0e560b0eb6944e974f37cdc52274f2d1f',
74-
'6581d65cf0c4c536122beb5d581ba2b128ed44b7528c07d4ec7837ea33d0cffe',
75-
'd0c2d4e122ecd4520af7bac133b09fde357622f20aa5a0f7a9328d25c9e9f28e',
76-
'd09de64bec03c750493b0771c9f2731204bc9a5f0479628848803e2ccded9aca',
77-
'a9f483f0cdc028a5e05d03d7ab683738f09a940c0173d9e6b004fbe85738a1f5',
78-
'2ffb5817a9fc465b9bb37b9112393cc1a274185f7f18618192421b7511b98830',
79-
'a6785a722fdb0f975a1a30302f8312709ae069358c901c609f4898a9ae14bdf2',
80-
'3d9ba35cab44358cf47c867f48c95f75b9ad54ca5407ed19576da55a085d3a8f',
81-
'ff59d2907ecb66f4d4a1705435460124a390d8cf7762dc7860d4b4171f832976',
82-
'aac9e8036d3e0efed49cd5fbea19ea8354c4e1dfc95a1585300c5178189e5bac',
83-
'1e7fa74813f733e35ea820f8272c6562b4b0c70429f1b549605cc9e8016f632e',
84-
'2cb74b224cb20b8e5a5a52f3fe5ca62672e5c77ce7f30223698bb4d4abff2293',
85-
'17a90589bfe29f40f826e2df4753c0bce17a05f4c04b9a0924304e7418aba9e8',
86-
'0925e4c5bc65ced02c65aa3afba5eaa98aed288d193f719a8fbaebafdeafc1ce',
87-
'a0308973730b505f1d6af7cd2f39c69bd86ea2a35b9d27118910e1c58d9a6a1a',
88-
'c780092461636d6d62179723f03cbfe4a7b5808a6b46de749d8b32c3384f1e74',
89-
'65d6083548c27387f9381ff2aa37581a41ba1d5e6162afdc18cf8130be528052',
90-
'e2241631d1211e15688735ec6d9f56b4839e65d2095f278630c884bd49f00be8',
91-
'f2d9e1c10371912c32e9eba18f348782345ff70d383ae8b38bc9e6b12c7841e7',
92-
'57411b20e1c406ac4339718287b3eaa83635291fb593c9a4068dd08ec1d03692',
93-
'06e91ecd6b2a9a02234951ab3a5a95aeb84ef34499a5001629aaa13d907ba1dc',
94-
'4d2f47e99000f6820307e525fcf972421335a86f39b6ada1c93d67410520af49',
95-
'538d3b1415c3feccbe68d59b5ad9ed35aa418fc64658ff603855494abf75f647',
96-
'68b11387ac9f805bdbea486b9d3e0724856180646f2b12617a81174d5c27833c',
97-
'a74797287c3d29f92fc729c2a8b3f17638cb273388e12cb8ffd972bcfbcdfdb8',
98-
'b53d2b6551ebd8d68321dbd2727a299b1d23ff15853be02fffb0c54f1f0e1349',
99-
'abad9dc57c9cb9a244b89b11f0a9123baf924a6908443dd8527cf6b411bbb33a',
100-
'd17b55c7d72052d76d76a039e1ceb613d443401d30eae91ac903a07d5ee0d2d2',
101-
'274a08018c6e4609dedc37e31aea589c527cd7b93242d305591c3f5313408ee8',
102-
'75ed9cca6d877ea218647d6021b89c5959156eed2ce4ccad29d4e497d9cd0119',
103-
'4862317bab4b4efc876a810b92a6841bcf6ba69ac7aa7ff792358862528e7fa8',
104-
'f0498fff4318e52729573a8bf451d7b978c5242af51ec8b1699798090bc00d32',
105-
'a6a3435402f66a94eefd07b16297f6b4a61e26992e8ed7742de2e49d7ea71104',
106-
'72d8ede07d3ef0fd8eb0cd7261d29f4f33b3554e06a726db151138a25a01b539',
107-
'937c4aae120326c861eb3ec23371e029d3cea21f5849e4d52d75e47e06473e5c',
108-
'e0138f35502faac574232bbbaab7ad769e2dcd449b596e32454368cb3cc035f9',
109-
'084e32dc89830d7bb120492ed55cc543de0405c7ae3d0c16c8f64ab07c44506d',
110-
'd59f0ce1670146019b2c77b56ff8faca6346adfcc93443712a613a89298e3fb9',
111-
'b99bd54a29c2e9adc17527f9df539415a1c0a83293f72e3e0c8744c5677ea1a1',
112-
'c252a61d3c19f58062ca9fe2b13dfe378bc11380705cec703d9d8d0a0e167995'
113-
})
50+
EXCLUDED_HASHES = set(
51+
{
52+
"5fbb169efa185c2a78d43574b01b56c66d7bb594b310f72702e1f167e4e283a9",
53+
"374be8e6556709787d472e276ebe3c46c0ab4b868ec99f4c96168a44df8307df",
54+
"6c8a2d5e9dbd4c71854aebca3026fe50045b05e19a16780dccea5439625ee1b4",
55+
"c4c6803067869081a8c4686780f32de979ade862c6af9ff9ebe5b7161e18362f",
56+
"0f1fa079412bb39b5fce8d96af3539925ede61cbc561ffcd38e27c8e8ae64edb",
57+
"e3bdce3350e62638ffbf79872c2fd69ef6cbbd35712d9faf735f874cf77ccbfc",
58+
"f96fe01cdf22f1ec75bc7c897e9605e6431fb5d8f6a8bb9d0e8fce2b0a1384a6",
59+
"6859b51ac773ea98e146bae47e98759f97ec64c253b9c0524ab56793cc5b6c75",
60+
"06b28c04e490ce1c9c017396b8b8e16fce1176a8b5de131a99d9af4df1d0fbc9",
61+
"d9c0afa45a34c9f3c1e615bfa77394b79ad7b434ea46856e3503445d5974d640",
62+
"320eb50509e2c58a50d80fac848ee0b86290c848a173a0402abdbb760b794595",
63+
"7380abb65605420dd6e61534c8eecaa6f14d25a6f90ec2edba811f7383123ded",
64+
"3182881fa027d1c8e4eea108df66dcb0387e375d1e4b551c3a3579fdb1e696d1",
65+
"d685aeb7d02ec757c4cbe591050a168d34be2f5305d9071d9695ed773057ef16",
66+
"875ab92bec4da51cf229145565364e98347fafaa2316a4a8e20f5d852bc95aed",
67+
"4a0d726e4b56d6f6d0407faf5396847146084bbabd042ca0dedba2873d8f9236",
68+
"a9dc6415c1ccd1874ed1cd303e3d5bf92ddb17ac2af968abed14a51dfb0c53be",
69+
"5f10a055c9e379869a159306b1d7242fec25584ce895f677f82a13133741c7f1",
70+
"e3e7608bbda7c15bf82fd7e2945ca74052f8b99e2090962318b6ef983c0ddb16",
71+
"7f0cbd50e11b475f6c2ed50e620c473e4bfc8df1f4c5174b49ecee1fcec6853e",
72+
"03004fb2209e6e4186c4364c71e5abc9cf272caf83cf58fb538c42684fd42fb0",
73+
"8721e8bf608c5eb4d74eeaf26fe588b4e5414742e0494ca7e67a89e1a297332b",
74+
"ac0d5c7daee8d2f89d5b3861fba0b9a0e560b0eb6944e974f37cdc52274f2d1f",
75+
"6581d65cf0c4c536122beb5d581ba2b128ed44b7528c07d4ec7837ea33d0cffe",
76+
"d0c2d4e122ecd4520af7bac133b09fde357622f20aa5a0f7a9328d25c9e9f28e",
77+
"d09de64bec03c750493b0771c9f2731204bc9a5f0479628848803e2ccded9aca",
78+
"a9f483f0cdc028a5e05d03d7ab683738f09a940c0173d9e6b004fbe85738a1f5",
79+
"2ffb5817a9fc465b9bb37b9112393cc1a274185f7f18618192421b7511b98830",
80+
"a6785a722fdb0f975a1a30302f8312709ae069358c901c609f4898a9ae14bdf2",
81+
"3d9ba35cab44358cf47c867f48c95f75b9ad54ca5407ed19576da55a085d3a8f",
82+
"ff59d2907ecb66f4d4a1705435460124a390d8cf7762dc7860d4b4171f832976",
83+
"aac9e8036d3e0efed49cd5fbea19ea8354c4e1dfc95a1585300c5178189e5bac",
84+
"1e7fa74813f733e35ea820f8272c6562b4b0c70429f1b549605cc9e8016f632e",
85+
"2cb74b224cb20b8e5a5a52f3fe5ca62672e5c77ce7f30223698bb4d4abff2293",
86+
"17a90589bfe29f40f826e2df4753c0bce17a05f4c04b9a0924304e7418aba9e8",
87+
"0925e4c5bc65ced02c65aa3afba5eaa98aed288d193f719a8fbaebafdeafc1ce",
88+
"a0308973730b505f1d6af7cd2f39c69bd86ea2a35b9d27118910e1c58d9a6a1a",
89+
"c780092461636d6d62179723f03cbfe4a7b5808a6b46de749d8b32c3384f1e74",
90+
"65d6083548c27387f9381ff2aa37581a41ba1d5e6162afdc18cf8130be528052",
91+
"e2241631d1211e15688735ec6d9f56b4839e65d2095f278630c884bd49f00be8",
92+
"f2d9e1c10371912c32e9eba18f348782345ff70d383ae8b38bc9e6b12c7841e7",
93+
"57411b20e1c406ac4339718287b3eaa83635291fb593c9a4068dd08ec1d03692",
94+
"06e91ecd6b2a9a02234951ab3a5a95aeb84ef34499a5001629aaa13d907ba1dc",
95+
"4d2f47e99000f6820307e525fcf972421335a86f39b6ada1c93d67410520af49",
96+
"538d3b1415c3feccbe68d59b5ad9ed35aa418fc64658ff603855494abf75f647",
97+
"68b11387ac9f805bdbea486b9d3e0724856180646f2b12617a81174d5c27833c",
98+
"a74797287c3d29f92fc729c2a8b3f17638cb273388e12cb8ffd972bcfbcdfdb8",
99+
"b53d2b6551ebd8d68321dbd2727a299b1d23ff15853be02fffb0c54f1f0e1349",
100+
"abad9dc57c9cb9a244b89b11f0a9123baf924a6908443dd8527cf6b411bbb33a",
101+
"d17b55c7d72052d76d76a039e1ceb613d443401d30eae91ac903a07d5ee0d2d2",
102+
"274a08018c6e4609dedc37e31aea589c527cd7b93242d305591c3f5313408ee8",
103+
"75ed9cca6d877ea218647d6021b89c5959156eed2ce4ccad29d4e497d9cd0119",
104+
"4862317bab4b4efc876a810b92a6841bcf6ba69ac7aa7ff792358862528e7fa8",
105+
"f0498fff4318e52729573a8bf451d7b978c5242af51ec8b1699798090bc00d32",
106+
"a6a3435402f66a94eefd07b16297f6b4a61e26992e8ed7742de2e49d7ea71104",
107+
"72d8ede07d3ef0fd8eb0cd7261d29f4f33b3554e06a726db151138a25a01b539",
108+
"937c4aae120326c861eb3ec23371e029d3cea21f5849e4d52d75e47e06473e5c",
109+
"e0138f35502faac574232bbbaab7ad769e2dcd449b596e32454368cb3cc035f9",
110+
"084e32dc89830d7bb120492ed55cc543de0405c7ae3d0c16c8f64ab07c44506d",
111+
"d59f0ce1670146019b2c77b56ff8faca6346adfcc93443712a613a89298e3fb9",
112+
"b99bd54a29c2e9adc17527f9df539415a1c0a83293f72e3e0c8744c5677ea1a1",
113+
"c252a61d3c19f58062ca9fe2b13dfe378bc11380705cec703d9d8d0a0e167995",
114+
}
115+
)
114116

115117

116118
def get_os_info():
@@ -166,12 +168,15 @@ def system_context() -> dict[str, Any]:
166168
"$os_version": os_version,
167169
}
168170

169-
def is_token_in_rollout(token: str, percentage: float = 0, included_hashes: set[str] = None, excluded_hashes: set[str] = None) -> bool:
171+
172+
def is_token_in_rollout(
173+
token: str, percentage: float = 0, included_hashes: set[str] = None, excluded_hashes: set[str] = None
174+
) -> bool:
170175
"""
171176
Determines if a token should be included in a rollout based on:
172177
1. If its hash matches any included_hashes provided
173178
2. If its hash falls within the percentage rollout
174-
179+
175180
Args:
176181
token: String to hash (usually API key)
177182
percentage: Float between 0 and 1 representing rollout percentage
@@ -181,20 +186,20 @@ def is_token_in_rollout(token: str, percentage: float = 0, included_hashes: set[
181186
bool: True if token should be included in rollout
182187
"""
183188
# First generate SHA1 hash of token
184-
token_hash = hashlib.sha1(token.encode('utf-8')).hexdigest()
185-
189+
token_hash = hashlib.sha1(token.encode("utf-8")).hexdigest()
190+
186191
# Check if hash matches any included hashes
187192
if included_hashes and token_hash in included_hashes:
188193
return True
189194

190195
# Check if hash matches any excluded hashes
191196
if excluded_hashes and token_hash in excluded_hashes:
192197
return False
193-
198+
194199
# Convert first 8 chars of hash to int and divide by max value to get number between 0-1
195200
hash_int = int(token_hash[:8], 16)
196-
hash_float = hash_int / 0xffffffff
197-
201+
hash_float = hash_int / 0xFFFFFFFF
202+
198203
return hash_float < percentage
199204

200205

@@ -408,13 +413,19 @@ def get_flags_decision(
408413
"group_properties": group_properties,
409414
"disable_geoip": disable_geoip,
410415
}
411-
412-
use_flags = is_token_in_rollout(self.api_key, ROLLOUT_PERCENTAGE, included_hashes=INCLUDED_HASHES, excluded_hashes=EXCLUDED_HASHES)
413-
416+
417+
use_flags = is_token_in_rollout(
418+
self.api_key, ROLLOUT_PERCENTAGE, included_hashes=INCLUDED_HASHES, excluded_hashes=EXCLUDED_HASHES
419+
)
420+
414421
if use_flags:
415-
resp_data = flags(self.api_key, self.host, timeout=self.feature_flags_request_timeout_seconds, **request_data)
422+
resp_data = flags(
423+
self.api_key, self.host, timeout=self.feature_flags_request_timeout_seconds, **request_data
424+
)
416425
else:
417-
resp_data = decide(self.api_key, self.host, timeout=self.feature_flags_request_timeout_seconds, **request_data)
426+
resp_data = decide(
427+
self.api_key, self.host, timeout=self.feature_flags_request_timeout_seconds, **request_data
428+
)
418429

419430
return normalize_flags_response(resp_data)
420431

@@ -1291,4 +1302,4 @@ def stringify_id(val):
12911302
return None
12921303
if isinstance(val, string_types):
12931304
return val
1294-
return str(val)
1305+
return str(val)

posthog/request.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def decide(api_key: str, host: Optional[str] = None, gzip: bool = False, timeout
105105
res = post(api_key, host, "/decide/?v=4", gzip, timeout, **kwargs)
106106
return _process_response(res, success_message="Feature flags decided successfully")
107107

108+
108109
def flags(api_key: str, host: Optional[str] = None, gzip: bool = False, timeout: int = 15, **kwargs) -> Any:
109110
"""Post the `kwargs to the flags API endpoint"""
110111
res = post(api_key, host, "/flags/?v=2", gzip, timeout, **kwargs)

posthog/test/test_client.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,11 +1290,13 @@ def test_get_flags_decision_rollout(self, patch_decide, patch_flags):
12901290
patch_flags.return_value = flags_response
12911291

12921292
client = Client(FAKE_TEST_API_KEY)
1293-
1293+
12941294
# Test 0% rollout - should use decide
12951295
with mock.patch("posthog.client.is_token_in_rollout", return_value=False) as mock_rollout:
12961296
client.get_flags_decision("distinct_id")
1297-
mock_rollout.assert_called_with(FAKE_TEST_API_KEY, 0.1, included_hashes=INCLUDED_HASHES, excluded_hashes=EXCLUDED_HASHES)
1297+
mock_rollout.assert_called_with(
1298+
FAKE_TEST_API_KEY, 0.1, included_hashes=INCLUDED_HASHES, excluded_hashes=EXCLUDED_HASHES
1299+
)
12981300
patch_decide.assert_called_once()
12991301
patch_flags.assert_not_called()
13001302
patch_decide.reset_mock()
@@ -1303,30 +1305,32 @@ def test_get_flags_decision_rollout(self, patch_decide, patch_flags):
13031305
# Test 100% rollout - should use flags
13041306
with mock.patch("posthog.client.is_token_in_rollout", return_value=True) as mock_rollout:
13051307
client.get_flags_decision("distinct_id")
1306-
mock_rollout.assert_called_with(FAKE_TEST_API_KEY, 0.1, included_hashes=INCLUDED_HASHES, excluded_hashes=EXCLUDED_HASHES)
1308+
mock_rollout.assert_called_with(
1309+
FAKE_TEST_API_KEY, 0.1, included_hashes=INCLUDED_HASHES, excluded_hashes=EXCLUDED_HASHES
1310+
)
13071311
patch_flags.assert_called_once()
13081312
patch_decide.assert_not_called()
13091313

13101314
def test_token_rollout_calculation(self):
13111315
# Test specific hash inclusion
13121316
token = "test_token"
1313-
token_hash = hashlib.sha1(token.encode('utf-8')).hexdigest()
1317+
token_hash = hashlib.sha1(token.encode("utf-8")).hexdigest()
13141318
included_hashes = {token_hash}
1315-
1319+
13161320
# Should be included due to specific hash, even with 0% rollout
13171321
self.assertTrue(expr=is_token_in_rollout(token, percentage=0.0, included_hashes=included_hashes))
1318-
1322+
13191323
# Should not be included with 0% rollout and no specific hash
13201324
self.assertFalse(is_token_in_rollout(token, percentage=0.0))
1321-
1325+
13221326
# Should be included with 100% rollout regardless of specific hash
13231327
self.assertTrue(is_token_in_rollout(token, percentage=1.0))
13241328
self.assertTrue(is_token_in_rollout(token, percentage=1.0, included_hashes=included_hashes))
1325-
1329+
13261330
# Test deterministic behavior - same token should always give same result
1327-
hash_float = int(token_hash[:8], 16) / 0xffffffff
1331+
hash_float = int(token_hash[:8], 16) / 0xFFFFFFFF
13281332
percentage = hash_float + 0.1 # Just above the hash value
1329-
1333+
13301334
self.assertTrue(is_token_in_rollout(token, percentage))
13311335
self.assertFalse(is_token_in_rollout(token, percentage - 0.2)) # Just below the hash value
13321336

0 commit comments

Comments
 (0)