From a5b568cbecee0e5dc77abe7ff834c755a37a174f Mon Sep 17 00:00:00 2001 From: Dylan Russell Date: Wed, 29 Jul 2026 14:09:38 +0000 Subject: [PATCH] Upgrade ruff --- .pre-commit-config.yaml | 7 ++- dev-requirements.txt | 2 +- gen-requirements.txt | 2 +- instrumentation-genai/AGENTS.md | 8 ++- .../instrumentation/aio_pika/__init__.py | 5 +- .../aiohttp_client/__init__.py | 33 ++++++---- .../instrumentation/aiopg/__init__.py | 22 +++++-- .../instrumentation/asgi/__init__.py | 62 +++++++++++++------ .../instrumentation/asyncclick/__init__.py | 4 +- .../instrumentation/asyncpg/__init__.py | 4 +- .../instrumentation/click/__init__.py | 4 +- .../instrumentation/falcon/__init__.py | 13 +++- .../instrumentation/fastapi/__init__.py | 28 +++++++-- .../instrumentation/flask/__init__.py | 21 +++++-- .../instrumentation/grpc/__init__.py | 25 +++++--- .../instrumentation/httpx/__init__.py | 35 ++++++++--- .../instrumentation/logging/__init__.py | 4 +- .../instrumentation/pika/__init__.py | 51 ++++++++++----- .../instrumentation/psycopg/__init__.py | 4 +- .../instrumentation/psycopg2/__init__.py | 4 +- .../instrumentation/pymemcache/__init__.py | 5 +- .../instrumentation/remoulade/__init__.py | 2 + .../instrumentation/starlette/__init__.py | 36 ++++++++--- .../instrumentation/structlog/__init__.py | 4 +- .../instrumentation/tornado/__init__.py | 6 ++ .../instrumentation/urllib/__init__.py | 2 +- .../instrumentation/urllib3/__init__.py | 2 + .../instrumentation/wsgi/__init__.py | 35 ++++++++--- .../src/opentelemetry/_opamp/__init__.py | 5 +- .../instrumentation/_labeler/__init__.py | 1 + pyproject.toml | 4 ++ util/opentelemetry-util-genai/AGENTS.md | 4 +- 32 files changed, 330 insertions(+), 114 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ac2bc78f9d..c3fd9b2e65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,18 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.14.1 + rev: v0.16.0 hooks: # Run the linter. - id: ruff args: ["--fix", "--show-fixes"] # Run the formatter. - id: ruff-format + - id: ruff-format + name: ruff-format (markdown & towncrier) + types_or: [python, pyi, jupyter, markdown, text] + files: \.(md|added|changed|deprecated|removed|fixed)$ + args: ["--preview"] - repo: https://github.com/astral-sh/uv-pre-commit # uv version. rev: 1ce7e7fa8aa6eda60e54755509a9380b0f1c5d08 # frozen: v0.9.30 diff --git a/dev-requirements.txt b/dev-requirements.txt index abcf1efe03..9d3b25a0d1 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -13,4 +13,4 @@ requests==2.33.1 ruamel.yaml==0.17.21 flaky==3.7.0 pre-commit==3.7.0 -ruff==0.14.1 +ruff==0.16.0 diff --git a/gen-requirements.txt b/gen-requirements.txt index 2512362a93..9382804471 100644 --- a/gen-requirements.txt +++ b/gen-requirements.txt @@ -2,7 +2,7 @@ astor==0.8.1 jinja2==3.1.6 markupsafe==2.0.1 -ruff==0.14.1 +ruff==0.16.0 requests tomli tomli_w diff --git a/instrumentation-genai/AGENTS.md b/instrumentation-genai/AGENTS.md index 9cde4973ad..23ee4c2337 100644 --- a/instrumentation-genai/AGENTS.md +++ b/instrumentation-genai/AGENTS.md @@ -54,6 +54,7 @@ hook without touching the environment. from opentelemetry.util.genai.completion_hook import load_completion_hook from opentelemetry.util.genai.handler import TelemetryHandler + def _instrument(self, **kwargs): tracer_provider = kwargs.get("tracer_provider") meter_provider = kwargs.get("meter_provider") @@ -63,7 +64,8 @@ def _instrument(self, **kwargs): tracer_provider=tracer_provider, meter_provider=meter_provider, logger_provider=logger_provider, - completion_hook=kwargs.get("completion_hook") or load_completion_hook(), + completion_hook=kwargs.get("completion_hook") + or load_completion_hook(), ) # pass handler to each patch/wrapper function ``` @@ -73,7 +75,9 @@ def _instrument(self, **kwargs): Use `start_*()` and control span lifetime manually: ```python -invocation = handler.start_inference(provider, request_model, server_address=..., server_port=...) +invocation = handler.start_inference( + provider, request_model, server_address=..., server_port=... +) invocation.temperature = ... try: response = client.call(...) diff --git a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/__init__.py b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/__init__.py index cb24606194..274970cd6f 100644 --- a/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aio-pika/src/opentelemetry/instrumentation/aio_pika/__init__.py @@ -30,8 +30,9 @@ async def main() -> None: channel = await connection.channel() queue = await channel.declare_queue("hello") await channel.default_exchange.publish( - Message(b"Hello World!"), - routing_key=queue.name) + Message(b"Hello World!"), routing_key=queue.name + ) + if __name__ == "__main__": asyncio.run(main()) 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 206ba8b2e1..75710934db 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 @@ -61,17 +61,28 @@ async def get(url): .. code-block:: python def request_hook(span: Span, params: aiohttp.TraceRequestStartParams): - if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_request_hook", "some-value") - - def response_hook(span: Span, params: typing.Union[ - aiohttp.TraceRequestEndParams, - aiohttp.TraceRequestExceptionParams, - ]): - if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_response_hook", "some-value") - - AioHttpClientInstrumentor().instrument(request_hook=request_hook, response_hook=response_hook) + if span and span.is_recording(): + span.set_attribute( + "custom_user_attribute_from_request_hook", "some-value" + ) + + + def response_hook( + span: Span, + params: typing.Union[ + aiohttp.TraceRequestEndParams, + aiohttp.TraceRequestExceptionParams, + ], + ): + if span and span.is_recording(): + span.set_attribute( + "custom_user_attribute_from_response_hook", "some-value" + ) + + + AioHttpClientInstrumentor().instrument( + request_hook=request_hook, response_hook=response_hook + ) Exclude lists ************* diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/__init__.py b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/__init__.py index 8167847002..85d821837c 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/__init__.py @@ -15,28 +15,36 @@ import asyncio import aiopg from opentelemetry.instrumentation.aiopg import AiopgInstrumentor + # Call instrument() to wrap all database connections AiopgInstrumentor().instrument() - dsn = 'user=user password=password host=127.0.0.1' + dsn = "user=user password=password host=127.0.0.1" + async def connect(): cnx = await aiopg.connect(dsn) cursor = await cnx.cursor() - await cursor.execute("CREATE TABLE IF NOT EXISTS test (testField INTEGER)") + await cursor.execute( + "CREATE TABLE IF NOT EXISTS test (testField INTEGER)" + ) await cursor.execute("INSERT INTO test (testField) VALUES (123)") cursor.close() cnx.close() + async def create_pool(): pool = await aiopg.create_pool(dsn) cnx = await pool.acquire() cursor = await cnx.cursor() - await cursor.execute("CREATE TABLE IF NOT EXISTS test (testField INTEGER)") + await cursor.execute( + "CREATE TABLE IF NOT EXISTS test (testField INTEGER)" + ) await cursor.execute("INSERT INTO test (testField) VALUES (123)") cursor.close() cnx.close() + asyncio.run(connect()) asyncio.run(create_pool()) @@ -46,18 +54,22 @@ async def create_pool(): import aiopg from opentelemetry.instrumentation.aiopg import AiopgInstrumentor - dsn = 'user=user password=password host=127.0.0.1' + dsn = "user=user password=password host=127.0.0.1" + # Alternatively, use instrument_connection for an individual connection async def go(): cnx = await aiopg.connect(dsn) instrumented_cnx = AiopgInstrumentor().instrument_connection(cnx) cursor = await instrumented_cnx.cursor() - await cursor.execute("CREATE TABLE IF NOT EXISTS test (testField INTEGER)") + await cursor.execute( + "CREATE TABLE IF NOT EXISTS test (testField INTEGER)" + ) await cursor.execute("INSERT INTO test (testField) VALUES (123)") cursor.close() instrumented_cnx.close() + asyncio.run(go()) API 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 efcc8ee05f..eb50dd05cc 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -17,10 +17,12 @@ app = Quart(__name__) app.asgi_app = OpenTelemetryMiddleware(app.asgi_app) + @app.route("/") async def hello(): return "Hello!" + if __name__ == "__main__": app.run(debug=True) @@ -36,7 +38,7 @@ async def hello(): from django.core.asgi import get_asgi_application from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'asgi_example.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "asgi_example.settings") application = get_asgi_application() application = OpenTelemetryMiddleware(application) @@ -75,33 +77,57 @@ async def hello(): from asgiref.typing import Scope, ASGIReceiveEvent, ASGISendEvent from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware - async def application(scope: Scope, receive: ASGIReceiveEvent, send: ASGISendEvent): - await send({ - 'type': 'http.response.start', - 'status': 200, - 'headers': [ - [b'content-type', b'text/plain'], - ], - }) - await send({ - 'type': 'http.response.body', - 'body': b'Hello, world!', - }) + async def application( + scope: Scope, receive: ASGIReceiveEvent, send: ASGISendEvent + ): + await send( + { + "type": "http.response.start", + "status": 200, + "headers": [ + [b"content-type", b"text/plain"], + ], + } + ) + + await send( + { + "type": "http.response.body", + "body": b"Hello, world!", + } + ) + def server_request_hook(span: Span, scope: Scope): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_request_hook", "some-value" + ) + def client_request_hook(span: Span, scope: Scope, message: dict[str, Any]): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_client_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_client_request_hook", "some-value" + ) - def client_response_hook(span: Span, scope: Scope, message: dict[str, Any]): + + def client_response_hook( + span: Span, scope: Scope, message: dict[str, Any] + ): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_response_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_response_hook", "some-value" + ) + - OpenTelemetryMiddleware(application, server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook) + OpenTelemetryMiddleware( + application, + server_request_hook=server_request_hook, + client_request_hook=client_request_hook, + client_response_hook=client_response_hook, + ) Capture HTTP request and response headers ***************************************** diff --git a/instrumentation/opentelemetry-instrumentation-asyncclick/src/opentelemetry/instrumentation/asyncclick/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncclick/src/opentelemetry/instrumentation/asyncclick/__init__.py index 61ccbf433c..f7c781c080 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncclick/src/opentelemetry/instrumentation/asyncclick/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncclick/src/opentelemetry/instrumentation/asyncclick/__init__.py @@ -21,9 +21,11 @@ AsyncClickInstrumentor().instrument() + @asyncclick.command() async def hello(): - asyncclick.echo(f'Hello world!') + asyncclick.echo(f"Hello world!") + if __name__ == "__main__": asyncio.run(hello()) diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py index 840fa2b4c2..49ea73f6ad 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py @@ -25,13 +25,15 @@ # You can optionally pass a custom TracerProvider to AsyncPGInstrumentor.instrument() AsyncPGInstrumentor().instrument() + async def main(): - conn = await asyncpg.connect(user='user', password='password') + conn = await asyncpg.connect(user="user", password="password") await conn.fetch('''SELECT 42;''') await conn.close() + asyncio.run(main()) API diff --git a/instrumentation/opentelemetry-instrumentation-click/src/opentelemetry/instrumentation/click/__init__.py b/instrumentation/opentelemetry-instrumentation-click/src/opentelemetry/instrumentation/click/__init__.py index 13387f2d1c..dbeb8f0414 100644 --- a/instrumentation/opentelemetry-instrumentation-click/src/opentelemetry/instrumentation/click/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-click/src/opentelemetry/instrumentation/click/__init__.py @@ -18,9 +18,11 @@ ClickInstrumentor().instrument() + @click.command() def hello(): - click.echo(f'Hello world!') + click.echo(f"Hello world!") + if __name__ == "__main__": hello() diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index f99c16029b..aa61c0b12a 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -54,11 +54,13 @@ app = falcon.App() + class HelloWorldResource(object): def on_get(self, req, resp): - resp.text = 'Hello World' + resp.text = "Hello World" + - app.add_route('/hello', HelloWorldResource()) + app.add_route("/hello", HelloWorldResource()) Request and Response hooks @@ -71,13 +73,18 @@ def on_get(self, req, resp): from opentelemetry.instrumentation.falcon import FalconInstrumentor + def request_hook(span, req): pass + def response_hook(span, req, resp): pass - FalconInstrumentor().instrument(request_hook=request_hook, response_hook=response_hook) + + FalconInstrumentor().instrument( + request_hook=request_hook, response_hook=response_hook + ) Capture HTTP request and response headers ***************************************** 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 e9e93c07eb..2b96c3b620 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py @@ -12,10 +12,12 @@ app = fastapi.FastAPI() + @app.get("/foobar") async def foobar(): return {"message": "hello world"} + FastAPIInstrumentor.instrument_app(app) Configuration @@ -39,7 +41,9 @@ async def foobar(): .. code-block:: python - FastAPIInstrumentor.instrument_app(app, excluded_urls="client/.*/info,healthcheck") + FastAPIInstrumentor.instrument_app( + app, excluded_urls="client/.*/info,healthcheck" + ) Request/Response hooks ********************** @@ -57,19 +61,33 @@ async def foobar(): from opentelemetry.trace import Span from starlette.types import Message, Scope + def server_request_hook(span: Span, scope: Scope): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_request_hook", "some-value" + ) + def client_request_hook(span: Span, scope: Scope, message: Message): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_client_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_client_request_hook", "some-value" + ) + def client_response_hook(span: Span, scope: Scope, message: Message): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_response_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_response_hook", "some-value" + ) + - FastAPIInstrumentor().instrument(server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook) + FastAPIInstrumentor().instrument( + server_request_hook=server_request_hook, + client_request_hook=client_request_hook, + client_response_hook=client_response_hook, + ) Capture HTTP request and response headers ***************************************** diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py index 9819c16022..1e96202319 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -25,10 +25,12 @@ FlaskInstrumentor().instrument_app(app) + @app.route("/") def hello(): return "Hello!" + if __name__ == "__main__": app.run(debug=True) @@ -53,7 +55,9 @@ def hello(): .. code-block:: python - FlaskInstrumentor().instrument_app(app, excluded_urls="client/.*/info,healthcheck") + FlaskInstrumentor().instrument_app( + app, excluded_urls="client/.*/info,healthcheck" + ) Request/Response hooks ********************** @@ -76,15 +80,24 @@ def hello(): from opentelemetry.instrumentation.flask import FlaskInstrumentor + def request_hook(span: Span, environ: WSGIEnvironment): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_request_hook", "some-value" + ) + def response_hook(span: Span, status: str, response_headers: List): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_response_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_response_hook", "some-value" + ) + - FlaskInstrumentor().instrument(request_hook=request_hook, response_hook=response_hook) + FlaskInstrumentor().instrument( + request_hook=request_hook, response_hook=response_hook + ) Flask Request object reference: https://flask.palletsprojects.com/en/2.1.x/api/#flask.Request diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py index 3b0ef08703..0f75e8e948 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/__init__.py @@ -35,9 +35,9 @@ grpc_client_instrumentor = GrpcInstrumentorClient() grpc_client_instrumentor.instrument() + def run(): with grpc.insecure_channel("localhost:50051") as channel: - stub = helloworld_pb2_grpc.GreeterStub(channel) response = stub.SayHello(helloworld_pb2.HelloRequest(name="YOU")) @@ -78,9 +78,12 @@ def run(): grpc_server_instrumentor = GrpcInstrumentorServer() grpc_server_instrumentor.instrument() + class Greeter(helloworld_pb2_grpc.GreeterServicer): def SayHello(self, request, context): - return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name) + return helloworld_pb2.HelloReply( + message="Hello, %s!" % request.name + ) def serve(): @@ -104,8 +107,9 @@ def serve(): from opentelemetry.instrumentation.grpc import server_interceptor - server = grpc.server(futures.ThreadPoolExecutor(), - interceptors = [server_interceptor()]) + server = grpc.server( + futures.ThreadPoolExecutor(), interceptors=[server_interceptor()] + ) Usage Aio Client ---------------- @@ -137,11 +141,13 @@ def serve(): grpc_client_instrumentor = GrpcAioInstrumentorClient() grpc_client_instrumentor.instrument() + async def run(): async with grpc.aio.insecure_channel("localhost:50051") as channel: - stub = helloworld_pb2_grpc.GreeterStub(channel) - response = await stub.SayHello(helloworld_pb2.HelloRequest(name="YOU")) + response = await stub.SayHello( + helloworld_pb2.HelloRequest(name="YOU") + ) print("Greeter client received: " + response.message) @@ -190,9 +196,12 @@ async def run(): grpc_server_instrumentor = GrpcAioInstrumentorServer() grpc_server_instrumentor.instrument() + class Greeter(helloworld_pb2_grpc.GreeterServicer): async def SayHello(self, request, context): - return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name) + return helloworld_pb2.HelloReply( + message="Hello, %s!" % request.name + ) async def serve(): @@ -216,7 +225,7 @@ async def serve(): from opentelemetry.instrumentation.grpc import aio_server_interceptor - server = grpc.aio.server(interceptors = [aio_server_interceptor()]) + server = grpc.aio.server(interceptors=[aio_server_interceptor()]) Filters ------- 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 a18be5b607..75b6660a42 100644 --- a/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-httpx/src/opentelemetry/instrumentation/httpx/__init__.py @@ -22,10 +22,12 @@ with httpx.Client() as client: response = client.get(url) + async def get(url): async with httpx.AsyncClient() as client: response = await client.get(url) + asyncio.run(get(url)) When instrumenting ``httpx2`` clients, use ``HTTPX2ClientInstrumentor``: @@ -42,10 +44,12 @@ async def get(url): with httpx2.Client() as client: response = client.get(url) + async def get(url): async with httpx2.AsyncClient() as client: response = await client.get(url) + asyncio.run(get(url)) Instrumenting single clients @@ -67,11 +71,13 @@ async def get(url): HTTPXClientInstrumentor.instrument_client(client) response = client.get(url) + async def get(url): async with httpx.AsyncClient() as client: HTTPXClientInstrumentor.instrument_client(client) response = await client.get(url) + asyncio.run(get(url)) For ``httpx2`` clients, use ``HTTPX2ClientInstrumentor.instrument_client``: @@ -130,10 +136,12 @@ async def get(url): transport = httpx.AsyncHTTPTransport() telemetry_transport = AsyncOpenTelemetryTransport(transport) + async def get(url): async with httpx.AsyncClient(transport=telemetry_transport) as client: response = await client.get(url) + asyncio.run(get(url)) For ``httpx2`` transports, use ``SyncOpenTelemetryTransportHttpx2`` and @@ -142,7 +150,9 @@ async def get(url): .. code-block:: python import httpx2 - from opentelemetry.instrumentation.httpx import SyncOpenTelemetryTransportHttpx2 + from opentelemetry.instrumentation.httpx import ( + SyncOpenTelemetryTransportHttpx2, + ) transport = httpx2.HTTPTransport() telemetry_transport = SyncOpenTelemetryTransportHttpx2(transport) @@ -167,29 +177,34 @@ async def get(url): from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor + def request_hook(span, request): # method, url, headers, stream, extensions = request pass + def response_hook(span, request, response): # method, url, headers, stream, extensions = request # status_code, headers, stream, extensions = response pass + async def async_request_hook(span, request): # method, url, headers, stream, extensions = request pass + async def async_response_hook(span, request, response): # method, url, headers, stream, extensions = request # status_code, headers, stream, extensions = response pass + HTTPXClientInstrumentor().instrument( request_hook=request_hook, response_hook=response_hook, async_request_hook=async_request_hook, - async_response_hook=async_response_hook + async_response_hook=async_response_hook, ) @@ -199,38 +214,44 @@ async def async_response_hook(span, request, response): .. code-block:: python import httpx - from opentelemetry.instrumentation.httpx import SyncOpenTelemetryTransport, AsyncOpenTelemetryTransport + from opentelemetry.instrumentation.httpx import ( + SyncOpenTelemetryTransport, + AsyncOpenTelemetryTransport, + ) + def request_hook(span, request): # method, url, headers, stream, extensions = request pass + def response_hook(span, request, response): # method, url, headers, stream, extensions = request # status_code, headers, stream, extensions = response pass + async def async_request_hook(span, request): # method, url, headers, stream, extensions = request pass + async def async_response_hook(span, request, response): # method, url, headers, stream, extensions = request # status_code, headers, stream, extensions = response pass + transport = httpx.HTTPTransport() telemetry_transport = SyncOpenTelemetryTransport( - transport, - request_hook=request_hook, - response_hook=response_hook + transport, request_hook=request_hook, response_hook=response_hook ) async_transport = httpx.AsyncHTTPTransport() async_telemetry_transport = AsyncOpenTelemetryTransport( async_transport, request_hook=async_request_hook, - response_hook=async_response_hook + response_hook=async_response_hook, ) diff --git a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py index 93087e9867..89ba37d495 100644 --- a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py @@ -20,7 +20,7 @@ LoggingInstrumentor().instrument(inject_trace_context=True) - logging.warning('OTel test') + logging.warning("OTel test") Alternatively, set ``set_logging_format=True`` (or the environment variable ``OTEL_PYTHON_LOG_CORRELATION=true``) to inject those same attributes and @@ -34,7 +34,7 @@ LoggingInstrumentor().instrument(set_logging_format=True) - logging.warning('OTel test') + logging.warning("OTel test") When running the above example you will see the following output: diff --git a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py index 434e88f12c..e76d99a0f4 100644 --- a/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pika/src/opentelemetry/instrumentation/pika/__init__.py @@ -21,10 +21,14 @@ PikaInstrumentor().instrument() - connection = pika.BlockingConnection(pika.URLParameters('amqp://localhost')) + connection = pika.BlockingConnection( + pika.URLParameters("amqp://localhost") + ) channel = connection.channel() - channel.queue_declare(queue='hello') - channel.basic_publish(exchange='', routing_key='hello', body=b'Hello World!') + channel.queue_declare(queue="hello") + channel.basic_publish( + exchange="", routing_key="hello", body=b"Hello World!" + ) * PikaInstrumentor also supports instrumentation of a single channel @@ -33,14 +37,18 @@ import pika from opentelemetry.instrumentation.pika import PikaInstrumentor - connection = pika.BlockingConnection(pika.URLParameters('amqp://localhost')) + connection = pika.BlockingConnection( + pika.URLParameters("amqp://localhost") + ) channel = connection.channel() - channel.queue_declare(queue='hello') + channel.queue_declare(queue="hello") pika_instrumentation = PikaInstrumentor() pika_instrumentation.instrument_channel(channel=channel) - channel.basic_publish(exchange='', routing_key='hello', body=b'Hello World!') + channel.basic_publish( + exchange="", routing_key="hello", body=b"Hello World!" + ) pika_instrumentation.uninstrument_channel(channel=channel) @@ -52,15 +60,21 @@ from opentelemetry.instrumentation.pika import PikaInstrumentor from opentelemetry.trace import get_tracer_provider - connection = pika.BlockingConnection(pika.URLParameters('amqp://localhost')) + connection = pika.BlockingConnection( + pika.URLParameters("amqp://localhost") + ) channel = connection.channel() tracer_provider = get_tracer_provider() - channel.queue_declare(queue='hello') + channel.queue_declare(queue="hello") - PikaInstrumentor.instrument_channel(channel, tracer_provider=tracer_provider) + PikaInstrumentor.instrument_channel( + channel, tracer_provider=tracer_provider + ) - channel.basic_publish(exchange='', routing_key='hello', body=b'Hello World!') + channel.basic_publish( + exchange="", routing_key="hello", body=b"Hello World!" + ) PikaInstrumentor.uninstrument_channel(channel) @@ -76,19 +90,28 @@ from opentelemetry.trace import Span from pika import BasicProperties + def publish_hook(span: Span, body: bytes, properties: BasicProperties): span.set_attribute("messaging.payload", body.decode()) + def consume_hook(span: Span, body: bytes, properties: BasicProperties): span.set_attribute("messaging.id", properties.message_id) - connection = pika.BlockingConnection(pika.URLParameters('amqp://localhost')) + + connection = pika.BlockingConnection( + pika.URLParameters("amqp://localhost") + ) channel = connection.channel() - channel.queue_declare(queue='hello') + channel.queue_declare(queue="hello") - PikaInstrumentor.instrument_channel(channel, publish_hook=publish_hook, consume_hook=consume_hook) + PikaInstrumentor.instrument_channel( + channel, publish_hook=publish_hook, consume_hook=consume_hook + ) - channel.basic_publish(exchange='', routing_key='hello', body=b'Hello World!') + channel.basic_publish( + exchange="", routing_key="hello", body=b"Hello World!" + ) PikaInstrumentor.uninstrument_channel(channel) 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 5d6bd93305..a543b77f56 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py @@ -18,7 +18,7 @@ # Call instrument() to wrap all database connections PsycopgInstrumentor().instrument() - cnx = psycopg.connect(database='Database') + cnx = psycopg.connect(database="Database") cursor = cnx.cursor() cursor.execute("CREATE TABLE IF NOT EXISTS test (testField INTEGER)") @@ -32,7 +32,7 @@ from opentelemetry.instrumentation.psycopg import PsycopgInstrumentor # Alternatively, use instrument_connection for an individual connection - cnx = psycopg.connect(database='Database') + cnx = psycopg.connect(database="Database") instrumented_cnx = PsycopgInstrumentor().instrument_connection(cnx) cursor = instrumented_cnx.cursor() cursor.execute("CREATE TABLE IF NOT EXISTS test (testField INTEGER)") 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 b7bf2c9601..97a273b2a2 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/src/opentelemetry/instrumentation/psycopg2/__init__.py @@ -18,7 +18,7 @@ # Call instrument() to wrap all database connections Psycopg2Instrumentor().instrument() - cnx = psycopg2.connect(database='Database') + cnx = psycopg2.connect(database="Database") cursor = cnx.cursor() cursor.execute("CREATE TABLE IF NOT EXISTS test (testField INTEGER)") @@ -32,7 +32,7 @@ from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor # Alternatively, use instrument_connection for an individual connection - cnx = psycopg2.connect(database='Database') + cnx = psycopg2.connect(database="Database") instrumented_cnx = Psycopg2Instrumentor().instrument_connection(cnx) cursor = instrumented_cnx.cursor() cursor.execute("CREATE TABLE IF NOT EXISTS test (testField INTEGER)") diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py index c433c88e73..3d4b88c9ba 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/src/opentelemetry/instrumentation/pymemcache/__init__.py @@ -18,8 +18,9 @@ PymemcacheInstrumentor().instrument() from pymemcache.client.base import Client - client = Client(('localhost', 11211)) - client.set('some_key', 'some_value') + + client = Client(("localhost", 11211)) + client.set("some_key", "some_value") API --- diff --git a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/__init__.py b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/__init__.py index ab96132a62..8990741640 100644 --- a/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-remoulade/src/opentelemetry/instrumentation/remoulade/__init__.py @@ -24,10 +24,12 @@ broker = RabbitmqBroker() remoulade.set_broker(broker) + @remoulade.actor def multiply(x, y): return x * y + broker.declare_actor(multiply) multiply.send(43, 51) 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 afe264bcd2..8ce5cd225b 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py @@ -12,12 +12,12 @@ from starlette.responses import PlainTextResponse from starlette.routing import Route + def home(request): return PlainTextResponse("hi") - app = applications.Starlette( - routes=[Route("/foobar", home)] - ) + + app = applications.Starlette(routes=[Route("/foobar", home)]) StarletteInstrumentor.instrument_app(app) Configuration @@ -55,19 +55,37 @@ def home(request): from opentelemetry.trace import Span from typing import Any + def server_request_hook(span: Span, scope: dict[str, Any]): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_request_hook", "some-value" + ) + - def client_request_hook(span: Span, scope: dict[str, Any], message: dict[str, Any]): + def client_request_hook( + span: Span, scope: dict[str, Any], message: dict[str, Any] + ): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_client_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_client_request_hook", "some-value" + ) + - def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, Any]): + def client_response_hook( + span: Span, scope: dict[str, Any], message: dict[str, Any] + ): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_response_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_response_hook", "some-value" + ) + - StarletteInstrumentor().instrument(server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook) + StarletteInstrumentor().instrument( + server_request_hook=server_request_hook, + client_request_hook=client_request_hook, + client_response_hook=client_response_hook, + ) Capture HTTP request and response headers ***************************************** diff --git a/instrumentation/opentelemetry-instrumentation-structlog/src/opentelemetry/instrumentation/structlog/__init__.py b/instrumentation/opentelemetry-instrumentation-structlog/src/opentelemetry/instrumentation/structlog/__init__.py index c280938ec3..f962a8ecd7 100644 --- a/instrumentation/opentelemetry-instrumentation-structlog/src/opentelemetry/instrumentation/structlog/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-structlog/src/opentelemetry/instrumentation/structlog/__init__.py @@ -288,7 +288,9 @@ class StructlogInstrumentor(BaseInstrumentor): chain, enabling automatic emission of structlog events as OpenTelemetry logs. Example: - >>> from opentelemetry.instrumentation.structlog import StructlogInstrumentor + >>> from opentelemetry.instrumentation.structlog import ( + ... StructlogInstrumentor, + ... ) >>> import structlog >>> StructlogInstrumentor().instrument() >>> logger = structlog.get_logger() diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py index ad41912144..8b841cb910 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -17,10 +17,12 @@ # apply tornado instrumentation TornadoInstrumentor().instrument() + class Handler(tornado.web.RequestHandler): def get(self): self.set_status(200) + app = tornado.web.Application([(r"/", Handler)]) app.listen(8080) tornado.ioloop.IOLoop.current().start() @@ -65,24 +67,28 @@ def get(self): from opentelemetry.instrumentation.tornado import TornadoInstrumentor + # will be called for each incoming request to Tornado # web server. `handler` is an instance of # `tornado.web.RequestHandler`. def server_request_hook(span, handler): pass + # will be called just before sending out a request with # `tornado.httpclient.AsyncHTTPClient.fetch`. # `request` is an instance of ``tornado.httpclient.HTTPRequest`. def client_request_hook(span, request): pass + # will be called after a outgoing request made with # `tornado.httpclient.AsyncHTTPClient.fetch` finishes. # `response`` is an instance of ``Future[tornado.httpclient.HTTPResponse]`. def client_response_hook(span, future): pass + # apply tornado instrumentation with hooks TornadoInstrumentor().instrument( server_request_hook=server_request_hook, 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 6c68d00d32..198a9ab136 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py @@ -16,7 +16,7 @@ # URLLibInstrumentor().instrument() URLLibInstrumentor().instrument() - req = request.Request('https://postman-echo.com/post', method="POST") + req = request.Request("https://postman-echo.com/post", method="POST") r = request.urlopen(req) Configuration diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py index 4728c09ba6..677a25ff47 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py @@ -12,9 +12,11 @@ import urllib3 from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor + def strip_query_params(url: str) -> str: return url.split("?")[0] + URLLib3Instrumentor().instrument( # Remove all query params from the URL attribute on the span. url_filter=strip_query_params, 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 47ec15da57..2a546f04f9 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -15,10 +15,12 @@ app = Flask(__name__) app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app) + @app.route("/") def hello(): return "Hello!" + if __name__ == "__main__": app.run(debug=True) @@ -34,7 +36,7 @@ def hello(): from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware from django.core.wsgi import get_wsgi_application - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings") application = get_wsgi_application() application = OpenTelemetryMiddleware(application) @@ -48,11 +50,10 @@ def hello(): from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware from cheroot import wsgi - urls = ('/', 'index') + urls = ("/", "index") class index: - def GET(self): return "Hello, world!" @@ -90,19 +91,37 @@ def GET(self): from wsgiref.types import WSGIEnvironment, StartResponse from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware + def app(environ: WSGIEnvironment, start_response: StartResponse): - start_response("200 OK", [("Content-Type", "text/plain"), ("Content-Length", "13")]) + start_response( + "200 OK", + [("Content-Type", "text/plain"), ("Content-Length", "13")], + ) return [b"Hello, World!"] + def request_hook(span: Span, environ: WSGIEnvironment): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_request_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_request_hook", "some-value" + ) + - def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_headers: list[tuple[str, str]]): + def response_hook( + span: Span, + environ: WSGIEnvironment, + status: str, + response_headers: list[tuple[str, str]], + ): if span and span.is_recording(): - span.set_attribute("custom_user_attribute_from_response_hook", "some-value") + span.set_attribute( + "custom_user_attribute_from_response_hook", "some-value" + ) + - OpenTelemetryMiddleware(app, request_hook=request_hook, response_hook=response_hook) + OpenTelemetryMiddleware( + app, request_hook=request_hook, response_hook=response_hook + ) Capture HTTP request and response headers ***************************************** diff --git a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/__init__.py b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/__init__.py index 5967290fbd..18a422ca47 100644 --- a/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/__init__.py +++ b/opamp/opentelemetry-opamp-client/src/opentelemetry/_opamp/__init__.py @@ -47,7 +47,10 @@ class MyCallbacks(OpAMPCallbacks): def on_message(self, agent, client, message): if message.remote_config is None: return - for config_filename, config in message.remote_config.config.config_map.items(): + for ( + config_filename, + config, + ) in message.remote_config.config.config_map.items(): print("do something") diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_labeler/__init__.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_labeler/__init__.py index 91db080ea4..5b06554b9b 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_labeler/__init__.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/_labeler/__init__.py @@ -38,6 +38,7 @@ description="Duration of HTTP server requests.", ) + def record_request(user_id: str, duration_s: float) -> None: labeler = get_labeler() labeler.add("user_id", user_id) diff --git a/pyproject.toml b/pyproject.toml index 3ebf07594c..77c230d259 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -157,6 +157,7 @@ target-version = "py310" line-length = 79 extend-exclude = ["_template", "*_pb2*.py*"] output-format = "concise" +extension = { added = "markdown", changed = "markdown", deprecated = "markdown", removed = "markdown", fixed = "markdown" } [tool.ruff.lint] # https://docs.astral.sh/ruff/linter/#rule-selection @@ -191,6 +192,9 @@ known-third-party = [ "opencensus", ] +[tool.ruff.format] +docstring-code-format = true + # https://github.com/microsoft/pyright/blob/main/docs/configuration.md#type-check-rule-overrides [tool.pyright] diff --git a/util/opentelemetry-util-genai/AGENTS.md b/util/opentelemetry-util-genai/AGENTS.md index 77cc5cf20b..979d4a7b35 100644 --- a/util/opentelemetry-util-genai/AGENTS.md +++ b/util/opentelemetry-util-genai/AGENTS.md @@ -25,7 +25,9 @@ applicable ones. Every new operation type must follow this pattern: ```python -invocation = handler.start_inference(provider, request_model, server_address=..., server_port=...) +invocation = handler.start_inference( + provider, request_model, server_address=..., server_port=... +) invocation.temperature = ... try: response = client.call(...)