fix: suppress ruff PLC0415 for conditional gevent import (#3842)

The generate_instrumentation_bootstrap.py script was failing with a
ruff linting error (PLC0415: import should be at top-level) when
checking the auto_instrumentation module.

Add noqa comment to suppress this error for the gevent monkey patch
import, which is intentionally inside a try-except block for
conditional loading. This allows the bootstrap generation script
to complete successfully.
This commit is contained in:
Luke (GuangHui) Zhang
2025-11-13 03:23:10 -08:00
committed by GitHub
parent 123f55615d
commit 4f89e758b1
24 changed files with 100 additions and 78 deletions

View File

@@ -143,7 +143,7 @@ def get_contrib_job_datas(tox_envs: list) -> list:
contrib_job_datas.append(
{
"ui_name": (f"{groups['name']}" f"{contrib_requirements}"),
"ui_name": (f"{groups['name']}{contrib_requirements}"),
"tox_env": tox_env,
}
)

View File

@@ -1,7 +1,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
rev: v0.14.1
hooks:
# Run the linter.
- id: ruff

View File

@@ -43,7 +43,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `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))
- `opentelemetry-instrumentation-elasticsearch`: Enhance elasticsearch query body sanitization
([#3919](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3919))
([#3919](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3919))
- build: bump ruff to 0.14.1
([#3842](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3842))
## Version 1.38.0/0.59b0 (2025-10-16)

View File

@@ -15,4 +15,4 @@ ruamel.yaml==0.17.21
flaky==3.7.0
pre-commit==3.7.0; python_version >= '3.9'
pre-commit==3.5.0; python_version < '3.9'
ruff==0.6.9
ruff==0.14.1

View File

@@ -122,9 +122,9 @@ def test_parse_metric(metric, prom_rw):
"bool_value": True,
}
assert (
len(metric.data.data_points) == 1
), "We can only support a single datapoint in tests"
assert len(metric.data.data_points) == 1, (
"We can only support a single datapoint in tests"
)
series = prom_rw._parse_metric(metric, tuple(attributes.items()))
timestamp = metric.data.data_points[0].time_unix_nano // 1_000_000
for single_series in series:

View File

@@ -2,7 +2,7 @@
astor==0.8.1
jinja2==3.1.6
markupsafe==2.0.1
ruff==0.6.9
ruff==0.14.1
requests
tomli
tomli_w

View File

@@ -164,9 +164,9 @@ class OTelMocker:
def assert_has_span_named(self, name):
span = self.get_span_named(name)
finished_spans = [span.name for span in self.get_finished_spans()]
assert (
span is not None
), f'Could not find span named "{name}"; finished spans: {finished_spans}'
assert span is not None, (
f'Could not find span named "{name}"; finished spans: {finished_spans}'
)
def assert_does_not_have_span_named(self, name):
span = self.get_span_named(name)
@@ -192,9 +192,9 @@ class OTelMocker:
def assert_has_event_named(self, name):
event = self.get_event_named(name)
finished_logs = self.get_finished_logs()
assert (
event is not None
), f'Could not find event named "{name}"; finished logs: {finished_logs}'
assert event is not None, (
f'Could not find event named "{name}"; finished logs: {finished_logs}'
)
def assert_does_not_have_event_named(self, name):
event = self.get_event_named(name)

View File

@@ -129,7 +129,7 @@ class OpenAIInstrumentor(BaseInstrumentor):
)
def _uninstrument(self, **kwargs):
import openai # pylint: disable=import-outside-toplevel
import openai # pylint: disable=import-outside-toplevel # noqa: PLC0415
unwrap(openai.resources.chat.completions.Completions, "create")
unwrap(openai.resources.chat.completions.AsyncCompletions, "create")

View File

@@ -68,14 +68,14 @@ def _methods_to_wrap(
):
# This import is very slow, do it lazily in case instrument() is not called
# pylint: disable=import-outside-toplevel
from google.cloud.aiplatform_v1.services.prediction_service import (
from google.cloud.aiplatform_v1.services.prediction_service import ( # noqa: PLC0415
async_client,
client,
)
from google.cloud.aiplatform_v1beta1.services.prediction_service import (
from google.cloud.aiplatform_v1beta1.services.prediction_service import ( # noqa: PLC0415
async_client as async_client_v1beta1,
)
from google.cloud.aiplatform_v1beta1.services.prediction_service import (
from google.cloud.aiplatform_v1beta1.services.prediction_service import ( # noqa: PLC0415
client as client_v1beta1,
)

View File

@@ -1,4 +1,8 @@
import pytest
from tests.shared_test_utils import (
ask_about_weather,
ask_about_weather_function_response,
)
from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor
from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import (
@@ -7,10 +11,6 @@ from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import (
from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
InMemorySpanExporter,
)
from tests.shared_test_utils import (
ask_about_weather,
ask_about_weather_function_response,
)
@pytest.mark.vcr()

View File

@@ -4,6 +4,10 @@ from typing import Any
import fsspec
import pytest
from tests.shared_test_utils import (
ask_about_weather,
ask_about_weather_function_response,
)
from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor
from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import (
@@ -12,10 +16,6 @@ from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import (
from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
InMemorySpanExporter,
)
from tests.shared_test_utils import (
ask_about_weather,
ask_about_weather_function_response,
)
def test_function_call_choice(

View File

@@ -351,9 +351,9 @@ class ClickTestCase(TestBase, IsolatedAsyncioTestCase):
async def command2() -> None:
pass
async def run_both() -> (
tuple[asyncclick.testing.Result, asyncclick.testing.Result]
):
async def run_both() -> tuple[
asyncclick.testing.Result, asyncclick.testing.Result
]:
runner = CliRunner()
task1 = asyncio.create_task(runner.invoke(command1))
task2 = asyncio.create_task(runner.invoke(command2))

View File

@@ -279,9 +279,9 @@ def remove_none_values(body):
def assert_log_parent(log, span):
if span:
assert (
log.log_record.trace_id == span.get_span_context().trace_id
), f"{span.get_span_context().trace_id} does not equal {log.log_record.trace_id}"
assert log.log_record.trace_id == span.get_span_context().trace_id, (
f"{span.get_span_context().trace_id} does not equal {log.log_record.trace_id}"
)
assert log.log_record.span_id == span.get_span_context().span_id
assert (
log.log_record.trace_flags == span.get_span_context().trace_flags

View File

@@ -287,9 +287,9 @@ class TestBaseManualFastAPI(TestBaseFastAPI):
"""If the application has an unhandled error the instrumentation should capture that a 500 response is returned."""
try:
resp = self._client.get("/error")
assert (
resp.status_code == 500
), resp.content # pragma: no cover, for debugging this test if an exception is _not_ raised
assert resp.status_code == 500, (
resp.content
) # pragma: no cover, for debugging this test if an exception is _not_ raised
except UnhandledException:
pass
else:
@@ -2442,9 +2442,9 @@ class TestFastAPIHostHeaderURLBothSemconv(TestFastAPIHostHeaderURL):
"""If the application has an unhandled error the instrumentation should capture that a 500 response is returned."""
try:
resp = self._client.get("/error")
assert (
resp.status_code == 500
), resp.content # pragma: no cover, for debugging this test if an exception is _not_ raised
assert resp.status_code == 500, (
resp.content
) # pragma: no cover, for debugging this test if an exception is _not_ raised
except UnhandledException:
pass
else:

View File

@@ -879,7 +879,7 @@ class TestProgrammaticHooksWithoutApp(InstrumentationTest, WsgiTestBase):
request_hook=request_hook_test, response_hook=response_hook_test
)
# pylint: disable=import-outside-toplevel,reimported,redefined-outer-name
from flask import Flask
from flask import Flask # noqa: PLC0415
self.app = Flask(__name__)
@@ -949,7 +949,7 @@ class TestProgrammaticCustomTracerProviderWithoutApp(
FlaskInstrumentor().instrument(tracer_provider=tracer_provider)
# pylint: disable=import-outside-toplevel,reimported,redefined-outer-name
from flask import Flask
from flask import Flask # noqa: PLC0415
self.app = Flask(__name__)

View File

@@ -584,7 +584,7 @@ def client_interceptor(
Returns:
An invocation-side interceptor object.
"""
from . import _client
from . import _client # noqa: PLC0415
tracer = trace.get_tracer(
__name__,
@@ -614,7 +614,7 @@ def server_interceptor(tracer_provider=None, filter_=None):
Returns:
A service-side interceptor object.
"""
from . import _server
from . import _server # noqa: PLC0415
tracer = trace.get_tracer(
__name__,
@@ -637,7 +637,7 @@ def aio_client_interceptors(
Returns:
An invocation-side interceptor object.
"""
from . import _aio_client
from . import _aio_client # noqa: PLC0415
tracer = trace.get_tracer(
__name__,
@@ -683,7 +683,7 @@ def aio_server_interceptor(tracer_provider=None, filter_=None):
Returns:
A service-side interceptor object.
"""
from . import _aio_server
from . import _aio_server # noqa: PLC0415
tracer = trace.get_tracer(
__name__,

View File

@@ -112,7 +112,7 @@ def intercept_channel(channel, *interceptors):
TypeError: If an interceptor derives from neither UnaryClientInterceptor
nor StreamClientInterceptor.
"""
from . import _interceptor
from . import _interceptor # noqa: PLC0415
return _interceptor.intercept_channel(channel, *interceptors)

View File

@@ -59,9 +59,9 @@ class TestPika(TestCase):
_QueueConsumerGeneratorInfo.__init__, BoundFunctionWrapper
)
)
assert hasattr(
instrumentation, "__opentelemetry_tracer_provider"
), "Tracer not stored for the object!"
assert hasattr(instrumentation, "__opentelemetry_tracer_provider"), (
"Tracer not stored for the object!"
)
instrumentation.uninstrument()
self.assertFalse(
isinstance(BlockingConnection.channel, BoundFunctionWrapper)
@@ -115,9 +115,9 @@ class TestPika(TestCase):
instrument_channel_functions: mock.MagicMock,
):
PikaInstrumentor.instrument_channel(channel=self.channel)
assert hasattr(
self.channel, "_is_instrumented_by_opentelemetry"
), "channel is not marked as instrumented!"
assert hasattr(self.channel, "_is_instrumented_by_opentelemetry"), (
"channel is not marked as instrumented!"
)
instrument_channel_consumers.assert_called_once()
instrument_basic_consume.assert_called_once()
instrument_channel_functions.assert_called_once()

View File

@@ -552,7 +552,7 @@ class PymemcacheHashClientTestCase(TestBase):
current_port = TEST_PORT
# pylint: disable=import-outside-toplevel
from pymemcache.client.hash import HashClient
from pymemcache.client.hash import HashClient # noqa: PLC0415
# pylint: disable=attribute-defined-outside-init
self.client = HashClient([], **kwargs)

View File

@@ -111,7 +111,7 @@ class TestSqlalchemyInstrumentation(TestBase):
)
def test_async_trace_integration(self):
async def run():
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
from sqlalchemy.ext.asyncio import ( # pylint: disable-all # noqa: PLC0415
create_async_engine,
)
@@ -161,7 +161,9 @@ class TestSqlalchemyInstrumentation(TestBase):
def test_create_engine_wrapper(self):
SQLAlchemyInstrumentor().instrument()
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -188,7 +190,9 @@ class TestSqlalchemyInstrumentation(TestBase):
def test_instrument_engine_from_config(self):
SQLAlchemyInstrumentor().instrument()
from sqlalchemy import engine_from_config # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
engine_from_config, # pylint: disable-all
)
engine = engine_from_config({"sqlalchemy.url": "sqlite:///:memory:"})
cnx = engine.connect()
@@ -203,7 +207,9 @@ class TestSqlalchemyInstrumentation(TestBase):
enable_commenter=True,
commenter_options={"db_framework": False},
)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -231,7 +237,9 @@ class TestSqlalchemyInstrumentation(TestBase):
commenter_options={"db_framework": False},
enable_attribute_commenter=True,
)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -261,7 +269,9 @@ class TestSqlalchemyInstrumentation(TestBase):
"opentelemetry_values": False,
},
)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -294,7 +304,9 @@ class TestSqlalchemyInstrumentation(TestBase):
},
enable_attribute_commenter=True,
)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -330,7 +342,9 @@ class TestSqlalchemyInstrumentation(TestBase):
)
SQLAlchemyInstrumentor().instrument(tracer_provider=provider)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -353,7 +367,7 @@ class TestSqlalchemyInstrumentation(TestBase):
def test_create_async_engine_wrapper(self):
async def run():
SQLAlchemyInstrumentor().instrument()
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
from sqlalchemy.ext.asyncio import ( # pylint: disable-all # noqa: PLC0415
create_async_engine,
)
@@ -394,7 +408,7 @@ class TestSqlalchemyInstrumentation(TestBase):
"db_framework": False,
},
)
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
from sqlalchemy.ext.asyncio import ( # pylint: disable-all # noqa: PLC0415
create_async_engine,
)
@@ -433,7 +447,7 @@ class TestSqlalchemyInstrumentation(TestBase):
},
enable_attribute_commenter=True,
)
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
from sqlalchemy.ext.asyncio import ( # pylint: disable-all # noqa: PLC0415
create_async_engine,
)
@@ -474,7 +488,7 @@ class TestSqlalchemyInstrumentation(TestBase):
"opentelemetry_values": False,
},
)
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
from sqlalchemy.ext.asyncio import ( # pylint: disable-all # noqa: PLC0415
create_async_engine,
)
@@ -516,7 +530,7 @@ class TestSqlalchemyInstrumentation(TestBase):
},
enable_attribute_commenter=True,
)
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
from sqlalchemy.ext.asyncio import ( # pylint: disable-all # noqa: PLC0415
create_async_engine,
)
@@ -581,7 +595,7 @@ class TestSqlalchemyInstrumentation(TestBase):
SQLAlchemyInstrumentor().instrument(
tracer_provider=self.tracer_provider
)
from sqlalchemy import create_engine
from sqlalchemy import create_engine # noqa: PLC0415
engine = create_engine("sqlite:///:memory:")
@@ -609,12 +623,12 @@ class TestSqlalchemyInstrumentation(TestBase):
def test_no_memory_leakage_if_engine_diposed(self):
SQLAlchemyInstrumentor().instrument()
import gc
import weakref
import gc # noqa: PLC0415
import weakref # noqa: PLC0415
from sqlalchemy import create_engine
from sqlalchemy import create_engine # noqa: PLC0415
from opentelemetry.instrumentation.sqlalchemy.engine import (
from opentelemetry.instrumentation.sqlalchemy.engine import ( # noqa: PLC0415
EngineTracer,
)
@@ -638,7 +652,7 @@ class TestSqlalchemyInstrumentation(TestBase):
def test_suppress_instrumentation_create_engine(self):
SQLAlchemyInstrumentor().instrument()
from sqlalchemy import create_engine
from sqlalchemy import create_engine # noqa: PLC0415
with suppress_instrumentation():
engine = create_engine("sqlite:///:memory:")
@@ -652,7 +666,7 @@ class TestSqlalchemyInstrumentation(TestBase):
def test_suppress_instrumentation_create_async_engine(self):
async def run():
SQLAlchemyInstrumentor().instrument()
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
from sqlalchemy.ext.asyncio import ( # pylint: disable-all # noqa: PLC0415
create_async_engine,
)

View File

@@ -304,7 +304,9 @@ class TestSqlalchemyInstrumentationWithSQLCommenter(TestBase):
tracer_provider=self.tracer_provider,
enable_commenter=True,
)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -332,7 +334,9 @@ class TestSqlalchemyInstrumentationWithSQLCommenter(TestBase):
enable_commenter=True,
enable_attribute_commenter=True,
)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()
@@ -357,7 +361,9 @@ class TestSqlalchemyInstrumentationWithSQLCommenter(TestBase):
tracer_provider=self.tracer_provider,
enable_commenter=False,
)
from sqlalchemy import create_engine # pylint: disable-all
from sqlalchemy import ( # noqa: PLC0415
create_engine, # pylint: disable-all
)
engine = create_engine("sqlite:///:memory:")
cnx = engine.connect()

View File

@@ -149,7 +149,7 @@ def initialize(*, swallow_exceptions: bool = True) -> None:
else:
try:
# pylint: disable=import-outside-toplevel
from gevent import monkey
from gevent import monkey # noqa: PLC0415
getattr(monkey, gevent_patch)()
except ImportError:

View File

@@ -29,7 +29,7 @@ def upload_completion_hook() -> CompletionHook:
# If fsspec is not installed the hook will be a no-op.
try:
# pylint: disable=import-outside-toplevel
from opentelemetry.util.genai._upload.completion_hook import (
from opentelemetry.util.genai._upload.completion_hook import ( # noqa: PLC0415
UploadCompletionHook,
)
except ImportError:

View File

@@ -58,7 +58,7 @@ class TestUploadEntryPoint(TestCase):
def test_upload_entry_point_no_fsspec(self):
"""Tests that the a no-op uploader is used when fsspec is not installed"""
from opentelemetry.util.genai import _upload
from opentelemetry.util.genai import _upload # noqa: PLC0415
# Simulate fsspec imports failing
with patch.dict(