Skip to content

Commit 6c945a0

Browse files
authored
Basic group analytics support (#44)
* Make setup instructions work * Add basic group analytics support to library * Resolve formatting issues
1 parent ab8ccb4 commit 6c945a0

File tree

4 files changed

+123
-6
lines changed

4 files changed

+123
-6
lines changed

posthog/__init__.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def capture(
2626
context=None, # type: Optional[Dict]
2727
timestamp=None, # type: Optional[datetime.datetime]
2828
message_id=None, # type: Optional[str]
29+
groups=None, # type: Optional[Dict]
2930
):
3031
# type: (...) -> None
3132
"""
@@ -38,10 +39,14 @@ def capture(
3839
3940
Optionally you can submit
4041
- `properties`, which can be a dict with any information you'd like to add
42+
- `groups`, which is a dict of group type -> group key mappings
4143
4244
For example:
4345
```python
46+
posthog.capture('distinct id', 'opened app')
4447
posthog.capture('distinct id', 'movie played', {'movie_id': '123', 'category': 'romcom'})
48+
49+
posthog.capture('distinct id', 'purchase', groups={'company': 'id:5'})
4550
```
4651
"""
4752
_proxy(
@@ -52,11 +57,12 @@ def capture(
5257
context=context,
5358
timestamp=timestamp,
5459
message_id=message_id,
60+
groups=groups,
5561
)
5662

5763

5864
def identify(
59-
distinct_id, # type: str,
65+
distinct_id, # type: str
6066
properties=None, # type: Optional[Dict]
6167
context=None, # type: Optional[Dict]
6268
timestamp=None, # type: Optional[datetime.datetime]
@@ -154,9 +160,39 @@ def set_once(
154160
)
155161

156162

157-
def group(*args, **kwargs):
158-
"""Send a group call."""
159-
_proxy("group", *args, **kwargs)
163+
def group_identify(
164+
group_type, # type: str
165+
group_key, # type: str
166+
properties=None, # type: Optional[Dict]
167+
context=None, # type: Optional[Dict]
168+
timestamp=None, # type: Optional[datetime.datetime]
169+
message_id=None, # type: Optional[str]
170+
):
171+
# type: (...) -> None
172+
"""
173+
Set properties on a group
174+
175+
A `set_once` call requires
176+
- `group_type` type of your group
177+
- `group_key` unique identifier of the group
178+
- `properties` with a dict with any key: value pairs
179+
180+
For example:
181+
```python
182+
posthog.group_identify('company', 5, {
183+
'employees': 11,
184+
})
185+
```
186+
"""
187+
_proxy(
188+
"group_identify",
189+
group_type=group_type,
190+
group_key=group_key,
191+
properties=properties,
192+
context=context,
193+
timestamp=timestamp,
194+
message_id=message_id,
195+
)
160196

161197

162198
def alias(

posthog/client.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ def identify(self, distinct_id=None, properties=None, context=None, timestamp=No
120120

121121
return self._enqueue(msg)
122122

123-
def capture(self, distinct_id=None, event=None, properties=None, context=None, timestamp=None, message_id=None):
123+
def capture(
124+
self, distinct_id=None, event=None, properties=None, context=None, timestamp=None, message_id=None, groups=None
125+
):
124126
properties = properties or {}
125127
context = context or {}
126128
require("distinct_id", distinct_id, ID_TYPES)
@@ -136,6 +138,10 @@ def capture(self, distinct_id=None, event=None, properties=None, context=None, t
136138
"messageId": message_id,
137139
}
138140

141+
if groups:
142+
require("groups", groups, dict)
143+
msg["properties"]["$groups"] = groups
144+
139145
return self._enqueue(msg)
140146

141147
def set(self, distinct_id=None, properties=None, context=None, timestamp=None, message_id=None):
@@ -172,6 +178,30 @@ def set_once(self, distinct_id=None, properties=None, context=None, timestamp=No
172178

173179
return self._enqueue(msg)
174180

181+
def group_identify(
182+
self, group_type=None, group_key=None, properties=None, context=None, timestamp=None, message_id=None
183+
):
184+
properties = properties or {}
185+
context = context or {}
186+
require("group_type", group_type, ID_TYPES)
187+
require("group_key", group_key, ID_TYPES)
188+
require("properties", properties, dict)
189+
190+
msg = {
191+
"event": "$groupidentify",
192+
"properties": {
193+
"$group_type": group_type,
194+
"$group_key": group_key,
195+
"$group_set": properties,
196+
},
197+
"distinct_id": "${}_{}".format(group_type, group_key),
198+
"timestamp": timestamp,
199+
"context": context,
200+
"messageId": message_id,
201+
}
202+
203+
return self._enqueue(msg)
204+
175205
def alias(self, previous_id=None, distinct_id=None, context=None, timestamp=None, message_id=None):
176206
context = context or {}
177207

posthog/test/test_client.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@ def test_advanced_capture(self):
9191
self.assertEqual(msg["properties"]["$lib_version"], VERSION)
9292
self.assertEqual(msg["messageId"], "messageId")
9393
self.assertEqual(msg["distinct_id"], "distinct_id")
94+
self.assertTrue("$groups" not in msg["properties"])
95+
96+
def test_groups_capture(self):
97+
success, msg = self.client.capture(
98+
"distinct_id",
99+
"test_event",
100+
groups={"company": "id:5", "instance": "app.posthog.com"},
101+
)
102+
103+
self.assertTrue(success)
104+
self.assertEqual(msg["properties"]["$groups"], {"company": "id:5", "instance": "app.posthog.com"})
94105

95106
def test_basic_identify(self):
96107
client = self.client
@@ -179,6 +190,46 @@ def test_advanced_set_once(self):
179190
self.assertEqual(msg["messageId"], "messageId")
180191
self.assertEqual(msg["distinct_id"], "distinct_id")
181192

193+
def test_basic_group_identify(self):
194+
success, msg = self.client.group_identify("organization", "id:5")
195+
196+
self.assertTrue(success)
197+
self.assertEqual(msg["event"], "$groupidentify")
198+
self.assertEqual(msg["distinct_id"], "$organization_id:5")
199+
self.assertEqual(
200+
msg["properties"],
201+
{
202+
"$group_type": "organization",
203+
"$group_key": "id:5",
204+
"$group_set": {},
205+
"$lib": "posthog-python",
206+
"$lib_version": VERSION,
207+
},
208+
)
209+
self.assertTrue(isinstance(msg["timestamp"], str))
210+
self.assertTrue(isinstance(msg["messageId"], str))
211+
212+
def test_advanced_group_identify(self):
213+
success, msg = self.client.group_identify(
214+
"organization", "id:5", {"trait": "value"}, {"ip": "192.168.0.1"}, datetime(2014, 9, 3), "messageId"
215+
)
216+
217+
self.assertTrue(success)
218+
self.assertEqual(msg["event"], "$groupidentify")
219+
self.assertEqual(msg["distinct_id"], "$organization_id:5")
220+
self.assertEqual(
221+
msg["properties"],
222+
{
223+
"$group_type": "organization",
224+
"$group_key": "id:5",
225+
"$group_set": {"trait": "value"},
226+
"$lib": "posthog-python",
227+
"$lib_version": VERSION,
228+
},
229+
)
230+
self.assertEqual(msg["timestamp"], "2014-09-03T00:00:00+00:00")
231+
self.assertEqual(msg["context"]["ip"], "192.168.0.1")
232+
182233
def test_basic_alias(self):
183234
client = self.client
184235
success, msg = client.alias("previousId", "distinct_id")

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"isort",
2323
"pre-commit",
2424
],
25-
"test": ["mock>=2.0.0", "freezegun==0.3.15", "pylint", "flake8", "coverage"],
25+
"test": ["mock>=2.0.0", "freezegun==0.3.15", "pylint", "flake8", "coverage", "pytest"],
2626
"sentry": ["sentry-sdk", "django"],
2727
}
2828

0 commit comments

Comments
 (0)