Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 15 additions & 100 deletions tests/integrations/huggingface_hub/test_huggingface_hub.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import re
from typing import TYPE_CHECKING
from unittest import mock

import pytest
import responses
Expand All @@ -10,6 +9,7 @@
from sentry_sdk.consts import SPANDATA
from sentry_sdk.integrations.huggingface_hub import HuggingfaceHubIntegration
from sentry_sdk.utils import package_version, safe_serialize
from tests.conftest import ApproxDict

try:
from huggingface_hub.utils._errors import HfHubHTTPError
Expand Down Expand Up @@ -522,19 +522,8 @@
"gen_ai.response.finish_reasons": "length",
"gen_ai.response.streaming": False,
"gen_ai.usage.total_tokens": 10,
"process.runtime.name": mock.ANY,
"process.runtime.version": mock.ANY,
"sentry.environment": "production",
"sentry.op": "gen_ai.text_completion",
"sentry.origin": "auto.ai.huggingface_hub",
"sentry.release": mock.ANY,
"sentry.sdk.name": "sentry.python",
"sentry.sdk.version": mock.ANY,
"sentry.segment.id": mock.ANY,
"sentry.segment.name": "test",
"server.address": mock.ANY,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
Expand All @@ -547,7 +536,7 @@
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["attributes"] == expected_data
assert span["attributes"] == ApproxDict(expected_data)

# text generation does not set the response model
assert "gen_ai.response.model" not in span["attributes"]
Expand Down Expand Up @@ -585,8 +574,6 @@
"gen_ai.response.finish_reasons": "length",
"gen_ai.response.streaming": False,
"gen_ai.usage.total_tokens": 10,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
Expand All @@ -599,7 +586,7 @@
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["data"] == expected_data
assert span["data"] == ApproxDict(expected_data)

# text generation does not set the response model
assert "gen_ai.response.model" not in span["data"]
Expand Down Expand Up @@ -661,19 +648,9 @@
"gen_ai.response.finish_reasons": "length",
"gen_ai.response.streaming": True,
"gen_ai.usage.total_tokens": 10,
"process.runtime.name": mock.ANY,
"process.runtime.version": mock.ANY,
"sentry.environment": "production",
"sentry.op": "gen_ai.text_completion",
"sentry.origin": "auto.ai.huggingface_hub",
"sentry.release": mock.ANY,
"sentry.sdk.name": "sentry.python",
"sentry.sdk.version": mock.ANY,
"sentry.segment.id": mock.ANY,
"sentry.segment.name": "test",
"server.address": mock.ANY,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
Expand All @@ -684,7 +661,7 @@
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["attributes"] == expected_data
assert span["attributes"] == ApproxDict(expected_data)

# text generation does not set the response model
assert "gen_ai.response.model" not in span["attributes"]
Expand Down Expand Up @@ -723,8 +700,6 @@
"gen_ai.response.finish_reasons": "length",
"gen_ai.response.streaming": True,
"gen_ai.usage.total_tokens": 10,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
Expand All @@ -735,7 +710,7 @@
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["data"] == expected_data
assert span["data"] == ApproxDict(expected_data)

# text generation does not set the response model
assert "gen_ai.response.model" not in span["data"]
Expand Down Expand Up @@ -804,19 +779,9 @@
"gen_ai.usage.input_tokens": 10,
"gen_ai.usage.output_tokens": 8,
"gen_ai.usage.total_tokens": 18,
"process.runtime.name": mock.ANY,
"process.runtime.version": mock.ANY,
"sentry.environment": "production",
"sentry.op": "gen_ai.chat",
"sentry.origin": "auto.ai.huggingface_hub",
"sentry.release": mock.ANY,
"sentry.sdk.name": "sentry.python",
"sentry.sdk.version": mock.ANY,
"sentry.segment.id": mock.ANY,
"sentry.segment.name": "test",
"server.address": mock.ANY,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
Expand All @@ -833,64 +798,62 @@
"[mocked] Hello! How can I help you today?"
)

