diff --git a/CHANGELOG.md b/CHANGELOG.md index e206925782..175c44737b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3882](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3882)) - `opentelemetry-instrumentation-aiohttp-server`: delay initialization of tracer, meter and excluded urls to instrumentation for testability ([#3836](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3836)) +- Replace Python 3.14-deprecated `asyncio.iscoroutinefunction` with `inspect.iscoroutinefunction`. + ([#3880](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3880)) ## Version 1.38.0/0.59b0 (2025-10-16) diff --git a/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/__init__.py b/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/__init__.py index 32837b23c5..d4662c9329 100644 --- a/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiokafka/src/opentelemetry/instrumentation/aiokafka/__init__.py @@ -95,7 +95,7 @@ async def produce(): from __future__ import annotations -from asyncio import iscoroutinefunction +from inspect import iscoroutinefunction from typing import TYPE_CHECKING, Collection import aiokafka diff --git a/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py b/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py index c005920368..892689b853 100644 --- a/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-aiokafka/tests/test_instrumentation.py @@ -261,11 +261,21 @@ async def async_consume_hook(span, *_) -> None: async def test_getone_consume_hook(self) -> None: async_consume_hook_mock = mock.AsyncMock() + def is_async_consume_hook_mock(obj: Any) -> bool: + return obj is async_consume_hook_mock + AIOKafkaInstrumentor().uninstrument() - AIOKafkaInstrumentor().instrument( - tracer_provider=self.tracer_provider, - async_consume_hook=async_consume_hook_mock, - ) + + # mock.patch is a hack for Python 3.9 see https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3880 + with mock.patch( + "opentelemetry.instrumentation.aiokafka.iscoroutinefunction" + ) as iscoro: + iscoro.side_effect = is_async_consume_hook_mock + + AIOKafkaInstrumentor().instrument( + tracer_provider=self.tracer_provider, + async_consume_hook=async_consume_hook_mock, + ) consumer = await self.consumer_factory() self.addAsyncCleanup(consumer.stop) @@ -448,11 +458,20 @@ async def test_send_baggage(self) -> None: async def test_send_produce_hook(self) -> None: async_produce_hook_mock = mock.AsyncMock() + def is_async_produce_hook_mock(obj: Any) -> bool: + return obj is async_produce_hook_mock + AIOKafkaInstrumentor().uninstrument() - AIOKafkaInstrumentor().instrument( - tracer_provider=self.tracer_provider, - async_produce_hook=async_produce_hook_mock, - ) + # mock.patch is a hack for Python 3.9 see https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3880 + with mock.patch( + "opentelemetry.instrumentation.aiokafka.iscoroutinefunction" + ) as iscoro: + iscoro.side_effect = is_async_produce_hook_mock + + AIOKafkaInstrumentor().instrument( + tracer_provider=self.tracer_provider, + async_produce_hook=async_produce_hook_mock, + ) producer = await self.producer_factory() self.addAsyncCleanup(producer.stop) diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py index 4e6257fbb1..948050818c 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py @@ -1,4 +1,4 @@ -import asyncio +import inspect import typing from collections.abc import Coroutine @@ -197,7 +197,7 @@ async def __aenter__(self): async def __aexit__(self, exc_type, exc, t_b): try: - if asyncio.iscoroutinefunction(self._obj.close): + if inspect.iscoroutinefunction(self._obj.close): await self._obj.close() else: self._obj.close() 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 2a82a123f9..67dc9aa960 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py @@ -225,8 +225,8 @@ async def async_response_hook(span, request, response): import logging import typing -from asyncio import iscoroutinefunction from functools import partial +from inspect import iscoroutinefunction from timeit import default_timer from types import TracebackType diff --git a/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py b/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py index e6506d290a..909ec33009 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/tests/test_httpx_integration.py @@ -16,6 +16,7 @@ import abc import asyncio +import inspect import typing from unittest import mock @@ -1086,7 +1087,7 @@ def test_custom_tracer_provider(self): def test_response_hook(self): response_hook_key = ( "async_response_hook" - if asyncio.iscoroutinefunction(self.response_hook) + if inspect.iscoroutinefunction(self.response_hook) else "response_hook" ) response_hook_kwargs = {response_hook_key: self.response_hook} @@ -1133,7 +1134,7 @@ def test_response_hook_sync_async_kwargs(self): def test_request_hook(self): request_hook_key = ( "async_request_hook" - if asyncio.iscoroutinefunction(self.request_hook) + if inspect.iscoroutinefunction(self.request_hook) else "request_hook" ) request_hook_kwargs = {request_hook_key: self.request_hook}