diff --git a/CHANGELOG.md b/CHANGELOG.md index d9e48cd6df..53ccda28bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Enabled the flake8-type-checking plugin rules for ruff linter. These rules do not allow the import of python objects outside the type-checking block, if they are only used for type annotations and are not used at runtime. +([#4398](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4398)) - `opentelemetry-instrumentation-asgi`: Respect `suppress_http_instrumentation` context in ASGI middleware to skip server span creation when HTTP instrumentation is suppressed ([#4375](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4375)) - `opentelemetry-instrumentation-confluent-kafka`: Loosen confluent-kafka upper bound to <3.0.0 diff --git a/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/messages_extractors.py b/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/messages_extractors.py index 907aa08d39..23e7b11d77 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/messages_extractors.py +++ b/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/messages_extractors.py @@ -19,8 +19,6 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Sequence -from anthropic.types import MessageDeltaUsage - from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) @@ -32,7 +30,6 @@ MessagePart, OutputMessage, ) -from opentelemetry.util.types import AttributeValue from .utils import ( convert_content_to_parts, @@ -46,6 +43,7 @@ from anthropic.resources.messages import Messages from anthropic.types import ( Message, + MessageDeltaUsage, MessageParam, MetadataParam, TextBlockParam, @@ -55,6 +53,8 @@ Usage, ) + from opentelemetry.util.types import AttributeValue + @dataclass class MessageRequestParams: diff --git a/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/patch.py b/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/patch.py index 2392dfcd08..4b6e80150a 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/patch.py +++ b/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/patch.py @@ -18,7 +18,6 @@ from typing import TYPE_CHECKING, Any, Callable, Union, cast from anthropic._streaming import Stream as AnthropicStream -from anthropic.types import Message as AnthropicMessage from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, @@ -42,9 +41,8 @@ if TYPE_CHECKING: from anthropic.resources.messages import Messages + from anthropic.types import Message as AnthropicMessage from anthropic.types import RawMessageStreamEvent - - _logger = logging.getLogger(__name__) ANTHROPIC = "anthropic" @@ -121,13 +119,6 @@ def traced_method( raise return cast( - Callable[ - ..., - Union[ - "AnthropicMessage", - "AnthropicStream[RawMessageStreamEvent]", - MessagesStreamWrapper, - ], - ], + "Callable[..., Union[AnthropicMessage, AnthropicStream[RawMessageStreamEvent], MessagesStreamWrapper]]", traced_method, ) diff --git a/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/wrappers.py b/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/wrappers.py index 585d70a9f9..5b7531828e 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/wrappers.py +++ b/instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/wrappers.py @@ -15,10 +15,8 @@ from __future__ import annotations import logging -from types import TracebackType from typing import TYPE_CHECKING, Callable, Iterator, Optional -from opentelemetry.util.genai.handler import TelemetryHandler from opentelemetry.util.genai.types import ( Error, LLMInvocation, @@ -41,6 +39,8 @@ ) if TYPE_CHECKING: + from types import TracebackType + from anthropic._streaming import Stream from anthropic.types import ( Message, @@ -49,7 +49,7 @@ Usage, ) - + from opentelemetry.util.genai.handler import TelemetryHandler _logger = logging.getLogger(__name__) diff --git a/instrumentation-genai/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/otel_wrapper.py b/instrumentation-genai/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/otel_wrapper.py index b82288dec9..9c8d47d778 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/otel_wrapper.py +++ b/instrumentation-genai/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/otel_wrapper.py @@ -14,18 +14,20 @@ from __future__ import annotations import logging -from typing import Any +from typing import TYPE_CHECKING, Any import google.genai from opentelemetry._logs import Logger, LoggerProvider, LogRecord -from opentelemetry.metrics import Meter, MeterProvider from opentelemetry.semconv._incubating.metrics import gen_ai_metrics from opentelemetry.semconv.schemas import Schemas -from opentelemetry.trace import Tracer, TracerProvider from .version import __version__ as _LIBRARY_VERSION +if TYPE_CHECKING: + from opentelemetry.metrics import Meter, MeterProvider + from opentelemetry.trace import Tracer, TracerProvider + _logger = logging.getLogger(__name__) _SCOPE_NAME = "opentelemetry.instrumentation.google_genai" diff --git a/instrumentation-genai/opentelemetry-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/callback_handler.py b/instrumentation-genai/opentelemetry-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/callback_handler.py index d694857da4..4d57b79636 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/callback_handler.py +++ b/instrumentation-genai/opentelemetry-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/callback_handler.py @@ -14,17 +14,22 @@ from __future__ import annotations -from typing import Any, Optional, cast -from uuid import UUID +from typing import TYPE_CHECKING, Any, Optional, cast from langchain_core.callbacks import BaseCallbackHandler -from langchain_core.messages import BaseMessage -from langchain_core.outputs import LLMResult from opentelemetry.instrumentation.langchain.invocation_manager import ( _InvocationManager, ) -from opentelemetry.util.genai.handler import TelemetryHandler + +if TYPE_CHECKING: + from uuid import UUID + + from langchain_core.messages import BaseMessage + from langchain_core.outputs import LLMResult + + from opentelemetry.util.genai.handler import TelemetryHandler + from opentelemetry.util.genai.types import ( Error, InputMessage, @@ -136,7 +141,7 @@ def on_chat_model_start( input_messages.append( InputMessage( - parts=cast(list[MessagePart], parts), role=role + parts=cast("list[MessagePart]", parts), role=role ) ) @@ -211,7 +216,7 @@ def on_llm_end( role = chat_generation.message.type output_message = OutputMessage( role=role, - parts=cast(list[MessagePart], parts), + parts=cast("list[MessagePart]", parts), finish_reason=finish_reason, ) output_messages.append(output_message) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-agents-v2/src/opentelemetry/instrumentation/openai_agents/span_processor.py b/instrumentation-genai/opentelemetry-instrumentation-openai-agents-v2/src/opentelemetry/instrumentation/openai_agents/span_processor.py index 74be663701..99155672a3 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-agents-v2/src/opentelemetry/instrumentation/openai_agents/span_processor.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-agents-v2/src/opentelemetry/instrumentation/openai_agents/span_processor.py @@ -70,7 +70,6 @@ Tracer, set_span_in_context, ) -from opentelemetry.util.types import AttributeValue # Import all semantic convention constants # ---- GenAI semantic convention helpers (embedded from constants.py) ---- @@ -297,6 +296,7 @@ def normalize_output_type(output_type: Optional[str]) -> str: if TYPE_CHECKING: pass + from opentelemetry.util.types import AttributeValue # Legacy attributes removed logger = logging.getLogger(__name__) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/response_wrappers.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/response_wrappers.py index ce3375b8d5..64393ad4ba 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/response_wrappers.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/response_wrappers.py @@ -4,10 +4,8 @@ import logging from contextlib import AsyncExitStack, ExitStack, contextmanager -from types import TracebackType from typing import TYPE_CHECKING, Callable, Generator, Generic, TypeVar -from opentelemetry.util.genai.handler import TelemetryHandler from opentelemetry.util.genai.types import Error, LLMInvocation # OpenAI Responses internals are version-gated (added in openai>=1.66.0), so @@ -49,6 +47,8 @@ _set_invocation_response_attributes = None if TYPE_CHECKING: + from types import TracebackType + from openai.lib.streaming.responses._events import ( # pylint: disable=no-name-in-module ResponseStreamEvent, ) @@ -63,6 +63,7 @@ Response, ) + from opentelemetry.util.genai.handler import TelemetryHandler _logger = logging.getLogger(__name__) TextFormatT = TypeVar("TextFormatT") ResponseT = TypeVar("ResponseT") diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/events.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/events.py index 75969d1687..396987c7d9 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/events.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/events.py @@ -25,11 +25,13 @@ from __future__ import annotations from dataclasses import asdict, dataclass -from typing import Any, Iterable, Literal +from typing import TYPE_CHECKING, Any, Iterable, Literal from opentelemetry._logs import LogRecord from opentelemetry.semconv._incubating.attributes import gen_ai_attributes -from opentelemetry.util.types import AnyValue + +if TYPE_CHECKING: + from opentelemetry.util.types import AnyValue def user_event( diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/patch.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/patch.py index 481277d696..c5e1a9ea12 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/patch.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/patch.py @@ -47,7 +47,6 @@ gen_ai_attributes as GenAI, ) from opentelemetry.trace import SpanKind, Tracer -from opentelemetry.util.genai.completion_hook import CompletionHook from opentelemetry.util.genai.types import ( ContentCapturingMode, InputMessage, @@ -71,6 +70,8 @@ prediction_service as prediction_service_v1beta1, ) + from opentelemetry.util.genai.completion_hook import CompletionHook + # Use parameter signature from # https://github.com/googleapis/python-aiplatform/blob/v1.76.0/google/cloud/aiplatform_v1/services/prediction_service/client.py#L2088 @@ -314,7 +315,7 @@ def generate_content( | prediction_service_v1beta1.GenerateContentResponse ): if self.sem_conv_opt_in_mode == _StabilityMode.DEFAULT: - capture_content_bool = cast(bool, self.capture_content) + capture_content_bool = cast("bool", self.capture_content) with self._with_default_instrumentation( capture_content_bool, instance, args, kwargs ) as handle_response: @@ -322,7 +323,9 @@ def generate_content( handle_response(response) return response else: - capture_content = cast(ContentCapturingMode, self.capture_content) + capture_content = cast( + "ContentCapturingMode", self.capture_content + ) with self._with_new_instrumentation( capture_content, instance, args, kwargs ) as handle_response: @@ -351,7 +354,7 @@ async def agenerate_content( | prediction_service_v1beta1.GenerateContentResponse ): if self.sem_conv_opt_in_mode == _StabilityMode.DEFAULT: - capture_content_bool = cast(bool, self.capture_content) + capture_content_bool = cast("bool", self.capture_content) with self._with_default_instrumentation( capture_content_bool, instance, args, kwargs ) as handle_response: @@ -359,7 +362,9 @@ async def agenerate_content( handle_response(response) return response else: - capture_content = cast(ContentCapturingMode, self.capture_content) + capture_content = cast( + "ContentCapturingMode", self.capture_content + ) with self._with_new_instrumentation( capture_content, instance, args, kwargs ) as handle_response: diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/utils.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/utils.py index 9686d0dd7a..0628283def 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/utils.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/src/opentelemetry/instrumentation/vertexai/utils.py @@ -34,7 +34,6 @@ from google.protobuf import json_format -from opentelemetry._logs import LogRecord from opentelemetry.instrumentation._semconv import ( _StabilityMode, ) @@ -62,7 +61,6 @@ Uri, ) from opentelemetry.util.genai.utils import get_content_capturing_mode -from opentelemetry.util.types import AnyValue, AttributeValue if TYPE_CHECKING: from google.cloud.aiplatform_v1.types import ( @@ -80,7 +78,8 @@ tool as tool_v1beta1, ) - + from opentelemetry._logs import LogRecord + from opentelemetry.util.types import AnyValue, AttributeValue _MODEL = "model" diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions.py index 05e729e1f4..f65bd07d16 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING + import pytest from google.api_core.exceptions import BadRequest, NotFound from vertexai.generative_models import ( @@ -12,8 +14,6 @@ GenerativeModel as PreviewGenerativeModel, ) -from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor - # Backward compatibility for InMemoryLogExporter -> InMemoryLogRecordExporter rename try: from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import ( # pylint: disable=no-name-in-module @@ -21,15 +21,20 @@ ) except ImportError: # Fallback to old name for compatibility with older SDK versions - from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import ( - InMemoryLogExporter as InMemoryLogRecordExporter, - ) -from opentelemetry.sdk.trace import ReadableSpan -from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( - InMemorySpanExporter, -) + if TYPE_CHECKING: + from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import ( + InMemoryLogExporter as InMemoryLogRecordExporter, + ) + from opentelemetry.trace import StatusCode +if TYPE_CHECKING: + from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor + from opentelemetry.sdk.trace import ReadableSpan + from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( + InMemorySpanExporter, + ) + @pytest.mark.vcr() def test_generate_content( diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions_experimental.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions_experimental.py index 617d9a81c9..a69ae1e886 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions_experimental.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_chat_completions_experimental.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING + import pytest from google.api_core.exceptions import BadRequest, NotFound from vertexai.generative_models import ( @@ -13,8 +15,6 @@ GenerativeModel as PreviewGenerativeModel, ) -from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor - # Backward compatibility for InMemoryLogExporter -> InMemoryLogRecordExporter rename try: from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import ( # pylint: disable=no-name-in-module @@ -22,15 +22,19 @@ ) except ImportError: # Fallback to old name for compatibility with older SDK versions - from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import ( - InMemoryLogExporter as InMemoryLogRecordExporter, - ) -from opentelemetry.sdk.trace import ReadableSpan -from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( - InMemorySpanExporter, -) + if TYPE_CHECKING: + from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import ( + InMemoryLogExporter as InMemoryLogRecordExporter, + ) from opentelemetry.trace import StatusCode +if TYPE_CHECKING: + from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor + from opentelemetry.sdk.trace import ReadableSpan + from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( + InMemorySpanExporter, + ) + @pytest.mark.vcr() def test_generate_content_with_files( diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_instrumentor.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_instrumentor.py index e701426d2e..38851b0908 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_instrumentor.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/tests/test_instrumentor.py @@ -14,13 +14,16 @@ from __future__ import annotations +from typing import TYPE_CHECKING + import pytest from google.cloud.aiplatform_v1.services.prediction_service import client from google.cloud.aiplatform_v1beta1.services.prediction_service import ( client as client_v1beta1, ) -from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor +if TYPE_CHECKING: + from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor @pytest.fixture( diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py index 9e98c6e942..0b19db2134 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/src/opentelemetry/instrumentation/aiohttp_client/__init__.py @@ -268,36 +268,40 @@ def response_hook(span: Span, params: typing.Union[ if TYPE_CHECKING: from typing_extensions import Unpack - UrlFilterT = typing.Optional[typing.Callable[[yarl.URL], str]] - RequestHookT = typing.Optional[ - typing.Callable[[Span, aiohttp.TraceRequestStartParams], None] - ] - ResponseHookT = typing.Optional[ - typing.Callable[ - [ - Span, - typing.Union[ - aiohttp.TraceRequestEndParams, - aiohttp.TraceRequestExceptionParams, - ], + +UrlFilterT = typing.Optional[typing.Callable[[yarl.URL], str]] +RequestHookT = typing.Optional[ + typing.Callable[[Span, aiohttp.TraceRequestStartParams], None] +] +ResponseHookT = typing.Optional[ + typing.Callable[ + [ + Span, + typing.Union[ + aiohttp.TraceRequestEndParams, + aiohttp.TraceRequestExceptionParams, ], - None, - ] + ], + None, ] +] + + +class ClientSessionInitKwargs(TypedDict, total=False): + trace_configs: typing.Sequence[aiohttp.TraceConfig] + - class ClientSessionInitKwargs(TypedDict, total=False): - trace_configs: typing.Sequence[aiohttp.TraceConfig] +class InstrumentKwargs(TypedDict, total=False): + tracer_provider: trace.TracerProvider + meter_provider: MeterProvider + url_filter: UrlFilterT + request_hook: RequestHookT + response_hook: ResponseHookT + trace_configs: typing.Sequence[aiohttp.TraceConfig] - class InstrumentKwargs(TypedDict, total=False): - tracer_provider: trace.TracerProvider - meter_provider: MeterProvider - url_filter: UrlFilterT - request_hook: RequestHookT - response_hook: ResponseHookT - trace_configs: typing.Sequence[aiohttp.TraceConfig] - class UninstrumentKwargs(TypedDict, total=False): - pass +class UninstrumentKwargs(TypedDict, total=False): + pass def _get_span_name(method: str) -> str: @@ -435,7 +439,7 @@ def _end_trace(trace_config_ctx: types.SimpleNamespace): if trace_config_ctx.duration_histogram_old is not None: duration_attrs_old = cast( - dict[str, Any], + "dict[str, Any]", _filter_semconv_duration_attrs( trace_config_ctx.metric_attributes, _client_duration_attrs_old, @@ -449,7 +453,7 @@ def _end_trace(trace_config_ctx: types.SimpleNamespace): ) if trace_config_ctx.duration_histogram_new is not None: duration_attrs_new = cast( - dict[str, Any], + "dict[str, Any]", _filter_semconv_duration_attrs( trace_config_ctx.metric_attributes, _client_duration_attrs_old, @@ -477,7 +481,7 @@ async def on_request_start( request_span_name = _get_span_name(method) request_url = ( redact_url( - cast(Callable[[yarl.URL], str], trace_config_ctx.url_filter)( + cast("Callable[[yarl.URL], str]", trace_config_ctx.url_filter)( params.url ) ) @@ -629,7 +633,7 @@ def _trace_config_ctx_factory(**kwargs: Any) -> types.SimpleNamespace: trace_config = aiohttp.TraceConfig( trace_config_ctx_factory=cast( - type[types.SimpleNamespace], _trace_config_ctx_factory + "type[types.SimpleNamespace]", _trace_config_ctx_factory ) ) diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py index f008a9e3be..e677de6119 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/src/opentelemetry/instrumentation/aiohttp_server/__init__.py @@ -157,9 +157,9 @@ async def hello(request): from __future__ import annotations from timeit import default_timer +from typing import TYPE_CHECKING from aiohttp import web -from multidict import CIMultiDictProxy from opentelemetry import metrics, trace from opentelemetry.instrumentation._semconv import ( @@ -218,6 +218,9 @@ async def hello(request): sanitize_method, ) +if TYPE_CHECKING: + from multidict import CIMultiDictProxy + tracer = None meter_old = None meter_new = None diff --git a/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/utils.py b/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/utils.py index 8533a98858..2518e08207 100644 --- a/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/utils.py +++ b/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/utils.py @@ -1,6 +1,5 @@ from __future__ import annotations -import asyncio import contextlib import json from logging import getLogger @@ -21,58 +20,66 @@ import aiokafka from opentelemetry import context, propagate, trace -from opentelemetry.context import Context from opentelemetry.propagators import textmap from opentelemetry.semconv._incubating.attributes import messaging_attributes from opentelemetry.semconv.attributes import server_attributes -from opentelemetry.trace import Tracer from opentelemetry.trace.span import Span if TYPE_CHECKING: + import asyncio + from aiokafka.structs import RecordMetadata - class AIOKafkaGetOneProto(Protocol): - async def __call__( - self, *partitions: aiokafka.TopicPartition - ) -> aiokafka.ConsumerRecord[object, object]: ... - - class AIOKafkaGetManyProto(Protocol): - async def __call__( - self, - *partitions: aiokafka.TopicPartition, - timeout_ms: int = 0, - max_records: int | None = None, - ) -> dict[ - aiokafka.TopicPartition, - list[aiokafka.ConsumerRecord[object, object]], - ]: ... - - class AIOKafkaSendProto(Protocol): - async def __call__( - self, - topic: str, - value: object | None = None, - key: object | None = None, - partition: int | None = None, - timestamp_ms: int | None = None, - headers: HeadersT | None = None, - ) -> asyncio.Future[RecordMetadata]: ... - - ProduceHookT = Callable[ - [Span, Tuple[Any, ...], Dict[str, Any]], Awaitable[None] - ] - - ConsumeHookT = Callable[ - [ - Span, - aiokafka.ConsumerRecord[object, object], - Tuple[aiokafka.TopicPartition, ...], - Dict[str, Any], - ], - Awaitable[None], - ] - - HeadersT = Sequence[Tuple[str, Optional[bytes]]] + from opentelemetry.context import Context + from opentelemetry.trace import Tracer + + +class AIOKafkaGetOneProto(Protocol): + async def __call__( + self, *partitions: aiokafka.TopicPartition + ) -> aiokafka.ConsumerRecord[object, object]: ... + + +class AIOKafkaGetManyProto(Protocol): + async def __call__( + self, + *partitions: aiokafka.TopicPartition, + timeout_ms: int = 0, + max_records: int | None = None, + ) -> dict[ + aiokafka.TopicPartition, + list[aiokafka.ConsumerRecord[object, object]], + ]: ... + + +class AIOKafkaSendProto(Protocol): + async def __call__( + self, + topic: str, + value: object | None = None, + key: object | None = None, + partition: int | None = None, + timestamp_ms: int | None = None, + headers: HeadersT | None = None, + ) -> asyncio.Future[RecordMetadata]: ... + + +ProduceHookT = Callable[ + [Span, Tuple[Any, ...], Dict[str, Any]], Awaitable[None] +] + +ConsumeHookT = Callable[ + [ + Span, + aiokafka.ConsumerRecord[object, object], + Tuple[aiokafka.TopicPartition, ...], + Dict[str, Any], + ], + Awaitable[None], +] + +HeadersT = Sequence[Tuple[str, Optional[bytes]]] + _LOG = getLogger(__name__) diff --git a/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py b/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py index 646232da35..117273d4de 100644 --- a/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py @@ -11,12 +11,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - from __future__ import annotations import sys import uuid -from typing import Any, Sequence, cast +from typing import TYPE_CHECKING, Any, Sequence, cast from unittest import IsolatedAsyncioTestCase, TestCase, mock, skipIf import aiokafka @@ -26,11 +25,14 @@ ConsumerRecord, TopicPartition, ) + +if TYPE_CHECKING: + from opentelemetry.sdk.trace import ReadableSpan + from wrapt import BoundFunctionWrapper from opentelemetry import baggage, context from opentelemetry.instrumentation.aiokafka import AIOKafkaInstrumentor -from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.semconv._incubating.attributes import messaging_attributes from opentelemetry.semconv.attributes import server_attributes from opentelemetry.test.test_base import TestBase @@ -158,7 +160,9 @@ async def test_getone(self) -> None: client_id=client_id, group_id=group_id ) self.addAsyncCleanup(consumer.stop) - next_record_mock = cast(mock.AsyncMock, consumer._fetcher.next_record) + next_record_mock = cast( + "mock.AsyncMock", consumer._fetcher.next_record + ) expected_spans = [ { @@ -241,7 +245,9 @@ async def async_consume_hook(span, *_) -> None: consumer = await self.consumer_factory() self.addAsyncCleanup(consumer.stop) - next_record_mock = cast(mock.AsyncMock, consumer._fetcher.next_record) + next_record_mock = cast( + "mock.AsyncMock", consumer._fetcher.next_record + ) self.memory_exporter.clear() @@ -284,7 +290,9 @@ def is_async_consume_hook_mock(obj: Any) -> bool: consumer = await self.consumer_factory() self.addAsyncCleanup(consumer.stop) - next_record_mock = cast(mock.AsyncMock, consumer._fetcher.next_record) + next_record_mock = cast( + "mock.AsyncMock", consumer._fetcher.next_record + ) next_record_mock.side_effect = [ self.consumer_record_factory(1, headers=()) @@ -302,7 +310,7 @@ async def test_getmany(self) -> None: ) self.addAsyncCleanup(consumer.stop) fetched_records_mock = cast( - mock.AsyncMock, consumer._fetcher.fetched_records + "mock.AsyncMock", consumer._fetcher.fetched_records ) expected_spans = [ @@ -408,7 +416,7 @@ async def test_send(self) -> None: producer = await self.producer_factory() self.addAsyncCleanup(producer.stop) add_message_mock = cast( - mock.AsyncMock, producer._message_accumulator.add_message + "mock.AsyncMock", producer._message_accumulator.add_message ) tracer = self.tracer_provider.get_tracer(__name__) @@ -441,7 +449,7 @@ async def test_send_baggage(self) -> None: producer = await self.producer_factory() self.addAsyncCleanup(producer.stop) add_message_mock = cast( - mock.AsyncMock, producer._message_accumulator.add_message + "mock.AsyncMock", producer._message_accumulator.add_message ) tracer = self.tracer_provider.get_tracer(__name__) diff --git a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py index e28315f502..21b99c04e8 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -215,7 +215,7 @@ def client_response_hook(span: Span, scope: Scope, message: dict[str, Any]): from collections import defaultdict from functools import wraps from timeit import default_timer -from typing import Any, Awaitable, Callable, DefaultDict, Tuple +from typing import TYPE_CHECKING, Any, Awaitable, Callable, DefaultDict, Tuple from asgiref.compatibility import guarantee_single_callable @@ -246,11 +246,6 @@ def client_response_hook(span: Span, scope: Scope, message: dict[str, Any]): _set_status, _StabilityMode, ) -from opentelemetry.instrumentation.asgi.types import ( - ClientRequestHook, - ClientResponseHook, - ServerRequestHook, -) from opentelemetry.instrumentation.asgi.version import __version__ # noqa from opentelemetry.instrumentation.propagators import ( get_global_response_propagator, @@ -295,6 +290,13 @@ def client_response_hook(span: Span, scope: Scope, message: dict[str, Any]): sanitize_method, ) +if TYPE_CHECKING: + from opentelemetry.instrumentation.asgi.types import ( + ClientRequestHook, + ClientResponseHook, + ServerRequestHook, + ) + class ASGIGetter(Getter[dict]): def get( diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py index e666250c63..87ff51f70a 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -81,7 +81,6 @@ def custom_event_context_extractor(lambda_event): from wrapt import wrap_function_wrapper from opentelemetry import context as context_api -from opentelemetry.context.context import Context from opentelemetry.instrumentation.aws_lambda.package import _instruments from opentelemetry.instrumentation.aws_lambda.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -148,6 +147,8 @@ class LambdaContext(typing.Protocol): log_group_name: str log_stream_name: str + from opentelemetry.context.context import Context + def _default_event_context_extractor(lambda_event: Any) -> Context: """Default way of extracting the context from the Lambda Event. diff --git a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py index 028009afd6..7b5541d429 100644 --- a/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-boto3sqs/src/opentelemetry/instrumentation/boto3sqs/__init__.py @@ -188,7 +188,7 @@ def _safe_end_processing_span(receipt_handle: str) -> None: @staticmethod def _extract_queue_name_from_url(queue_url: str) -> str: # A Queue name cannot have the `/` char, therefore we can return the part after the last / - return queue_url.split("/")[-1] + return queue_url.rsplit("/", maxsplit=1)[-1] def _create_processing_span( self, diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/bedrock.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/bedrock.py index 063fe2ab78..ea5c9109d8 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/bedrock.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/bedrock.py @@ -23,7 +23,7 @@ import json import logging from timeit import default_timer -from typing import Any +from typing import TYPE_CHECKING, Any from botocore.eventstream import EventStream from botocore.response import StreamingBody @@ -37,6 +37,11 @@ genai_capture_message_content, message_to_event, ) + +if TYPE_CHECKING: + from opentelemetry.metrics import Instrument, Meter + from opentelemetry.trace.span import Span + from opentelemetry.instrumentation.botocore.extensions.types import ( _AttributeMapT, _AwsSdkExtension, @@ -44,7 +49,6 @@ _BotocoreInstrumentorContext, ) from opentelemetry.instrumentation.botocore.utils import get_server_attributes -from opentelemetry.metrics import Instrument, Meter from opentelemetry.semconv._incubating.attributes.error_attributes import ( ERROR_TYPE, ) @@ -69,7 +73,6 @@ GEN_AI_CLIENT_TOKEN_USAGE, ) from opentelemetry.trace.propagation import set_span_in_context -from opentelemetry.trace.span import Span from opentelemetry.trace.status import Status, StatusCode _logger = logging.getLogger(__name__) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py index acc33bcf0a..fc0a80ff61 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py @@ -15,14 +15,16 @@ from __future__ import annotations import logging -from typing import Any, Dict, Optional, Tuple +from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple -from opentelemetry._logs import Logger -from opentelemetry.metrics import Instrument, Meter from opentelemetry.trace import SpanKind -from opentelemetry.trace.span import Span from opentelemetry.util.types import AttributeValue +if TYPE_CHECKING: + from opentelemetry._logs import Logger + from opentelemetry.metrics import Instrument, Meter + from opentelemetry.trace.span import Span + _logger = logging.getLogger(__name__) _BotoClientT = "botocore.client.BaseClient" diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/utils.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/utils.py index 29e8d12b88..dd9776a4aa 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/utils.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/utils.py @@ -14,13 +14,16 @@ from __future__ import annotations import logging -from typing import Callable +from typing import TYPE_CHECKING, Callable from urllib.parse import urlparse from opentelemetry.semconv._incubating.attributes import ( server_attributes as ServerAttributes, ) -from opentelemetry.util.types import AttributeValue + +if TYPE_CHECKING: + from opentelemetry.util.types import AttributeValue + _logger = logging.getLogger(__name__) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/tests/bedrock_utils.py b/instrumentation/opentelemetry-instrumentation-botocore/tests/bedrock_utils.py index cd357f9597..da04500a72 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/tests/bedrock_utils.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/tests/bedrock_utils.py @@ -16,16 +16,19 @@ import json import math -from typing import Any - -from botocore.response import StreamingBody +from typing import TYPE_CHECKING, Any from opentelemetry.instrumentation.botocore.extensions.bedrock import ( _GEN_AI_CLIENT_OPERATION_DURATION_BUCKETS, _GEN_AI_CLIENT_TOKEN_USAGE_BUCKETS, ) -from opentelemetry.sdk.metrics._internal.point import ResourceMetrics -from opentelemetry.sdk.trace import ReadableSpan + +if TYPE_CHECKING: + from botocore.response import StreamingBody + + from opentelemetry.sdk.metrics._internal.point import ResourceMetrics + from opentelemetry.sdk.trace import ReadableSpan + from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) diff --git a/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/utils.py b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/utils.py index c6bd7b9d86..8c9d4b8e8f 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/utils.py +++ b/instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/utils.py @@ -18,17 +18,19 @@ from typing import TYPE_CHECKING, Optional, Tuple from celery import registry # pylint: disable=no-name-in-module -from celery.app.task import Task from opentelemetry.semconv._incubating.attributes.messaging_attributes import ( MESSAGING_MESSAGE_ID, ) from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace import Span if TYPE_CHECKING: from contextlib import AbstractContextManager + from celery.app.task import Task + + from opentelemetry.trace import Span + logger = logging.getLogger(__name__) # Celery Context key diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py index 9eb386b0ea..bd161e98a1 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py @@ -181,7 +181,8 @@ except ImportError: from wrapt import ObjectProxy as BaseObjectProxy -from opentelemetry import trace as trace_api +from typing import TYPE_CHECKING + from opentelemetry.instrumentation.dbapi.version import __version__ from opentelemetry.instrumentation.sqlcommenter_utils import _add_sql_comment from opentelemetry.instrumentation.utils import ( @@ -202,6 +203,9 @@ from opentelemetry.trace import SpanKind, TracerProvider, get_tracer from opentelemetry.util._importlib_metadata import version as util_version +if TYPE_CHECKING: + from opentelemetry import trace as trace_api + _DB_DRIVER_ALIASES = { "MySQLdb": "mysqlclient", } diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py index 7de11cab8d..9e28483e95 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py @@ -185,14 +185,12 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A import functools import logging import types -from typing import Any, Collection, Literal +from typing import TYPE_CHECKING, Any, Collection, Literal from weakref import WeakSet as _WeakSet import fastapi -from starlette.applications import Starlette from starlette.middleware.errors import ServerErrorMiddleware from starlette.routing import Match, Route -from starlette.types import ASGIApp, Receive, Scope, Send from opentelemetry.instrumentation._semconv import ( _get_schema_url, @@ -201,11 +199,6 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A _StabilityMode, ) from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware -from opentelemetry.instrumentation.asgi.types import ( - ClientRequestHook, - ClientResponseHook, - ServerRequestHook, -) from opentelemetry.instrumentation.fastapi.package import _instruments from opentelemetry.instrumentation.fastapi.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -219,6 +212,16 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A sanitize_method, ) +if TYPE_CHECKING: + from starlette.applications import Starlette + from starlette.types import ASGIApp, Receive, Scope, Send + + from opentelemetry.instrumentation.asgi.types import ( + ClientRequestHook, + ClientResponseHook, + ServerRequestHook, + ) + _excluded_urls_from_env = get_excluded_urls("FASTAPI") _logger = logging.getLogger(__name__) diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py index aa6189a60e..bd33253f84 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py @@ -20,7 +20,7 @@ import weakref as _weakref from contextlib import ExitStack from timeit import default_timer -from typing import Any, Final, cast +from typing import TYPE_CHECKING, Any, Final, cast from unittest.mock import Mock, call, patch import fastapi @@ -53,7 +53,6 @@ NumberDataPoint, ) from opentelemetry.sdk.resources import Resource -from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.semconv._incubating.attributes.http_attributes import ( HTTP_FLAVOR, HTTP_HOST, @@ -90,6 +89,10 @@ get_excluded_urls, ) +if TYPE_CHECKING: + from opentelemetry.sdk.trace import ReadableSpan + + _expected_metric_names_old = [ "http.server.active_requests", "http.server.duration", @@ -1091,7 +1094,7 @@ def test_hooks(self): self._client.get("/foobar") spans = cast( - list[ReadableSpan], + "list[ReadableSpan]", self.sorted_spans(self.memory_exporter.get_finished_spans()), ) self.assertEqual(len(spans), 3) diff --git a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py index 882552d09b..16c24c05a5 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py @@ -320,7 +320,7 @@ async def async_response_hook(span, request, response): from functools import partial from inspect import iscoroutinefunction from timeit import default_timer -from types import TracebackType +from typing import TYPE_CHECKING import httpx from wrapt import wrap_function_wrapper @@ -383,6 +383,10 @@ async def async_response_hook(span, request, response): sanitize_method, ) +if TYPE_CHECKING: + from types import TracebackType + + _logger = logging.getLogger(__name__) RequestHook = typing.Callable[[Span, "RequestInfo"], None] diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/__init__.py b/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/__init__.py index 9867992d49..e66cee10aa 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-jinja2/src/opentelemetry/instrumentation/jinja2/__init__.py @@ -42,11 +42,9 @@ from __future__ import annotations import logging -from types import CodeType -from typing import Any, Callable, Collection, TypeVar +from typing import TYPE_CHECKING, Any, Callable, Collection, TypeVar import jinja2 -from jinja2.environment import Template from wrapt import wrap_function_wrapper as _wrap from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -55,6 +53,11 @@ from opentelemetry.instrumentation.utils import unwrap from opentelemetry.trace import SpanKind, Tracer, get_tracer +if TYPE_CHECKING: + from types import CodeType + + from jinja2.environment import Template + logger = logging.getLogger(__name__) ATTRIBUTE_JINJA2_TEMPLATE_NAME = "jinja2.template_name" diff --git a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/handler.py b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/handler.py index 44ba3164ad..d69baaea91 100644 --- a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/handler.py +++ b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/handler.py @@ -20,7 +20,7 @@ import traceback from contextvars import ContextVar from time import time_ns -from typing import Callable +from typing import TYPE_CHECKING, Callable from opentelemetry._logs import ( LoggerProvider, @@ -30,11 +30,14 @@ get_logger, get_logger_provider, ) + +if TYPE_CHECKING: + from opentelemetry.util.types import _ExtendedAttributes + from opentelemetry.attributes import _VALID_ANY_VALUE_TYPES from opentelemetry.context import get_current from opentelemetry.semconv._incubating.attributes import code_attributes from opentelemetry.semconv.attributes import exception_attributes -from opentelemetry.util.types import _ExtendedAttributes _internal_logger = logging.getLogger(__name__ + ".internal") _internal_logger.propagate = False diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py index 28896be138..0869679623 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py @@ -144,7 +144,7 @@ from __future__ import annotations import logging -from typing import Any, Callable, Collection, TypeVar +from typing import TYPE_CHECKING, Any, Callable, Collection, TypeVar import psycopg # pylint: disable=import-self from psycopg.sql import Composable # pylint: disable=no-name-in-module @@ -153,7 +153,9 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.psycopg.package import _instruments from opentelemetry.instrumentation.psycopg.version import __version__ -from opentelemetry.trace import TracerProvider + +if TYPE_CHECKING: + from opentelemetry.trace import TracerProvider _logger = logging.getLogger(__name__) _OTEL_CURSOR_FACTORY_KEY = "_otel_orig_cursor_factory" diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py index 4c8b1b6e02..f08ad84181 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py @@ -168,7 +168,6 @@ ) from psycopg2.sql import Composed # pylint: disable=no-name-in-module -from opentelemetry import trace as trace_api from opentelemetry.instrumentation import dbapi from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.psycopg2.package import ( @@ -185,6 +184,8 @@ connection as PgConnection, ) + from opentelemetry import trace as trace_api + class Psycopg2Instrumentor(BaseInstrumentor): _CONNECTION_ATTRIBUTES = { diff --git a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py index 320758f842..838bf9bffd 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py +++ b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py @@ -33,7 +33,6 @@ DbSystemValues, NetTransportValues, ) -from opentelemetry.trace import Span if TYPE_CHECKING: from opentelemetry.instrumentation.redis.custom_types import ( @@ -42,7 +41,7 @@ PipelineInstance, RedisInstance, ) - + from opentelemetry.trace import Span _FIELD_TYPES = ["NUMERIC", "TEXT", "GEO", "TAG", "VECTOR"] diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py b/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py index 086d47f3f5..7f9ad9a74d 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py @@ -60,13 +60,15 @@ import sqlite3 from sqlite3 import dbapi2 -from typing import Any, Collection, TypeVar, Union +from typing import TYPE_CHECKING, Any, Collection, TypeVar, Union from opentelemetry.instrumentation import dbapi from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.sqlite3.package import _instruments from opentelemetry.instrumentation.sqlite3.version import __version__ -from opentelemetry.trace import TracerProvider + +if TYPE_CHECKING: + from opentelemetry.trace import TracerProvider # No useful attributes of sqlite3 connection object _CONNECTION_ATTRIBUTES = {} diff --git a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py index 227c4dcf31..882bbda4e1 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py @@ -176,18 +176,13 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A from __future__ import annotations -from typing import TYPE_CHECKING, Any, Collection, cast +from typing import TYPE_CHECKING, Any, Collection, TypedDict, Unpack, cast from weakref import WeakSet from starlette import applications from starlette.routing import Match from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware -from opentelemetry.instrumentation.asgi.types import ( - ClientRequestHook, - ClientResponseHook, - ServerRequestHook, -) from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.starlette.package import _instruments from opentelemetry.instrumentation.starlette.version import __version__ @@ -199,14 +194,19 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A from opentelemetry.util.http import get_excluded_urls if TYPE_CHECKING: - from typing import TypedDict, Unpack + from opentelemetry.instrumentation.asgi.types import ( + ClientRequestHook, + ClientResponseHook, + ServerRequestHook, + ) + - class InstrumentKwargs(TypedDict, total=False): - tracer_provider: TracerProvider - meter_provider: MeterProvider - server_request_hook: ServerRequestHook - client_request_hook: ClientRequestHook - client_response_hook: ClientResponseHook +class InstrumentKwargs(TypedDict, total=False): + tracer_provider: TracerProvider + meter_provider: MeterProvider + server_request_hook: ServerRequestHook + client_request_hook: ClientRequestHook + client_response_hook: ClientResponseHook _excluded_urls = get_excluded_urls("STARLETTE") @@ -362,7 +362,7 @@ def _get_route_details(scope: dict[str, Any]) -> str | None: Returns: The path to the route if found, otherwise None. """ - app = cast(applications.Starlette, scope["app"]) + app = cast("applications.Starlette", scope["app"]) route: str | None = None for starlette_route in app.routes: diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py index 7c10932c0d..775a67abe1 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py @@ -182,7 +182,7 @@ def response_hook(span: Span, request: Request, response: HTTPResponse): import typing from http import client from timeit import default_timer -from typing import Any, Collection +from typing import TYPE_CHECKING, Any, Collection from urllib.request import ( # pylint: disable=no-name-in-module,import-error OpenerDirector, Request, @@ -242,7 +242,9 @@ def response_hook(span: Span, request: Request, response: HTTPResponse): redact_url, sanitize_method, ) -from opentelemetry.util.types import Attributes + +if TYPE_CHECKING: + from opentelemetry.util.types import Attributes _excluded_urls_from_env = get_excluded_urls("URLLIB") diff --git a/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py b/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py index 6c723b8cb0..699b1a31fc 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py @@ -17,11 +17,11 @@ import abc import socket import urllib +from typing import TYPE_CHECKING from unittest import mock from unittest.mock import patch from urllib import request from urllib.error import HTTPError -from urllib.request import OpenerDirector import httpretty @@ -31,6 +31,10 @@ OTEL_SEMCONV_STABILITY_OPT_IN, _OpenTelemetrySemanticConventionStability, ) + +if TYPE_CHECKING: + from urllib.request import OpenerDirector + from opentelemetry.instrumentation.urllib import ( # pylint: disable=no-name-in-module,import-error URLLibInstrumentor, ) diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py index b30423d3bf..b55ed12658 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -266,7 +266,6 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he from opentelemetry.semconv.metrics.http_metrics import ( HTTP_SERVER_REQUEST_DURATION, ) -from opentelemetry.trace import TracerProvider from opentelemetry.trace.status import Status, StatusCode from opentelemetry.util.http import ( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS, @@ -286,7 +285,7 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he if TYPE_CHECKING: from wsgiref.types import StartResponse, WSGIApplication, WSGIEnvironment - + from opentelemetry.trace import TracerProvider T = TypeVar("T") RequestHook = Callable[[trace.Span, "WSGIEnvironment"], None] ResponseHook = Callable[ @@ -339,7 +338,7 @@ def collect_request_attributes( _set_http_method( result, environ.get("REQUEST_METHOD", ""), - sanitize_method(cast(str, environ.get("REQUEST_METHOD", ""))), + sanitize_method(cast("str", environ.get("REQUEST_METHOD", ""))), sem_conv_opt_in_mode, ) # old semconv v1.12.0 @@ -551,11 +550,11 @@ def get_default_span_name(environ: WSGIEnvironment) -> str: The span name. """ method = sanitize_method( - cast(str, environ.get("REQUEST_METHOD", "")).strip() + cast("str", environ.get("REQUEST_METHOD", "")).strip() ) if method == "_OTHER": return "HTTP" - path = cast(str, environ.get("PATH_INFO", "")).strip() + path = cast("str", environ.get("PATH_INFO", "")).strip() if method and path: return f"{method} {path}" return method diff --git a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/agent.py b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/agent.py index 917f753a4f..caf6078425 100644 --- a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/agent.py +++ b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/agent.py @@ -19,12 +19,14 @@ import queue import random import threading -from typing import Any, Callable +from typing import TYPE_CHECKING, Any, Callable from opentelemetry._opamp.callbacks import MessageData, OpAMPCallbacks -from opentelemetry._opamp.client import OpAMPClient from opentelemetry._opamp.proto import opamp_pb2 +if TYPE_CHECKING: + from opentelemetry._opamp.client import OpAMPClient + logger = logging.getLogger(__name__) diff --git a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/callbacks.py b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/callbacks.py index c543793ded..43f1a36265 100644 --- a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/callbacks.py +++ b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/callbacks.py @@ -18,11 +18,10 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -from opentelemetry._opamp.proto import opamp_pb2 - if TYPE_CHECKING: from opentelemetry._opamp.agent import OpAMPAgent from opentelemetry._opamp.client import OpAMPClient + from opentelemetry._opamp.proto import opamp_pb2 @dataclass diff --git a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/client.py b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/client.py index 234e15451e..30f68ff791 100644 --- a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/client.py +++ b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/client.py @@ -15,13 +15,12 @@ from __future__ import annotations from logging import getLogger -from typing import Generator, Mapping +from typing import TYPE_CHECKING, Generator, Mapping from uuid_utils import uuid7 from opentelemetry._opamp import messages from opentelemetry._opamp.proto import opamp_pb2 -from opentelemetry._opamp.transport.base import HttpTransport from opentelemetry._opamp.transport.requests import RequestsTransport from opentelemetry._opamp.version import __version__ from opentelemetry.context import ( @@ -30,7 +29,11 @@ detach, set_value, ) -from opentelemetry.util.types import AnyValue + +if TYPE_CHECKING: + from opentelemetry._opamp.transport.base import HttpTransport + from opentelemetry.util.types import AnyValue + _logger = getLogger(__name__) diff --git a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/messages.py b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/messages.py index 04d4da0322..64e2e2a49f 100644 --- a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/messages.py +++ b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/messages.py @@ -17,12 +17,16 @@ from __future__ import annotations import json -from typing import Generator, Mapping +from typing import TYPE_CHECKING, Generator, Mapping from opentelemetry._opamp.exceptions import ( OpAMPRemoteConfigDecodeException, OpAMPRemoteConfigParseException, ) + +if TYPE_CHECKING: + from opentelemetry.util.types import AnyValue + from opentelemetry._opamp.proto import opamp_pb2 from opentelemetry._opamp.proto.anyvalue_pb2 import ( AnyValue as PB2AnyValue, @@ -30,7 +34,6 @@ from opentelemetry._opamp.proto.anyvalue_pb2 import ( KeyValue as PB2KeyValue, ) -from opentelemetry.util.types import AnyValue def decode_message(data: bytes) -> opamp_pb2.ServerToAgent: diff --git a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/transport/base.py b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/transport/base.py index ac4e6866bc..4c96db76b7 100644 --- a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/transport/base.py +++ b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/transport/base.py @@ -15,9 +15,11 @@ from __future__ import annotations import abc -from typing import Mapping +from typing import TYPE_CHECKING, Mapping + +if TYPE_CHECKING: + from opentelemetry._opamp.proto import opamp_pb2 -from opentelemetry._opamp.proto import opamp_pb2 base_headers = { "Content-Type": "application/x-protobuf", diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py index 1edd18d038..bf94d6837b 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_semconv.py @@ -17,7 +17,7 @@ import os import threading from enum import Enum -from typing import Container, Mapping, MutableMapping +from typing import TYPE_CHECKING, Container, Mapping, MutableMapping from urllib.parse import urlparse from packaging import version as package_version @@ -30,6 +30,11 @@ DB_SYSTEM, DB_USER, ) + +if TYPE_CHECKING: + from opentelemetry.trace import Span + from opentelemetry.util.types import AttributeValue + from opentelemetry.semconv._incubating.attributes.http_attributes import ( HTTP_FLAVOR, HTTP_HOST, @@ -82,9 +87,7 @@ USER_AGENT_ORIGINAL, ) from opentelemetry.semconv.schemas import Schemas -from opentelemetry.trace import Span from opentelemetry.trace.status import Status, StatusCode -from opentelemetry.util.types import AttributeValue # Values defined in milliseconds HTTP_DURATION_HISTOGRAM_BUCKETS_OLD = ( diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py index 1b450f2549..d853ee9a43 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py @@ -19,10 +19,13 @@ from abc import ABC, abstractmethod from logging import getLogger +from typing import TYPE_CHECKING -from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.util._importlib_metadata import EntryPoint +if TYPE_CHECKING: + from opentelemetry.instrumentation.instrumentor import BaseInstrumentor + _LOG = getLogger(__name__) diff --git a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py index 7e09e591e0..346b09a904 100644 --- a/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py +++ b/processor/opentelemetry-processor-baggage/src/opentelemetry/processor/baggage/processor.py @@ -12,12 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Callable, Optional +from typing import TYPE_CHECKING, Callable, Optional from opentelemetry.baggage import get_all as get_all_baggage from opentelemetry.context import Context from opentelemetry.sdk.trace.export import SpanProcessor -from opentelemetry.trace import Span + +if TYPE_CHECKING: + from opentelemetry.trace import Span # A BaggageKeyPredicate is a function that takes a baggage key and returns a boolean BaggageKeyPredicateT = Callable[[str], bool] diff --git a/pyproject.toml b/pyproject.toml index c877d5f038..e3f08f6940 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,9 +171,18 @@ select = [ "PLE", # pylint error "Q", # flake8-quotes "A", # flake8-builtins + "TCH", # flake8-type-checking ] ignore = [ "E501", # line-too-long + + # flake8-type-checking rules: + # This rule enforces to add quotes for type aliases. + # This rule is unsafe as no static type checker can determine + # the exact behavior of runtime typing libraries. + "TC007", + # This rule is unstable and in preview + "TC008", ] [tool.ruff.lint.per-file-ignores] diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/_sampling_rule_applier.py b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/_sampling_rule_applier.py index 332b274de2..0d79749e77 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/_sampling_rule_applier.py +++ b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/_sampling_rule_applier.py @@ -18,17 +18,21 @@ from __future__ import annotations -# pylint: disable=no-name-in-module -from opentelemetry.sdk.extension.aws.trace.sampler._clock import _Clock -from opentelemetry.sdk.extension.aws.trace.sampler._sampling_rule import ( - _SamplingRule, -) -from opentelemetry.sdk.extension.aws.trace.sampler._sampling_statistics_document import ( - _SamplingStatisticsDocument, -) -from opentelemetry.sdk.extension.aws.trace.sampler._sampling_target import ( - _SamplingTarget, -) +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from opentelemetry.sdk.extension.aws.trace.sampler._clock import _Clock + + # pylint: disable=no-name-in-module + from opentelemetry.sdk.extension.aws.trace.sampler._sampling_rule import ( + _SamplingRule, + ) + from opentelemetry.sdk.extension.aws.trace.sampler._sampling_statistics_document import ( + _SamplingStatisticsDocument, + ) + from opentelemetry.sdk.extension.aws.trace.sampler._sampling_target import ( + _SamplingTarget, + ) class _SamplingRuleApplier: diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/aws_xray_remote_sampler.py b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/aws_xray_remote_sampler.py index 0f34a83be3..598c9873fa 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/aws_xray_remote_sampler.py +++ b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/sampler/aws_xray_remote_sampler.py @@ -21,16 +21,22 @@ import random from logging import getLogger from threading import Timer -from typing import Sequence +from typing import TYPE_CHECKING, Sequence from typing_extensions import override # pylint: disable=no-name-in-module -from opentelemetry.context import Context from opentelemetry.sdk.extension.aws.trace.sampler._aws_xray_sampling_client import ( DEFAULT_SAMPLING_PROXY_ENDPOINT, _AwsXRaySamplingClient, ) + +if TYPE_CHECKING: + from opentelemetry.context import Context + from opentelemetry.trace import Link, SpanKind + from opentelemetry.trace.span import TraceState + from opentelemetry.util.types import Attributes + from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace.sampling import ( Decision, @@ -38,9 +44,6 @@ Sampler, SamplingResult, ) -from opentelemetry.trace import Link, SpanKind -from opentelemetry.trace.span import TraceState -from opentelemetry.util.types import Attributes _logger = getLogger(__name__) diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_upload/completion_hook.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_upload/completion_hook.py index 79ebd3a170..de56714191 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_upload/completion_hook.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/_upload/completion_hook.py @@ -26,6 +26,12 @@ Future, ThreadPoolExecutor, ) +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from opentelemetry._logs import LogRecord + from opentelemetry.trace import Span + from contextlib import ExitStack from dataclasses import asdict, dataclass from functools import partial @@ -35,9 +41,7 @@ import fsspec -from opentelemetry._logs import LogRecord from opentelemetry.semconv._incubating.attributes import gen_ai_attributes -from opentelemetry.trace import Span from opentelemetry.util.genai import types from opentelemetry.util.genai.completion_hook import CompletionHook from opentelemetry.util.genai.utils import gen_ai_json_dump diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/completion_hook.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/completion_hook.py index b66b1217a5..6abb585f93 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/completion_hook.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/completion_hook.py @@ -25,18 +25,21 @@ import logging from os import environ -from typing import Any, Protocol, cast, runtime_checkable +from typing import TYPE_CHECKING, Any, Protocol, cast, runtime_checkable -from opentelemetry._logs import LogRecord -from opentelemetry.trace import Span from opentelemetry.util._importlib_metadata import ( entry_points, # pyright: ignore[reportUnknownVariableType] ) -from opentelemetry.util.genai import types from opentelemetry.util.genai.environment_variables import ( OTEL_INSTRUMENTATION_GENAI_COMPLETION_HOOK, ) +if TYPE_CHECKING: + from opentelemetry._logs import LogRecord + from opentelemetry.trace import Span + from opentelemetry.util.genai import types + + _logger = logging.getLogger(__name__) @@ -100,7 +103,7 @@ def load_completion_hook() -> CompletionHook: for entry_point in entry_points( # pyright: ignore[reportUnknownVariableType] group="opentelemetry_genai_completion_hook" ): - name = cast(str, entry_point.name) # pyright: ignore[reportUnknownMemberType] + name = cast("str", entry_point.name) # pyright: ignore[reportUnknownMemberType] try: if hook_name != name: continue diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/metrics.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/metrics.py index 075cbe60a1..4be75d31ef 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/metrics.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/metrics.py @@ -3,12 +3,17 @@ from __future__ import annotations import timeit -from typing import Dict, Optional +from typing import TYPE_CHECKING, Dict, Optional -from opentelemetry.metrics import Histogram, Meter from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAI, ) + +if TYPE_CHECKING: + from opentelemetry.metrics import Histogram, Meter + from opentelemetry.util.genai.types import LLMInvocation + from opentelemetry.util.types import AttributeValue + from opentelemetry.semconv.attributes import ( error_attributes, server_attributes, @@ -18,8 +23,6 @@ create_duration_histogram, create_token_histogram, ) -from opentelemetry.util.genai.types import LLMInvocation -from opentelemetry.util.types import AttributeValue class InvocationMetricsRecorder: diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py index 0a82462c1b..741467fa5b 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py @@ -15,7 +15,7 @@ from __future__ import annotations from dataclasses import asdict -from typing import Any +from typing import TYPE_CHECKING, Any from opentelemetry._logs import Logger, LogRecord from opentelemetry.context import get_current @@ -26,21 +26,8 @@ error_attributes, server_attributes, ) -from opentelemetry.trace import ( - Span, -) from opentelemetry.trace.propagation import set_span_in_context from opentelemetry.trace.status import Status, StatusCode -from opentelemetry.util.genai.types import ( - EmbeddingInvocation, - Error, - GenAIInvocation, - InputMessage, - LLMInvocation, - MessagePart, - OutputMessage, - WorkflowInvocation, -) from opentelemetry.util.genai.utils import ( ContentCapturingMode, gen_ai_json_dumps, @@ -49,6 +36,21 @@ should_emit_event, ) +if TYPE_CHECKING: + from opentelemetry.trace import ( + Span, + ) + from opentelemetry.util.genai.types import ( + EmbeddingInvocation, + Error, + GenAIInvocation, + InputMessage, + LLMInvocation, + MessagePart, + OutputMessage, + WorkflowInvocation, + ) + def _get_llm_common_attributes( invocation: LLMInvocation, diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py index 6d59f03bf5..f83a37b536 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py @@ -17,7 +17,7 @@ from contextvars import Token from dataclasses import dataclass, field from enum import Enum -from typing import Any, Literal, Type, Union +from typing import TYPE_CHECKING, Any, Literal, Type, Union from typing_extensions import TypeAlias @@ -25,7 +25,9 @@ from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAI, ) -from opentelemetry.trace import Span + +if TYPE_CHECKING: + from opentelemetry.trace import Span ContextToken: TypeAlias = Token[Context] diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py index 69c2612f1d..db5e13fbe2 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -14,12 +14,11 @@ from __future__ import annotations -from collections.abc import Mapping from os import environ from re import IGNORECASE as RE_IGNORECASE from re import compile as re_compile from re import search -from typing import Callable, Iterable, overload +from typing import TYPE_CHECKING, Callable, Iterable, overload from urllib.parse import parse_qs, urlencode, urlparse, urlunparse from opentelemetry.semconv._incubating.attributes.http_attributes import ( @@ -30,6 +29,10 @@ HTTP_SERVER_NAME, HTTP_STATUS_CODE, ) + +if TYPE_CHECKING: + from collections.abc import Mapping + from opentelemetry.semconv._incubating.attributes.net_attributes import ( NET_HOST_NAME, NET_HOST_PORT, diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py index 2a3723c927..60a5b76e30 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/httplib.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + """ This library provides functionality to enrich HTTP client spans with IPs. It does not create spans on its own. @@ -22,9 +23,17 @@ import contextlib import http.client import logging -import socket # pylint:disable=unused-import # Used for typing -import typing -from typing import Any, Callable, Collection, TypedDict, cast +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Collection, + List, + Optional, + TypedDict, + TypeVar, + cast, +) import wrapt @@ -34,13 +43,17 @@ from opentelemetry.semconv._incubating.attributes.net_attributes import ( NET_PEER_IP, ) -from opentelemetry.trace.span import Span + +if TYPE_CHECKING: + import socket # pylint:disable=unused-import # Used for typing + + from opentelemetry.trace.span import Span _STATE_KEY = "httpbase_instrumentation_state" logger = logging.getLogger(__name__) -R = typing.TypeVar("R") +R = TypeVar("R") class HttpClientInstrumentor(BaseInstrumentor): @@ -86,7 +99,7 @@ def trysetip( state = _getstate() if not state: return True - spanlist: typing.List[Span] = state.get("need_ip") + spanlist: List[Span] = state.get("need_ip") if not spanlist: return True @@ -97,7 +110,7 @@ def trysetip( sock = "" ip = None try: - sock: typing.Optional[socket.socket] = conn.sock + sock: Optional[socket.socket] = conn.sock logger.debug("Got socket: %s", sock) if sock is None: return False @@ -168,7 +181,7 @@ class _ConnectionState(TypedDict): def _getstate() -> _ConnectionState | None: - return cast(_ConnectionState, context.get_value(_STATE_KEY)) + return cast("_ConnectionState", context.get_value(_STATE_KEY)) @contextlib.contextmanager