Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cba6e86537 | ||
|
|
4e45255207 | ||
|
|
bc37351ab4 | ||
|
|
a5e8b7d7fb |
+13
-1
@@ -1,3 +1,15 @@
|
||||
## 3.4.2 - 2024-02-20
|
||||
|
||||
1. Add `historical_migration` option for bulk migration to PostHog Cloud.
|
||||
|
||||
## 3.4.1 - 2024-02-09
|
||||
|
||||
1. Use new hosts for event capture as well
|
||||
|
||||
## 3.4.0 - 2024-02-05
|
||||
|
||||
1. Point given hosts to new ingestion hosts
|
||||
|
||||
## 3.3.4 - 2024-01-30
|
||||
|
||||
1. Update type hints for module variables to work with newer versions of mypy
|
||||
@@ -115,7 +127,7 @@ Changes:
|
||||
Breaking changes:
|
||||
|
||||
1. The minimum version requirement for PostHog servers is now 1.38. If you're using PostHog Cloud, you satisfy this requirement automatically.
|
||||
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.
|
||||
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.
|
||||
**Note: These are removed in 2.0.2**
|
||||
3. Feature flag remote evaluation doesn't require a personal API key.
|
||||
|
||||
|
||||
+14
-4
@@ -10,7 +10,7 @@ from six import string_types
|
||||
from posthog.consumer import Consumer
|
||||
from posthog.feature_flags import InconclusiveMatchError, match_feature_flag_properties
|
||||
from posthog.poller import Poller
|
||||
from posthog.request import APIError, batch_post, decide, get
|
||||
from posthog.request import APIError, batch_post, decide, determine_server_host, get
|
||||
from posthog.utils import SizeLimitedDict, clean, guess_timezone
|
||||
from posthog.version import VERSION
|
||||
|
||||
@@ -49,6 +49,7 @@ class Client(object):
|
||||
project_api_key=None,
|
||||
disabled=False,
|
||||
disable_geoip=True,
|
||||
historical_migration=False,
|
||||
):
|
||||
self.queue = queue.Queue(max_queue_size)
|
||||
|
||||
@@ -61,7 +62,7 @@ class Client(object):
|
||||
self.debug = debug
|
||||
self.send = send
|
||||
self.sync_mode = sync_mode
|
||||
self.host = host
|
||||
self.host = determine_server_host(host)
|
||||
self.gzip = gzip
|
||||
self.timeout = timeout
|
||||
self.feature_flags = None
|
||||
@@ -73,6 +74,7 @@ class Client(object):
|
||||
self.distinct_ids_feature_flags_reported = SizeLimitedDict(MAX_DICT_SIZE, set)
|
||||
self.disabled = disabled
|
||||
self.disable_geoip = disable_geoip
|
||||
self.historical_migration = historical_migration
|
||||
|
||||
# personal_api_key: This should be a generated Personal API Key, private
|
||||
self.personal_api_key = personal_api_key
|
||||
@@ -100,13 +102,14 @@ class Client(object):
|
||||
consumer = Consumer(
|
||||
self.queue,
|
||||
self.api_key,
|
||||
host=host,
|
||||
host=self.host,
|
||||
on_error=on_error,
|
||||
flush_at=flush_at,
|
||||
flush_interval=flush_interval,
|
||||
gzip=gzip,
|
||||
retries=max_retries,
|
||||
timeout=timeout,
|
||||
historical_migration=historical_migration,
|
||||
)
|
||||
self.consumers.append(consumer)
|
||||
|
||||
@@ -374,7 +377,14 @@ class Client(object):
|
||||
|
||||
if self.sync_mode:
|
||||
self.log.debug("enqueued with blocking %s.", msg["event"])
|
||||
batch_post(self.api_key, self.host, gzip=self.gzip, timeout=self.timeout, batch=[msg])
|
||||
batch_post(
|
||||
self.api_key,
|
||||
self.host,
|
||||
gzip=self.gzip,
|
||||
timeout=self.timeout,
|
||||
batch=[msg],
|
||||
historical_migration=self.historical_migration,
|
||||
)
|
||||
|
||||
return True, msg
|
||||
|
||||
|
||||
+10
-1
@@ -36,6 +36,7 @@ class Consumer(Thread):
|
||||
gzip=False,
|
||||
retries=10,
|
||||
timeout=15,
|
||||
historical_migration=False,
|
||||
):
|
||||
"""Create a consumer thread."""
|
||||
Thread.__init__(self)
|
||||
@@ -55,6 +56,7 @@ class Consumer(Thread):
|
||||
self.running = True
|
||||
self.retries = retries
|
||||
self.timeout = timeout
|
||||
self.historical_migration = historical_migration
|
||||
|
||||
def run(self):
|
||||
"""Runs the consumer."""
|
||||
@@ -134,6 +136,13 @@ class Consumer(Thread):
|
||||
|
||||
@backoff.on_exception(backoff.expo, Exception, max_tries=self.retries + 1, giveup=fatal_exception)
|
||||
def send_request():
|
||||
batch_post(self.api_key, self.host, gzip=self.gzip, timeout=self.timeout, batch=batch)
|
||||
batch_post(
|
||||
self.api_key,
|
||||
self.host,
|
||||
gzip=self.gzip,
|
||||
timeout=self.timeout,
|
||||
batch=batch,
|
||||
historical_migration=self.historical_migration,
|
||||
)
|
||||
|
||||
send_request()
|
||||
|
||||
+15
-1
@@ -13,10 +13,24 @@ from posthog.version import VERSION
|
||||
|
||||
_session = requests.sessions.Session()
|
||||
|
||||
DEFAULT_HOST = "https://app.posthog.com"
|
||||
US_INGESTION_ENDPOINT = "https://us-api.i.posthog.com"
|
||||
EU_INGESTION_ENDPOINT = "https://eu-api.i.posthog.com"
|
||||
DEFAULT_HOST = US_INGESTION_ENDPOINT
|
||||
USER_AGENT = "posthog-python/" + VERSION
|
||||
|
||||
|
||||
def determine_server_host(host: Optional[str]) -> str:
|
||||
"""Determines the server host to use."""
|
||||
host_or_default = host or DEFAULT_HOST
|
||||
trimmed_host = remove_trailing_slash(host_or_default)
|
||||
if trimmed_host in ("https://app.posthog.com", "https://us.posthog.com"):
|
||||
return US_INGESTION_ENDPOINT
|
||||
elif trimmed_host == "https://eu.posthog.com":
|
||||
return EU_INGESTION_ENDPOINT
|
||||
else:
|
||||
return host_or_default
|
||||
|
||||
|
||||
def post(
|
||||
api_key: str, host: Optional[str] = None, path=None, gzip: bool = False, timeout: int = 15, **kwargs
|
||||
) -> requests.Response:
|
||||
|
||||
+14
-10
@@ -314,7 +314,7 @@ class TestClient(unittest.TestCase):
|
||||
self.assertEqual(patch_decide.call_count, 1)
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"https://us-api.i.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="distinct_id",
|
||||
groups={},
|
||||
@@ -330,7 +330,11 @@ class TestClient(unittest.TestCase):
|
||||
}
|
||||
|
||||
client = Client(
|
||||
FAKE_TEST_API_KEY, on_error=self.set_fail, personal_api_key=FAKE_TEST_API_KEY, disable_geoip=True
|
||||
FAKE_TEST_API_KEY,
|
||||
host="https://app.posthog.com",
|
||||
on_error=self.set_fail,
|
||||
personal_api_key=FAKE_TEST_API_KEY,
|
||||
disable_geoip=True,
|
||||
)
|
||||
success, msg = client.capture("distinct_id", "python test event", send_feature_flags=True, disable_geoip=False)
|
||||
client.flush()
|
||||
@@ -351,7 +355,7 @@ class TestClient(unittest.TestCase):
|
||||
self.assertEqual(patch_decide.call_count, 1)
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"https://us-api.i.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="distinct_id",
|
||||
groups={},
|
||||
@@ -779,7 +783,7 @@ class TestClient(unittest.TestCase):
|
||||
client.get_feature_flag("random_key", "some_id", disable_geoip=True)
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"https://us-api.i.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="some_id",
|
||||
groups={},
|
||||
@@ -791,7 +795,7 @@ class TestClient(unittest.TestCase):
|
||||
client.feature_enabled("random_key", "feature_enabled_distinct_id", disable_geoip=True)
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"https://us-api.i.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="feature_enabled_distinct_id",
|
||||
groups={},
|
||||
@@ -803,7 +807,7 @@ class TestClient(unittest.TestCase):
|
||||
client.get_all_flags_and_payloads("all_flags_payloads_id")
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"https://us-api.i.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="all_flags_payloads_id",
|
||||
groups={},
|
||||
@@ -829,7 +833,7 @@ class TestClient(unittest.TestCase):
|
||||
patch_decide.return_value = {
|
||||
"featureFlags": {"beta-feature": "random-variant", "alpha-feature": True, "off-feature": False}
|
||||
}
|
||||
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, disable_geoip=False)
|
||||
client = Client(FAKE_TEST_API_KEY, host="http://app2.posthog.com", on_error=self.set_fail, disable_geoip=False)
|
||||
client.get_feature_flag(
|
||||
"random_key",
|
||||
"some_id",
|
||||
@@ -839,7 +843,7 @@ class TestClient(unittest.TestCase):
|
||||
)
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"http://app2.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="some_id",
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
@@ -865,7 +869,7 @@ class TestClient(unittest.TestCase):
|
||||
)
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"http://app2.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="some_id",
|
||||
groups={"company": "id:5", "instance": "app.posthog.com"},
|
||||
@@ -882,7 +886,7 @@ class TestClient(unittest.TestCase):
|
||||
client.get_all_flags_and_payloads("some_id", groups={}, person_properties=None, group_properties=None)
|
||||
patch_decide.assert_called_with(
|
||||
"random_key",
|
||||
None,
|
||||
"http://app2.posthog.com",
|
||||
timeout=10,
|
||||
distinct_id="some_id",
|
||||
groups={},
|
||||
|
||||
@@ -2,9 +2,10 @@ import json
|
||||
import unittest
|
||||
from datetime import date, datetime
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from posthog.request import DatetimeSerializer, batch_post
|
||||
from posthog.request import DatetimeSerializer, batch_post, determine_server_host
|
||||
from posthog.test.test_utils import TEST_API_KEY
|
||||
|
||||
|
||||
@@ -42,3 +43,26 @@ class TestRequests(unittest.TestCase):
|
||||
batch_post(
|
||||
"key", batch=[{"distinct_id": "distinct_id", "event": "python event", "type": "track"}], timeout=0.0001
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"host, expected",
|
||||
[
|
||||
("https://t.posthog.com", "https://t.posthog.com"),
|
||||
("https://t.posthog.com/", "https://t.posthog.com/"),
|
||||
("t.posthog.com", "t.posthog.com"),
|
||||
("t.posthog.com/", "t.posthog.com/"),
|
||||
("https://us.posthog.com.rg.proxy.com", "https://us.posthog.com.rg.proxy.com"),
|
||||
("app.posthog.com", "app.posthog.com"),
|
||||
("eu.posthog.com", "eu.posthog.com"),
|
||||
("https://app.posthog.com", "https://us-api.i.posthog.com"),
|
||||
("https://eu.posthog.com", "https://eu-api.i.posthog.com"),
|
||||
("https://us.posthog.com", "https://us-api.i.posthog.com"),
|
||||
("https://app.posthog.com/", "https://us-api.i.posthog.com"),
|
||||
("https://eu.posthog.com/", "https://eu-api.i.posthog.com"),
|
||||
("https://us.posthog.com/", "https://us-api.i.posthog.com"),
|
||||
(None, "https://us-api.i.posthog.com"),
|
||||
],
|
||||
)
|
||||
def test_routing_to_custom_host(host, expected):
|
||||
assert determine_server_host(host) == expected
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
VERSION = "3.3.4"
|
||||
VERSION = "3.4.2"
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(VERSION, end="") # noqa: T201
|
||||
|
||||
Reference in New Issue
Block a user