Skip to content

Commit c8104b8

Browse files
committed
Patch an UnleashClient instance instead of the class
1 parent b773e49 commit c8104b8

File tree

2 files changed

+60
-69
lines changed

2 files changed

+60
-69
lines changed

sentry_sdk/integrations/unleash.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,39 @@
55
from sentry_sdk.flag_utils import flag_error_processor
66
from sentry_sdk.integrations import Integration, DidNotEnable
77

8-
try:
9-
from UnleashClient import UnleashClient
10-
except ImportError:
11-
raise DidNotEnable("UnleashClient is not installed")
12-
138
if TYPE_CHECKING:
14-
from typing import Any
9+
from typing import Any, Optional
10+
11+
try:
12+
from UnleashClient import UnleashClient
13+
except ImportError:
14+
raise DidNotEnable("UnleashClient is not installed")
1515

1616

1717
class UnleashIntegration(Integration):
1818
identifier = "unleash"
19+
_unleash_client = None # type: Optional[UnleashClient]
20+
21+
def __init__(self, unleash_client):
22+
# type: (Optional[UnleashClient]) -> None
23+
self.__class__._unleash_client = unleash_client
1924

2025
@staticmethod
2126
def setup_once():
2227
# type: () -> None
2328

24-
# Wrap and patch evaluation functions
25-
old_is_enabled = UnleashClient.is_enabled
26-
old_get_variant = UnleashClient.get_variant
29+
client = UnleashIntegration._unleash_client
30+
if not client:
31+
raise DidNotEnable("Error getting UnleashClient instance")
32+
33+
# Wrap and patch evaluation methods (instance methods)
34+
old_is_enabled = client.is_enabled
35+
old_get_variant = client.get_variant
2736

2837
@wraps(old_is_enabled)
29-
def sentry_is_enabled(self, feature, *a, **kw):
30-
# type: (UnleashClient, str, *Any, **Any) -> Any
31-
enabled = old_is_enabled(self, feature, *a, **kw)
38+
def sentry_is_enabled(feature, *a, **kw):
39+
# type: (str, *Any, **Any) -> Any
40+
enabled = old_is_enabled(feature, *a, **kw)
3241

3342
# We have no way of knowing what type of unleash feature this is, so we have to treat
3443
# it as a boolean / toggle feature.
@@ -38,9 +47,9 @@ def sentry_is_enabled(self, feature, *a, **kw):
3847
return enabled
3948

4049
@wraps(old_get_variant)
41-
def sentry_get_variant(self, feature, *a, **kw):
42-
# type: (UnleashClient, str, *Any, **Any) -> Any
43-
variant = old_get_variant(self, feature, *a, **kw)
50+
def sentry_get_variant(feature, *a, **kw):
51+
# type: (str, *Any, **Any) -> Any
52+
variant = old_get_variant(feature, *a, **kw)
4453
enabled = variant.get("enabled", False)
4554
# _payload_type = variant.get("payload", {}).get("type")
4655

@@ -51,8 +60,8 @@ def sentry_get_variant(self, feature, *a, **kw):
5160
flags.set(feature, enabled)
5261
return variant
5362

54-
UnleashClient.is_enabled = sentry_is_enabled # type: ignore
55-
UnleashClient.get_variant = sentry_get_variant # type: ignore
63+
client.is_enabled = sentry_is_enabled # type: ignore
64+
client.get_variant = sentry_get_variant # type: ignore
5665

5766
# Error processor
5867
scope = sentry_sdk.get_current_scope()

tests/integrations/unleash/test_unleash.py

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
import concurrent.futures as cf
22
import sys
33
from random import random
4-
from unittest.mock import patch
4+
from unittest import mock
55

66
import pytest
77

88
import sentry_sdk
99
from sentry_sdk.integrations.unleash import UnleashIntegration
1010
from tests.integrations.unleash.testutils import MockUnleashClient
1111

12-
original_is_enabled = MockUnleashClient.is_enabled
13-
original_get_variant = MockUnleashClient.get_variant
1412

15-
16-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
1713
def test_is_enabled(sentry_init, capture_events, uninstall_integration):
1814
client = MockUnleashClient()
1915
uninstall_integration(UnleashIntegration)
20-
sentry_init(integrations=[UnleashIntegration()])
16+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
2117

2218
client.is_enabled("hello")
2319
client.is_enabled("world")
@@ -36,11 +32,10 @@ def test_is_enabled(sentry_init, capture_events, uninstall_integration):
3632
}
3733

3834

39-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
4035
def test_get_variant(sentry_init, capture_events, uninstall_integration):
4136
client = MockUnleashClient()
4237
uninstall_integration(UnleashIntegration)
43-
sentry_init(integrations=[UnleashIntegration()])
38+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
4439

4540
client.get_variant("no_payload_feature")
4641
client.get_variant("string_feature")
@@ -65,11 +60,10 @@ def test_get_variant(sentry_init, capture_events, uninstall_integration):
6560
}
6661

6762

