Skip to content

Commit 42e72a3

Browse files
committed
Merge branch 'master' into potel-base
2 parents 760aa90 + c1861a3 commit 42e72a3

File tree

4 files changed

+77
-43
lines changed

4 files changed

+77
-43
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ for your feedback. How was the migration? Is everything working as expected? Is
2020
[on GitHub](https://github.com/getsentry/sentry-python/discussions/3936) or
2121
[on Discord](https://discord.com/invite/Ww9hbqr).
2222

23+
## 2.34.1
24+
25+
### Various fixes & improvements
26+
27+
- Fix: Make sure Span data in AI instrumentations is always a primitive data type (#4643) by @antonpirker
28+
- Fix: Typo in CHANGELOG.md (#4640) by @jgillard
29+
2330
## 2.34.0
2431

2532
### Various fixes & improvements

sentry_sdk/integrations/openai.py

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
from sentry_sdk.tracing import Span
2222

2323
try:
24+
try:
25+
from openai import NOT_GIVEN
26+
except ImportError:
27+
NOT_GIVEN = None
28+
2429
from openai.resources.chat.completions import Completions, AsyncCompletions
2530
from openai.resources import Embeddings, AsyncEmbeddings
2631

@@ -196,12 +201,13 @@ def _set_input_data(
196201
}
197202
for key, attribute in kwargs_keys_to_attributes.items():
198203
value = kwargs.get(key)
199-
if value is not None:
204+
205+
if value is not NOT_GIVEN and value is not None:
200206
set_data_normalized(span, attribute, value)
201207

202208
# Input attributes: Tools
203209
tools = kwargs.get("tools")
204-
if tools is not None and len(tools) > 0:
210+
if tools is not NOT_GIVEN and tools is not None and len(tools) > 0:
205211
set_data_normalized(
206212
span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools)
207213
)
@@ -429,8 +435,7 @@ def _execute_sync(f: Any, *args: Any, **kwargs: Any) -> Any:
429435
return e.value
430436

431437
@wraps(f)
432-
def _sentry_patched_create_sync(*args, **kwargs):
433-
# type: (Any, Any) -> Any
438+
def _sentry_patched_create_sync(*args: Any, **kwargs: Any) -> Any:
434439
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
435440
if integration is None or "messages" not in kwargs:
436441
# no "messages" means invalid call (in all versions of openai), let it return error
@@ -441,10 +446,8 @@ def _sentry_patched_create_sync(*args, **kwargs):
441446
return _sentry_patched_create_sync
442447

443448

444-
def _wrap_async_chat_completion_create(f):
445-
# type: (Callable[..., Any]) -> Callable[..., Any]
446-
async def _execute_async(f, *args, **kwargs):
447-
# type: (Any, Any, Any) -> Any
449+
def _wrap_async_chat_completion_create(f: Callable[..., Any]) -> Callable[..., Any]:
450+
async def _execute_async(f: Any, *args: Any, **kwargs: Any) -> Any:
448451
gen = _new_chat_completion_common(f, *args, **kwargs)
449452

450453
try:
@@ -464,8 +467,7 @@ async def _execute_async(f, *args, **kwargs):
464467
return e.value
465468

466469
@wraps(f)
467-
async def _sentry_patched_create_async(*args, **kwargs):
468-
# type: (Any, Any) -> Any
470+
async def _sentry_patched_create_async(*args: Any, **kwargs: Any) -> Any:
469471
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
470472
if integration is None or "messages" not in kwargs:
471473
# no "messages" means invalid call (in all versions of openai), let it return error
@@ -476,8 +478,7 @@ async def _sentry_patched_create_async(*args, **kwargs):
476478
return _sentry_patched_create_async
477479

478480

479-
def _new_embeddings_create_common(f, *args, **kwargs):
480-
# type: (Any, Any, Any) -> Any
481+
def _new_embeddings_create_common(f: Any, *args: Any, **kwargs: Any) -> Any:
481482
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
482483
if integration is None:
483484
return f(*args, **kwargs)
@@ -499,10 +500,8 @@ def _new_embeddings_create_common(f, *args, **kwargs):
499500
return response
500501

501502

502-
def _wrap_embeddings_create(f):
503-
# type: (Any) -> Any
504-
def _execute_sync(f, *args, **kwargs):
505-
# type: (Any, Any, Any) -> Any
503+
def _wrap_embeddings_create(f: Any) -> Any:
504+
def _execute_sync(f: Any, *args: Any, **kwargs: Any) -> Any:
506505
gen = _new_embeddings_create_common(f, *args, **kwargs)
507506

508507
try:
@@ -522,8 +521,7 @@ def _execute_sync(f, *args, **kwargs):
522521
return e.value
523522

524523
@wraps(f)
525-
def _sentry_patched_create_sync(*args, **kwargs):
526-
# type: (Any, Any) -> Any
524+
def _sentry_patched_create_sync(*args: Any, **kwargs: Any) -> Any:
527525
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
528526
if integration is None:
529527
return f(*args, **kwargs)
@@ -533,10 +531,8 @@ def _sentry_patched_create_sync(*args, **kwargs):
533531
return _sentry_patched_create_sync
534532

535533

536-
def _wrap_async_embeddings_create(f):
537-
# type: (Any) -> Any
538-
async def _execute_async(f, *args, **kwargs):
539-
# type: (Any, Any, Any) -> Any
534+
def _wrap_async_embeddings_create(f: Any) -> Any:
535+
async def _execute_async(f: Any, *args: Any, **kwargs: Any):
540536
gen = _new_embeddings_create_common(f, *args, **kwargs)
541537

542538
try:
@@ -556,8 +552,7 @@ async def _execute_async(f, *args, **kwargs):
556552
return e.value
557553

558554
@wraps(f)
559-
async def _sentry_patched_create_async(*args, **kwargs):
560-
# type: (Any, Any) -> Any
555+
async def _sentry_patched_create_async(*args: Any, **kwargs: Any) -> Any:
561556
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
562557
if integration is None:
563558
return await f(*args, **kwargs)
@@ -567,8 +562,7 @@ async def _sentry_patched_create_async(*args, **kwargs):
567562
return _sentry_patched_create_async
568563

569564

570-
def _new_responses_create_common(f, *args, **kwargs):
571-
# type: (Any, Any, Any) -> Any
565+
def _new_responses_create_common(f: Any, *args: Any, **kwargs: Any) -> Any:
572566
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
573567
if integration is None:
574568
return f(*args, **kwargs)
@@ -592,10 +586,8 @@ def _new_responses_create_common(f, *args, **kwargs):
592586
return response
593587

594588

595-
def _wrap_responses_create(f):
596-
# type: (Any) -> Any
597-
def _execute_sync(f, *args, **kwargs):
598-
# type: (Any, Any, Any) -> Any
589+
def _wrap_responses_create(f: Any) -> Any:
590+
def _execute_sync(f: Any, *args: Any, **kwargs: Any) -> Any:
599591
gen = _new_responses_create_common(f, *args, **kwargs)
600592

601593
try:
@@ -615,8 +607,7 @@ def _execute_sync(f, *args, **kwargs):
615607
return e.value
616608

617609
@wraps(f)
618-
def _sentry_patched_create_sync(*args, **kwargs):
619-
# type: (Any, Any) -> Any
610+
def _sentry_patched_create_sync(*args: Any, **kwargs: Any) -> Any:
620611
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
621612
if integration is None:
622613
return f(*args, **kwargs)
@@ -626,10 +617,8 @@ def _sentry_patched_create_sync(*args, **kwargs):
626617
return _sentry_patched_create_sync
627618

628619

629-
def _wrap_async_responses_create(f):
630-
# type: (Any) -> Any
631-
async def _execute_async(f, *args, **kwargs):
632-
# type: (Any, Any, Any) -> Any
620+
def _wrap_async_responses_create(f: Any) -> Any:
621+
async def _execute_async(f: Any, *args: Any, **kwargs: Any):
633622
gen = _new_responses_create_common(f, *args, **kwargs)
634623

635624
try:
@@ -649,8 +638,7 @@ async def _execute_async(f, *args, **kwargs):
649638
return e.value
650639

651640
@wraps(f)
652-
async def _sentry_patched_responses_async(*args, **kwargs):
653-
# type: (Any, Any) -> Any
641+
async def _sentry_patched_responses_async(*args: Any, **kwargs: Any) -> Any:
654642
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
655643
if integration is None:
656644
return await f(*args, **kwargs)

sentry_sdk/integrations/openfeature.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from __future__ import annotations
2-
from typing import TYPE_CHECKING
2+
from typing import TYPE_CHECKING, Any
33

44
from sentry_sdk.feature_flags import add_feature_flag
55
from sentry_sdk.integrations import DidNotEnable, Integration
@@ -9,7 +9,6 @@
99
from openfeature.hook import Hook
1010

1111
if TYPE_CHECKING:
12-
from openfeature.flag_evaluation import FlagEvaluationDetails
1312
from openfeature.hook import HookContext, HookHints
1413
except ImportError:
1514
raise DidNotEnable("OpenFeature is not installed")
@@ -28,9 +27,9 @@ class OpenFeatureHook(Hook):
2827

2928
def after(
3029
self,
31-
hook_context: HookContext,
32-
details: FlagEvaluationDetails[bool],
33-
hints: HookHints,
30+
hook_context: Any,
31+
details: Any,
32+
hints: Any,
3433
) -> None:
3534
if isinstance(details.value, bool):
3635
add_feature_flag(details.flag_key, details.value)

tests/integrations/openai/test_openai.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
import pytest
2+
3+
from sentry_sdk.utils import package_version
4+
5+
try:
6+
from openai import NOT_GIVEN
7+
except ImportError:
8+
NOT_GIVEN = None
9+
210
from openai import AsyncOpenAI, OpenAI, AsyncStream, Stream, OpenAIError
311
from openai.types import CompletionUsage, CreateEmbeddingResponse, Embedding
412
from openai.types.chat import ChatCompletion, ChatCompletionMessage, ChatCompletionChunk
@@ -43,6 +51,7 @@ async def __call__(self, *args, **kwargs):
4351
return super(AsyncMock, self).__call__(*args, **kwargs)
4452

4553

54+
OPENAI_VERSION = package_version("openai")
4655
EXAMPLE_CHAT_COMPLETION = ChatCompletion(
4756
id="chat-id",
4857
choices=[
@@ -1418,3 +1427,34 @@ async def test_streaming_responses_api_async(
14181427
assert span["data"]["gen_ai.usage.input_tokens"] == 20
14191428
assert span["data"]["gen_ai.usage.output_tokens"] == 10
14201429
assert span["data"]["gen_ai.usage.total_tokens"] == 30
1430+
1431+
1432+
@pytest.mark.skipif(
1433+
OPENAI_VERSION <= (1, 1, 0),
1434+
reason="OpenAI versions <=1.1.0 do not support the tools parameter.",
1435+
)
1436+
@pytest.mark.parametrize(
1437+
"tools",
1438+
[[], None, NOT_GIVEN],
1439+
)
1440+
def test_empty_tools_in_chat_completion(sentry_init, capture_events, tools):
1441+
sentry_init(
1442+
integrations=[OpenAIIntegration()],
1443+
traces_sample_rate=1.0,
1444+
)
1445+
events = capture_events()
1446+
1447+
client = OpenAI(api_key="z")
1448+
client.chat.completions._post = mock.Mock(return_value=EXAMPLE_CHAT_COMPLETION)
1449+
1450+
with sentry_sdk.start_span(name="openai tx"):
1451+
client.chat.completions.create(
1452+
model="some-model",
1453+
messages=[{"role": "system", "content": "hello"}],
1454+
tools=tools,
1455+
)
1456+
1457+
(event,) = events
1458+
span = event["spans"][0]
1459+
1460+
assert "gen_ai.request.available_tools" not in span["data"]

0 commit comments

Comments
 (0)