Skip to content

Commit 7a5498f

Browse files
Sihem TchabiSihem Tchabi
authored andcommitted
fix(LAB-4118): add a warning log to inform the user he uses a deprecated field
1 parent 994dc17 commit 7a5498f

File tree

3 files changed

+90
-29
lines changed

3 files changed

+90
-29
lines changed

src/kili/core/graphql/graphql_client.py

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import threading
66
import time
7+
import warnings
78
from pathlib import Path
89
from typing import Any, Optional, Union
910
from urllib.parse import urlparse
@@ -322,20 +323,48 @@ def _raw_execute(
322323
log_context = LogContext()
323324
log_context.set_client_name(self.client_name)
324325
with _execute_lock:
325-
res = self._gql_client.execute(
326-
document=document,
327-
variable_values=variables,
328-
extra_args={
329-
"headers": {
330-
**(self._gql_transport.headers or {}),
331-
**log_context,
332-
}
333-
},
334-
**kwargs,
335-
)
336-
transport = self._gql_client.transport
337-
if transport:
338-
headers = transport.response_headers # pyright: ignore[reportAttributeAccessIssue]
339-
returned_complexity = int(headers.get("x-complexity", 0)) if headers else 0
340-
self.complexity_consumed += returned_complexity
341-
return res
326+
with self._gql_client as session:
327+
transport = session.transport
328+
if transport is None:
329+
raise RuntimeError("GraphQL transport not initialized")
330+
331+
res = transport.execute(
332+
document=document,
333+
variable_values=variables,
334+
extra_args={
335+
"headers": {
336+
**(self._gql_transport.headers or {}),
337+
**log_context,
338+
}
339+
},
340+
**kwargs,
341+
)
342+
343+
extensions = getattr(res, "extensions", None)
344+
if isinstance(extensions, dict):
345+
for item in extensions.get("deprecations", []) or []:
346+
warnings.warn(
347+
f"[Kili SDK] Deprecated GraphQL field used: "
348+
f"{item.get('path')}{item.get('reason')}"
349+
)
350+
351+
headers = getattr(transport, "response_headers", None)
352+
if isinstance(headers, dict) and "x-complexity" in headers:
353+
try:
354+
self.complexity_consumed += int(headers["x-complexity"])
355+
except (TypeError, ValueError):
356+
pass
357+
358+
if isinstance(res, dict):
359+
return res
360+
361+
data = getattr(res, "data", None)
362+
if data is None:
363+
raise kili.exceptions.GraphQLError(
364+
error="GraphQL response contains no data",
365+
)
366+
367+
if isinstance(data, dict) and "data" in data:
368+
return data
369+
370+
return {"data": data}

tests/integration/entrypoints/client/test_client.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import pytest
88
import pytest_mock
99
from filelock import FileLock
10+
from graphql import ExecutionResult
1011

1112
from kili.adapters.kili_api_gateway.kili_api_gateway import KiliAPIGateway
1213
from kili.client import Kili
@@ -147,10 +148,11 @@ def test_complexity_increases_with_calls(
147148
mocker: pytest_mock.MockerFixture,
148149
):
149150
graphql_mock = mocker.MagicMock()
150-
graphql_mock.execute.return_value = {"data": 1}
151-
graphql_mock.transport.response_headers = {"x-complexity": "125"}
151+
graphql_mock.__enter__.return_value.transport.execute.return_value = ExecutionResult(
152+
data={"data": 1}, extensions=None
153+
)
154+
graphql_mock.__enter__.return_value.transport.response_headers = {"x-complexity": "125"}
152155

153-
# Given
154156
mocker.patch("kili.client.is_api_key_valid", return_value=True)
155157
mocker.patch.object(ApiKeyUseCases, "check_expiry_of_key_is_close")
156158
mocker.patch(
@@ -172,8 +174,10 @@ def test_complexity_compatibility_with_legacy(
172174
mocker: pytest_mock.MockerFixture,
173175
):
174176
graphql_mock = mocker.MagicMock()
175-
graphql_mock.execute.return_value = {"data": 1}
176-
graphql_mock.transport.response_headers = {}
177+
graphql_mock.__enter__.return_value.transport.execute.return_value = ExecutionResult(
178+
data={"data": 1}, extensions=None
179+
)
180+
graphql_mock.__enter__.return_value.transport.response_headers = {}
177181

178182
# Given
179183
mocker.patch("kili.client.is_api_key_valid", return_value=True)

tests/unit/test_graphql_client.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import pytest
55
import pytest_mock
6-
from gql import Client
76
from gql.transport import exceptions
87
from pyrate_limiter import Duration, Rate
98
from pyrate_limiter.limiter import Limiter
@@ -88,9 +87,20 @@ def mock_execute(*args, **kwargs):
8887
nonlocal before_last_call_timestamp
8988
before_last_call_timestamp = last_call_timestamp
9089
last_call_timestamp = time()
90+
return {"data": 1}
9191

92-
client._gql_client = mocker.MagicMock()
93-
client._gql_client.execute.side_effect = mock_execute
92+
transport_mock = mocker.MagicMock()
93+
transport_mock.execute.side_effect = mock_execute
94+
transport_mock.response_headers = {}
95+
96+
session_mock = mocker.MagicMock()
97+
session_mock.transport = transport_mock
98+
99+
gql_client_mock = mocker.MagicMock()
100+
gql_client_mock.__enter__.return_value = session_mock
101+
gql_client_mock.__exit__.return_value = None
102+
103+
client._gql_client = gql_client_mock
94104

95105
# first calls should not be rate limited
96106
for _ in range(MAX_CALLS_PER_MINUTE):
@@ -130,7 +140,15 @@ def mocked_backend_response(*args, **kwargs):
130140
extensions=None,
131141
)
132142

133-
mocked_execute = mocker.patch.object(Client, "execute", side_effect=mocked_backend_response)
143+
transport_mock = mocker.MagicMock()
144+
transport_mock.execute.side_effect = mocked_backend_response
145+
146+
session_mock = mocker.MagicMock()
147+
session_mock.transport = transport_mock
148+
149+
gql_client_mock = mocker.MagicMock()
150+
gql_client_mock.__enter__.return_value = session_mock
151+
gql_client_mock.__exit__.return_value = None
134152

135153
# Given
136154
client = GraphQLClient(
@@ -143,12 +161,13 @@ def mocked_backend_response(*args, **kwargs):
143161
enable_schema_caching=False,
144162
)
145163

164+
client._gql_client = gql_client_mock
146165
with pytest.raises(
147166
GraphQLError, match=r'Variable "(\$\w+)" of required type "(\w+!)" was not provided.'
148167
):
149168
client.execute(query="fake_query") # When
150169

151-
assert mocked_execute.call_count == nb_times_called == 1
170+
assert nb_times_called == 1
152171

153172

154173
def test_given_gql_client_when_the_server_returns_flagsmith_error_then_it_retries(
@@ -207,7 +226,15 @@ def mocked_backend_response(*args, **kwargs):
207226
data={"data": None},
208227
)
209228

210-
mocked_execute = mocker.patch.object(Client, "execute", side_effect=mocked_backend_response)
229+
transport_mock = mocker.MagicMock()
230+
transport_mock.execute.side_effect = mocked_backend_response
231+
232+
session_mock = mocker.MagicMock()
233+
session_mock.transport = transport_mock
234+
235+
gql_client_mock = mocker.MagicMock()
236+
gql_client_mock.__enter__.return_value = session_mock
237+
gql_client_mock.__exit__.return_value = None
211238

212239
# Given
213240
client = GraphQLClient(
@@ -220,12 +247,13 @@ def mocked_backend_response(*args, **kwargs):
220247
enable_schema_caching=False,
221248
)
222249

250+
client._gql_client = gql_client_mock
223251
# When
224252
result = client.execute(query="fake_query")
225253

226254
# Then
227255
assert result["data"] == "all good"
228-
assert mocked_execute.call_count == nb_times_called == 3
256+
assert nb_times_called == 3
229257

230258

231259
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)