if not send_default_pii or not include_prompts:
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["attributes"] == expected_data
assert span["attributes"] == ApproxDict(expected_data)
else:
events = capture_events()

with sentry_sdk.start_transaction(name="test"):
client.chat_completion(
messages=[{"role": "user", "content": "Hello!"}],
stream=False,
)

(transaction,) = events

span = None
for sp in transaction["spans"]:
if sp["op"].startswith("gen_ai"):
assert span is None, "there is exactly one gen_ai span"
span = sp
else:
# there should be no other spans, just the gen_ai span
# and optionally some http.client spans from talking to the hf api
assert sp["op"] == "http.client"

assert span is not None

assert span["op"] == "gen_ai.chat"
assert span["description"] == "chat test-model"
assert span["origin"] == "auto.ai.huggingface_hub"

expected_data = {
"gen_ai.operation.name": "chat",
"gen_ai.request.model": "test-model",
"gen_ai.response.finish_reasons": "stop",
"gen_ai.response.model": "test-model-123",
"gen_ai.response.streaming": False,
"gen_ai.usage.input_tokens": 10,
"gen_ai.usage.output_tokens": 8,
"gen_ai.usage.total_tokens": 18,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
expected_data["gen_ai.request.messages"] = (
'[{"role": "user", "content": "Hello!"}]'
)
expected_data["gen_ai.response.text"] = (
"[mocked] Hello! How can I help you today?"
)

if not send_default_pii or not include_prompts:
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["data"] == expected_data
assert span["data"] == ApproxDict(expected_data)

Check warning on line 856 in tests/integrations/huggingface_hub/test_huggingface_hub.py

View check run for this annotation

@sentry/warden / warden: find-bugs

ApproxDict no longer fails when PII prompt fields leak

After switching to ApproxDict, assert that PII keys are absent from the actual span attributes/data when send_default_pii or include_prompts is false; the current checks only inspect expected_data and no longer catch leaks.


@pytest.mark.parametrize("stream_gen_ai_spans", [True, False])
Expand Down Expand Up @@ -955,19 +918,9 @@
"gen_ai.response.finish_reasons": "stop",
"gen_ai.response.model": "test-model-123",
"gen_ai.response.streaming": True,
"process.runtime.name": mock.ANY,
"process.runtime.version": mock.ANY,
"sentry.environment": "production",
"sentry.op": "gen_ai.chat",
"sentry.origin": "auto.ai.huggingface_hub",
"sentry.release": mock.ANY,
"sentry.sdk.name": "sentry.python",
"sentry.sdk.version": mock.ANY,
"sentry.segment.id": mock.ANY,
"sentry.segment.name": "test",
"server.address": mock.ANY,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}
# usage is not available in older versions of the library
if HF_VERSION and HF_VERSION >= (0, 26, 0):
Expand All @@ -991,7 +944,7 @@
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["attributes"] == expected_data
assert span["attributes"] == ApproxDict(expected_data)
else:
events = capture_events()

Expand Down Expand Up @@ -1027,8 +980,6 @@
"gen_ai.response.finish_reasons": "stop",
"gen_ai.response.model": "test-model-123",
"gen_ai.response.streaming": True,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}
# usage is not available in older versions of the library
if HF_VERSION and HF_VERSION >= (0, 26, 0):
Expand All @@ -1046,7 +997,7 @@
assert "gen_ai.request.messages" not in expected_data
assert "gen_ai.response.text" not in expected_data

assert span["data"] == expected_data
assert span["data"] == ApproxDict(expected_data)


@pytest.mark.parametrize("stream_gen_ai_spans", [True, False])
Expand Down Expand Up @@ -1104,21 +1055,11 @@
expected_data = {
"gen_ai.operation.name": "chat",
"gen_ai.request.model": "test-model",
"process.runtime.name": mock.ANY,
"process.runtime.version": mock.ANY,
"sentry.environment": "production",
"sentry.op": "gen_ai.chat",
"sentry.origin": "auto.ai.huggingface_hub",
"sentry.release": mock.ANY,
"sentry.sdk.name": "sentry.python",
"sentry.sdk.version": mock.ANY,
"sentry.segment.id": mock.ANY,
"sentry.segment.name": "test",
"server.address": mock.ANY,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}
assert span["attributes"] == expected_data
assert span["attributes"] == ApproxDict(expected_data)
else:
events = capture_events()

