Skip to content

Commit 3bac5b5

Browse files
committed
Fix type handling and add stub modules for Python tracking tests
1 parent 2f6ed58 commit 3bac5b5

File tree

3 files changed

+42
-19
lines changed

3 files changed

+42
-19
lines changed

src/analyze/python/pythonTrackingAnalyzer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def extract_type_annotation(self, annotation: ast.AST) -> PropertyType:
170170
# Handle generic types like List[int], Dict[str, int]
171171
container_type = getattr(annotation.value, 'id', None)
172172
if container_type is None and isinstance(annotation.value, ast.Attribute):
173-
container_type = getattr(annotation.value.attr, 'id', None) or annotation.value.attr
173+
container_type = getattr(annotation.value, 'attr', None)
174174

175175
if container_type:
176176

@@ -284,7 +284,7 @@ def _detect_method_call_source(self, node: ast.Call) -> Optional[str]:
284284
return None
285285

286286
obj_id = _safe_id(obj_val) or ''
287-
method_name = node.func.attr
287+
method_name = getattr(node.func, 'attr', '')
288288

289289
# Check standard analytics libraries
290290
for source, config in ANALYTICS_SOURCES.items():

tests/analyzePython.test.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ test.describe('analyzePythonFile', () => {
2222
assert.ok(segmentEvent);
2323
assert.strictEqual(segmentEvent.source, 'segment');
2424
assert.strictEqual(segmentEvent.functionName, 'segment_track');
25-
assert.strictEqual(segmentEvent.line, 41);
25+
assert.strictEqual(segmentEvent.line, 64);
2626
assert.deepStrictEqual(segmentEvent.properties, {
2727
user_id: { type: 'string' },
2828
method: { type: 'string' },
@@ -35,7 +35,7 @@ test.describe('analyzePythonFile', () => {
3535
assert.ok(mixpanelEvent);
3636
assert.strictEqual(mixpanelEvent.source, 'mixpanel');
3737
assert.strictEqual(mixpanelEvent.functionName, 'mixpanel_track');
38-
assert.strictEqual(mixpanelEvent.line, 51);
38+
assert.strictEqual(mixpanelEvent.line, 74);
3939
assert.deepStrictEqual(mixpanelEvent.properties, {
4040
distinct_id: { type: 'string' },
4141
plan: { type: 'string' },
@@ -48,7 +48,7 @@ test.describe('analyzePythonFile', () => {
4848
assert.ok(amplitudeEvent);
4949
assert.strictEqual(amplitudeEvent.source, 'amplitude');
5050
assert.strictEqual(amplitudeEvent.functionName, 'amplitude_track');
51-
assert.strictEqual(amplitudeEvent.line, 61);
51+
assert.strictEqual(amplitudeEvent.line, 84);
5252
assert.deepStrictEqual(amplitudeEvent.properties, {
5353
user_id: { type: 'string' },
5454
color: { type: 'string' },
@@ -60,7 +60,7 @@ test.describe('analyzePythonFile', () => {
6060
assert.ok(rudderstackEvent);
6161
assert.strictEqual(rudderstackEvent.source, 'rudderstack');
6262
assert.strictEqual(rudderstackEvent.functionName, 'rudderstack_track');
63-
assert.strictEqual(rudderstackEvent.line, 77);
63+
assert.strictEqual(rudderstackEvent.line, 100);
6464
assert.deepStrictEqual(rudderstackEvent.properties, {
6565
user_id: { type: 'string' },
6666
timestamp: { type: 'number' },
@@ -73,7 +73,7 @@ test.describe('analyzePythonFile', () => {
7373
assert.ok(posthogEvent1);
7474
assert.strictEqual(posthogEvent1.source, 'posthog');
7575
assert.strictEqual(posthogEvent1.functionName, 'posthog_capture');
76-
assert.strictEqual(posthogEvent1.line, 88);
76+
assert.strictEqual(posthogEvent1.line, 111);
7777
assert.deepStrictEqual(posthogEvent1.properties, {
7878
method: { type: 'string' },
7979
is_free_trial: { type: 'boolean' },
@@ -84,7 +84,7 @@ test.describe('analyzePythonFile', () => {
8484
assert.ok(posthogEvent2);
8585
assert.strictEqual(posthogEvent2.source, 'posthog');
8686
assert.strictEqual(posthogEvent2.functionName, 'posthog_capture');
87-
assert.strictEqual(posthogEvent2.line, 94);
87+
assert.strictEqual(posthogEvent2.line, 117);
8888
assert.deepStrictEqual(posthogEvent2.properties, {
8989
method: { type: 'string' },
9090
is_free_trial: { type: 'boolean' },
@@ -96,7 +96,7 @@ test.describe('analyzePythonFile', () => {
9696
assert.ok(snowplowEvent);
9797
assert.strictEqual(snowplowEvent.source, 'snowplow');
9898
assert.strictEqual(snowplowEvent.functionName, 'snowplow_track_events');
99-
assert.strictEqual(snowplowEvent.line, 104);
99+
assert.strictEqual(snowplowEvent.line, 127);
100100
assert.deepStrictEqual(snowplowEvent.properties, {
101101
category: { type: 'string' },
102102
label: { type: 'string' },
@@ -109,7 +109,7 @@ test.describe('analyzePythonFile', () => {
109109
assert.ok(customEvent);
110110
assert.strictEqual(customEvent.source, 'custom');
111111
assert.strictEqual(customEvent.functionName, 'main');
112-
assert.strictEqual(customEvent.line, 119);
112+
assert.strictEqual(customEvent.line, 142);
113113
assert.deepStrictEqual(customEvent.properties, {
114114
userId: { type: 'string' },
115115
key: { type: 'string' },
@@ -178,7 +178,7 @@ test.describe('analyzePythonFile', () => {
178178
assert.ok(eventMap['User Signed Up']);
179179
assert.strictEqual(eventMap['User Signed Up'].eventName, 'User Signed Up');
180180
assert.strictEqual(eventMap['User Signed Up'].source, 'segment');
181-
assert.strictEqual(eventMap['User Signed Up'].line, 41);
181+
assert.strictEqual(eventMap['User Signed Up'].line, 64);
182182
assert.strictEqual(eventMap['User Signed Up'].functionName, 'segment_track');
183183
assert.deepStrictEqual(eventMap['User Signed Up'].properties, {
184184
user_id: { type: 'string' },
@@ -190,7 +190,7 @@ test.describe('analyzePythonFile', () => {
190190
assert.ok(eventMap['Purchase Completed']);
191191
assert.strictEqual(eventMap['Purchase Completed'].eventName, 'Purchase Completed');
192192
assert.strictEqual(eventMap['Purchase Completed'].source, 'mixpanel');
193-
assert.strictEqual(eventMap['Purchase Completed'].line, 51);
193+
assert.strictEqual(eventMap['Purchase Completed'].line, 74);
194194
assert.strictEqual(eventMap['Purchase Completed'].functionName, 'mixpanel_track');
195195
assert.deepStrictEqual(eventMap['Purchase Completed'].properties, {
196196
distinct_id: { type: 'string' },
@@ -202,7 +202,7 @@ test.describe('analyzePythonFile', () => {
202202
assert.ok(eventMap['Button Clicked']);
203203
assert.strictEqual(eventMap['Button Clicked'].eventName, 'Button Clicked');
204204
assert.strictEqual(eventMap['Button Clicked'].source, 'amplitude');
205-
assert.strictEqual(eventMap['Button Clicked'].line, 61);
205+
assert.strictEqual(eventMap['Button Clicked'].line, 84);
206206
assert.strictEqual(eventMap['Button Clicked'].functionName, 'amplitude_track');
207207
assert.deepStrictEqual(eventMap['Button Clicked'].properties, {
208208
user_id: { type: 'string' },
@@ -213,7 +213,7 @@ test.describe('analyzePythonFile', () => {
213213
assert.ok(eventMap['User Logged In']);
214214
assert.strictEqual(eventMap['User Logged In'].eventName, 'User Logged In');
215215
assert.strictEqual(eventMap['User Logged In'].source, 'rudderstack');
216-
assert.strictEqual(eventMap['User Logged In'].line, 77);
216+
assert.strictEqual(eventMap['User Logged In'].line, 100);
217217
assert.strictEqual(eventMap['User Logged In'].functionName, 'rudderstack_track');
218218
assert.deepStrictEqual(eventMap['User Logged In'].properties, {
219219
user_id: { type: 'string' },
@@ -225,7 +225,7 @@ test.describe('analyzePythonFile', () => {
225225
assert.ok(eventMap['user_signed_up']);
226226
assert.strictEqual(eventMap['user_signed_up'].eventName, 'user_signed_up');
227227
assert.strictEqual(eventMap['user_signed_up'].source, 'posthog');
228-
assert.strictEqual(eventMap['user_signed_up'].line, 88);
228+
assert.strictEqual(eventMap['user_signed_up'].line, 111);
229229
assert.strictEqual(eventMap['user_signed_up'].functionName, 'posthog_capture');
230230
assert.deepStrictEqual(eventMap['user_signed_up'].properties, {
231231
method: { type: 'string' },
@@ -236,7 +236,7 @@ test.describe('analyzePythonFile', () => {
236236
assert.ok(eventMap['user_cancelled_subscription']);
237237
assert.strictEqual(eventMap['user_cancelled_subscription'].eventName, 'user_cancelled_subscription');
238238
assert.strictEqual(eventMap['user_cancelled_subscription'].source, 'posthog');
239-
assert.strictEqual(eventMap['user_cancelled_subscription'].line, 94);
239+
assert.strictEqual(eventMap['user_cancelled_subscription'].line, 117);
240240
assert.strictEqual(eventMap['user_cancelled_subscription'].functionName, 'posthog_capture');
241241
assert.deepStrictEqual(eventMap['user_cancelled_subscription'].properties, {
242242
method: { type: 'string' },
@@ -247,7 +247,7 @@ test.describe('analyzePythonFile', () => {
247247
assert.ok(eventMap['add-to-basket']);
248248
assert.strictEqual(eventMap['add-to-basket'].eventName, 'add-to-basket');
249249
assert.strictEqual(eventMap['add-to-basket'].source, 'snowplow');
250-
assert.strictEqual(eventMap['add-to-basket'].line, 104);
250+
assert.strictEqual(eventMap['add-to-basket'].line, 127);
251251
assert.strictEqual(eventMap['add-to-basket'].functionName, 'snowplow_track_events');
252252
assert.deepStrictEqual(eventMap['add-to-basket'].properties, {
253253
category: { type: 'string' },
@@ -259,7 +259,7 @@ test.describe('analyzePythonFile', () => {
259259
assert.ok(eventMap['custom_event']);
260260
assert.strictEqual(eventMap['custom_event'].eventName, 'custom_event');
261261
assert.strictEqual(eventMap['custom_event'].source, 'custom');
262-
assert.strictEqual(eventMap['custom_event'].line, 119);
262+
assert.strictEqual(eventMap['custom_event'].line, 142);
263263
assert.strictEqual(eventMap['custom_event'].functionName, 'main');
264264
assert.deepStrictEqual(eventMap['custom_event'].properties, {
265265
userId: { type: 'string' },

tests/fixtures/python/main.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import sys
1414
from types import ModuleType
1515

16-
_stub_modules = [
16+
_stub_modules = [ # type: ignore[var-annotated]
1717
'segment',
1818
'segment.analytics',
1919
'mixpanel',
@@ -30,6 +30,29 @@
3030
if _name not in sys.modules:
3131
sys.modules[_name] = ModuleType(_name)
3232

33+
# Add minimal attributes/classes used in tests
34+
amplitude_mod = sys.modules.get('amplitude') # type: ignore[var-annotated]
35+
if amplitude_mod:
36+
class Amplitude: # type: ignore[too-many-instance-attributes]
37+
def __init__(self, *args, **kwargs):
38+
pass
39+
def track(self, *args, **kwargs): # type: ignore[no-self-use]
40+
pass
41+
class BaseEvent: # type: ignore[too-many-instance-attributes]
42+
def __init__(self, *args, **kwargs):
43+
pass
44+
amplitude_mod.Amplitude = Amplitude # type: ignore[attr-defined]
45+
amplitude_mod.BaseEvent = BaseEvent # type: ignore[attr-defined]
46+
47+
posthog_mod = sys.modules.get('posthog') # type: ignore[var-annotated]
48+
if posthog_mod and not hasattr(posthog_mod, 'Posthog'):
49+
class Posthog: # type: ignore[too-many-instance-attributes]
50+
def __init__(self, *args, **kwargs):
51+
pass
52+
def capture(self, *args, **kwargs): # type: ignore[no-self-use]
53+
pass
54+
posthog_mod.Posthog = Posthog # type: ignore[attr-defined]
55+
3356
# Custom tracking function stub
3457
def customTrackFunction(user_id: str, event_name: str, params: Dict[str, Any]) -> None:
3558
print(f"Custom track: {user_id} - {event_name} - {params}")

0 commit comments

Comments
 (0)