68-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
6963
def test_is_enabled_threaded(sentry_init, capture_events, uninstall_integration):
7064
client = MockUnleashClient()
7165
uninstall_integration(UnleashIntegration)
72-
sentry_init(integrations=[UnleashIntegration()])
66+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
7367
events = capture_events()
7468

7569
def task(flag_key):
@@ -113,11 +107,10 @@ def task(flag_key):
113107
}
114108

115109

116-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
117110
def test_get_variant_threaded(sentry_init, capture_events, uninstall_integration):
118111
client = MockUnleashClient()
119112
uninstall_integration(UnleashIntegration)
120-
sentry_init(integrations=[UnleashIntegration()])
113+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
121114
events = capture_events()
122115

123116
def task(flag_key):
@@ -162,13 +155,12 @@ def task(flag_key):
162155

163156

164157
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher")
165-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
166158
def test_is_enabled_asyncio(sentry_init, capture_events, uninstall_integration):
167159
asyncio = pytest.importorskip("asyncio")
168160

169161
client = MockUnleashClient()
170162
uninstall_integration(UnleashIntegration)
171-
sentry_init(integrations=[UnleashIntegration()])
163+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
172164
events = capture_events()
173165

174166
async def task(flag_key):
@@ -213,13 +205,12 @@ async def runner():
213205

214206

215207
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher")
216-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
217208
def test_get_variant_asyncio(sentry_init, capture_events, uninstall_integration):
218209
asyncio = pytest.importorskip("asyncio")
219210

220211
client = MockUnleashClient()
221212
uninstall_integration(UnleashIntegration)
222-
sentry_init(integrations=[UnleashIntegration()])
213+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
223214
events = capture_events()
224215

225216
async def task(flag_key):
@@ -263,50 +254,41 @@ async def runner():
263254
}
264255

265256

266-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
267257
def test_wraps_original(sentry_init, uninstall_integration):
258+
client = MockUnleashClient()
259+
mock_is_enabled = mock.Mock(return_value=random() < 0.5)
260+
client.is_enabled = mock_is_enabled
261+
mock_get_variant = mock.Mock(return_value={"enabled": random() < 0.5})
262+
client.get_variant = mock_get_variant
263+
268264
uninstall_integration(UnleashIntegration)
265+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
266+
267+
res = client.is_enabled("test-flag", "arg", kwarg=1)
268+
assert res == mock_is_enabled.return_value
269+
assert mock_is_enabled.call_args == (
270+
("test-flag", "arg"),
271+
{"kwarg": 1},
272+
)
273+
274+
res = client.get_variant("test-flag", "arg", kwarg=1)
275+
assert res == mock_get_variant.return_value
276+
assert mock_get_variant.call_args == (
277+
("test-flag", "arg"),
278+
{"kwarg": 1},
279+
)
280+
269281

270-
with patch(
271-
"sentry_sdk.integrations.unleash.UnleashClient.is_enabled"
272-
) as mock_is_enabled:
273-
with patch(
274-
"sentry_sdk.integrations.unleash.UnleashClient.get_variant"
275-
) as mock_get_variant:
276-
mock_is_enabled.return_value = random() < 0.5
277-
mock_get_variant.return_value = {"enabled": random() < 0.5}
278-
sentry_init(integrations=[UnleashIntegration()])
279-
client = MockUnleashClient()
280-
281-
res = client.is_enabled("test-flag", "arg", kwarg=1)
282-
assert res == mock_is_enabled.return_value
283-
assert mock_is_enabled.call_args == (
284-
(client, "test-flag", "arg"),
285-
{"kwarg": 1},
286-
)
287-
288-
res = client.get_variant("test-flag", "arg", kwarg=1)
289-
assert res == mock_get_variant.return_value
290-
assert mock_get_variant.call_args == (
291-
(client, "test-flag", "arg"),
292-
{"kwarg": 1},
293-
)
294-
295-
296-
@patch("sentry_sdk.integrations.unleash.UnleashClient", MockUnleashClient)
297282
def test_wrapper_attributes(sentry_init, uninstall_integration):
283+
client = MockUnleashClient()
284+
original_is_enabled = client.is_enabled
285+
original_get_variant = client.get_variant
286+
298287
uninstall_integration(UnleashIntegration)
299-
sentry_init(integrations=[UnleashIntegration()])
288+
sentry_init(integrations=[UnleashIntegration(client)]) # type: ignore
300289

301-
client = MockUnleashClient()
302290
assert client.is_enabled.__name__ == "is_enabled"
303291
assert client.is_enabled.__qualname__ == original_is_enabled.__qualname__
304-
assert MockUnleashClient.is_enabled.__name__ == "is_enabled"
305-
assert MockUnleashClient.is_enabled.__qualname__ == original_is_enabled.__qualname__
306292

307293
assert client.get_variant.__name__ == "get_variant"
308294
assert client.get_variant.__qualname__ == original_get_variant.__qualname__
309-
assert MockUnleashClient.get_variant.__name__ == "get_variant"
310-
assert (
311-
MockUnleashClient.get_variant.__qualname__ == original_get_variant.__qualname__
312-
)

0 commit comments

Comments
 (0)