Expand Down Expand Up @@ -1160,10 +1101,8 @@
expected_data = {
"gen_ai.operation.name": "chat",
"gen_ai.request.model": "test-model",
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}
assert span["data"] == expected_data
assert span["data"] == ApproxDict(expected_data)


@pytest.mark.parametrize("stream_gen_ai_spans", [True, False])
Expand Down Expand Up @@ -1305,19 +1244,9 @@
"gen_ai.usage.input_tokens": 10,
"gen_ai.usage.output_tokens": 8,
"gen_ai.usage.total_tokens": 18,
"process.runtime.name": mock.ANY,
"process.runtime.version": mock.ANY,
"sentry.environment": "production",
"sentry.op": "gen_ai.chat",
"sentry.origin": "auto.ai.huggingface_hub",
"sentry.release": mock.ANY,
"sentry.sdk.name": "sentry.python",
"sentry.sdk.version": mock.ANY,
"sentry.segment.id": mock.ANY,
"sentry.segment.name": "test",
"server.address": mock.ANY,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
Expand All @@ -1333,7 +1262,7 @@
assert "gen_ai.response.text" not in expected_data
assert "gen_ai.response.tool_calls" not in expected_data

assert span["attributes"] == expected_data
assert span["attributes"] == ApproxDict(expected_data)
else:
events = capture_events()

Expand Down Expand Up @@ -1371,8 +1300,6 @@
"gen_ai.usage.input_tokens": 10,
"gen_ai.usage.output_tokens": 8,
"gen_ai.usage.total_tokens": 18,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if send_default_pii and include_prompts:
Expand All @@ -1388,7 +1315,7 @@
assert "gen_ai.response.text" not in expected_data
assert "gen_ai.response.tool_calls" not in expected_data

assert span["data"] == expected_data
assert span["data"] == ApproxDict(expected_data)


@pytest.mark.parametrize("stream_gen_ai_spans", [True, False])
Expand Down Expand Up @@ -1467,19 +1394,9 @@
"gen_ai.response.finish_reasons": "tool_calls",
"gen_ai.response.model": "test-model-123",
"gen_ai.response.streaming": True,
"process.runtime.name": mock.ANY,
"process.runtime.version": mock.ANY,
"sentry.environment": "production",
"sentry.op": "gen_ai.chat",
"sentry.origin": "auto.ai.huggingface_hub",
"sentry.release": mock.ANY,
"sentry.sdk.name": "sentry.python",
"sentry.sdk.version": mock.ANY,
"sentry.segment.id": mock.ANY,
"sentry.segment.name": "test",
"server.address": mock.ANY,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if HF_VERSION and HF_VERSION >= (0, 26, 0):
Expand All @@ -1501,7 +1418,7 @@
assert "gen_ai.response.text" not in expected_data
assert "gen_ai.response.tool_calls" not in expected_data

assert span["attributes"] == expected_data
assert span["attributes"] == ApproxDict(expected_data)
else:
events = capture_events()

Expand Down Expand Up @@ -1542,8 +1459,6 @@
"gen_ai.response.finish_reasons": "tool_calls",
"gen_ai.response.model": "test-model-123",
"gen_ai.response.streaming": True,
"thread.id": mock.ANY,
"thread.name": mock.ANY,
}

if HF_VERSION and HF_VERSION >= (0, 26, 0):
Expand All @@ -1565,7 +1480,7 @@
assert "gen_ai.response.text" not in expected_data
assert "gen_ai.response.tool_calls" not in expected_data

assert span["data"] == expected_data
assert span["data"] == ApproxDict(expected_data)


DATA_COLLECTION_TOOLS = [
Expand Down
Loading