diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a4de30776..ed7726960e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#3100](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3100)) - Add support to database stability opt-in in `_semconv` utilities and add tests ([#3111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3111)) +- `opentelemetry-instrumentation-urllib3` Add `py.typed` file to enable PEP 561 + ([#3130](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3130)) - `opentelemetry-instrumentation-system-metrics` Add `py.typed` file to enable PEP 561 ([#3132](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3132)) - `opentelemetry-opentelemetry-sqlite3` Add `py.typed` file to enable PEP 561 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 2d1cf4c1b0..8abe397ea2 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py @@ -83,15 +83,19 @@ def response_hook( --- """ +from __future__ import annotations + import collections.abc import io import typing from dataclasses import dataclass from timeit import default_timer -from typing import Collection +from typing import Any, Callable, Collection, Mapping, Optional import urllib3.connectionpool import wrapt +from urllib3.connectionpool import HTTPConnectionPool +from urllib3.response import HTTPResponse from opentelemetry.instrumentation._semconv import ( _client_duration_attrs_new, @@ -151,32 +155,16 @@ class RequestInfo: # The type annotations here come from ``HTTPConnectionPool.urlopen()``. method: str url: str - headers: typing.Optional[typing.Mapping[str, str]] - body: typing.Union[ - bytes, typing.IO[typing.Any], typing.Iterable[bytes], str, None - ] - - -_UrlFilterT = typing.Optional[typing.Callable[[str], str]] -_RequestHookT = typing.Optional[ - typing.Callable[ - [ - Span, - urllib3.connectionpool.HTTPConnectionPool, - RequestInfo, - ], - None, - ] + headers: Mapping[str, str] | None + body: bytes | typing.IO[typing.Any] | typing.Iterable[bytes] | str | None + + +_UrlFilterT = Optional[Callable[[str], str]] +_RequestHookT = Optional[ + Callable[[Span, HTTPConnectionPool, RequestInfo], None] ] -_ResponseHookT = typing.Optional[ - typing.Callable[ - [ - Span, - urllib3.connectionpool.HTTPConnectionPool, - urllib3.response.HTTPResponse, - ], - None, - ] +_ResponseHookT = Optional[ + Callable[[Span, HTTPConnectionPool, HTTPResponse], None] ] _URL_OPEN_ARG_TO_INDEX_MAPPING = { @@ -190,7 +178,7 @@ class URLLib3Instrumentor(BaseInstrumentor): def instrumentation_dependencies(self) -> Collection[str]: return _instruments - def _instrument(self, **kwargs): + def _instrument(self, **kwargs: Any): """Instruments the urllib3 module Args: @@ -286,7 +274,7 @@ def _instrument(self, **kwargs): sem_conv_opt_in_mode=sem_conv_opt_in_mode, ) - def _uninstrument(self, **kwargs): + def _uninstrument(self, **kwargs: Any): _uninstrument() @@ -308,10 +296,15 @@ def _instrument( request_hook: _RequestHookT = None, response_hook: _ResponseHookT = None, url_filter: _UrlFilterT = None, - excluded_urls: ExcludeList = None, + excluded_urls: ExcludeList | None = None, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ): - def instrumented_urlopen(wrapped, instance, args, kwargs): + def instrumented_urlopen( + wrapped: Callable[..., HTTPResponse], + instance: HTTPConnectionPool, + args: list[Any], + kwargs: dict[str, Any], + ): if not is_http_instrumentation_enabled(): return wrapped(*args, **kwargs) @@ -397,7 +390,9 @@ def instrumented_urlopen(wrapped, instance, args, kwargs): ) -def _get_url_open_arg(name: str, args: typing.List, kwargs: typing.Mapping): +def _get_url_open_arg( + name: str, args: list[Any], kwargs: typing.Mapping[str, Any] +): arg_idx = _URL_OPEN_ARG_TO_INDEX_MAPPING.get(name) if arg_idx is not None: try: @@ -408,9 +403,9 @@ def _get_url_open_arg(name: str, args: typing.List, kwargs: typing.Mapping): def _get_url( - instance: urllib3.connectionpool.HTTPConnectionPool, - args: typing.List, - kwargs: typing.Mapping, + instance: HTTPConnectionPool, + args: list[Any], + kwargs: typing.Mapping[str, Any], url_filter: _UrlFilterT, ) -> str: url_or_path = _get_url_open_arg("url", args, kwargs) @@ -427,7 +422,7 @@ def _get_url( return url -def _get_body_size(body: object) -> typing.Optional[int]: +def _get_body_size(body: object) -> int | None: if body is None: return 0 if isinstance(body, collections.abc.Sized): @@ -437,7 +432,7 @@ def _get_body_size(body: object) -> typing.Optional[int]: return None -def _should_append_port(scheme: str, port: typing.Optional[int]) -> bool: +def _should_append_port(scheme: str, port: int | None) -> bool: if not port: return False if scheme == "http" and port == 80: @@ -447,7 +442,7 @@ def _should_append_port(scheme: str, port: typing.Optional[int]) -> bool: return True -def _prepare_headers(urlopen_kwargs: typing.Dict) -> typing.Dict: +def _prepare_headers(urlopen_kwargs: dict[str, Any]) -> dict[str, Any]: headers = urlopen_kwargs.get("headers") # avoid modifying original headers on inject @@ -460,7 +455,7 @@ def _prepare_headers(urlopen_kwargs: typing.Dict) -> typing.Dict: def _set_status_code_attribute( span: Span, status_code: int, - metric_attributes: dict = None, + metric_attributes: dict[str, Any] | None = None, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ) -> None: status_code_str = str(status_code) @@ -483,9 +478,9 @@ def _set_status_code_attribute( def _set_metric_attributes( - metric_attributes: dict, - instance: urllib3.connectionpool.HTTPConnectionPool, - response: urllib3.response.HTTPResponse, + metric_attributes: dict[str, Any], + instance: HTTPConnectionPool, + response: HTTPResponse, method: str, sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, ) -> None: @@ -515,9 +510,9 @@ def _set_metric_attributes( def _filter_attributes_semconv( - metric_attributes, + metric_attributes: dict[str, object], sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT, -): +) -> tuple[dict[str, object] | None, dict[str, object] | None]: duration_attrs_old = None duration_attrs_new = None if _report_old(sem_conv_opt_in_mode): @@ -539,7 +534,7 @@ def _filter_attributes_semconv( def _record_metrics( - metric_attributes: dict, + metric_attributes: dict[str, object], duration_histogram_old: Histogram, duration_histogram_new: Histogram, request_size_histogram_old: Histogram, diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/py.typed b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/py.typed new file mode 100644 index 0000000000..e69de29bb2 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 f5dacf0fff..83db1c5c7a 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -19,7 +19,7 @@ from re import IGNORECASE as RE_IGNORECASE from re import compile as re_compile from re import search -from typing import Callable, Iterable, Optional +from typing import Callable, Iterable, Optional, overload from urllib.parse import urlparse, urlunparse from opentelemetry.semconv.trace import SpanAttributes @@ -193,6 +193,14 @@ def normalise_response_header_name(header: str) -> str: return f"http.response.header.{key}" +@overload +def sanitize_method(method: str) -> str: ... + + +@overload +def sanitize_method(method: None) -> None: ... + + def sanitize_method(method: Optional[str]) -> Optional[str]: if method is None: return None