Skip to content

Commit d865e0d

Browse files
committed
Support PEP 561 to opentelemetry-instrumentation-urllib3
1 parent 54cbf59 commit d865e0d

File tree

4 files changed

+51
-48
lines changed

4 files changed

+51
-48
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
([#3100](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3100))
1818
- Add support to database stability opt-in in `_semconv` utilities and add tests
1919
([#3111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3111))
20+
- `opentelemetry-instrumentation-urllib3` Add `py.typed` file to enable PEP 561
21+
([#3130](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3130))
2022

2123
### Fixed
2224

instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,19 @@ def response_hook(
8383
---
8484
"""
8585

86+
from __future__ import annotations
87+
8688
import collections.abc
8789
import io
8890
import typing
8991
from dataclasses import dataclass
9092
from timeit import default_timer
91-
from typing import Collection
93+
from typing import Any, Callable, Collection, Mapping, Optional
9294

9395
import urllib3.connectionpool
9496
import wrapt
97+
from urllib3.connectionpool import HTTPConnectionPool
98+
from urllib3.response import HTTPResponse
9599

96100
from opentelemetry.instrumentation._semconv import (
97101
_client_duration_attrs_new,
@@ -142,41 +146,23 @@ def response_hook(
142146
_excluded_urls_from_env = get_excluded_urls("URLLIB3")
143147

144148

145-
@dataclass
149+
@dataclass(slots=True)
146150
class RequestInfo:
147151
"""Arguments that were passed to the ``urlopen()`` call."""
148152

149-
__slots__ = ("method", "url", "headers", "body")
150-
151153
# The type annotations here come from ``HTTPConnectionPool.urlopen()``.
152154
method: str
153155
url: str
154-
headers: typing.Optional[typing.Mapping[str, str]]
155-
body: typing.Union[
156-
bytes, typing.IO[typing.Any], typing.Iterable[bytes], str, None
157-
]
158-
159-
160-
_UrlFilterT = typing.Optional[typing.Callable[[str], str]]
161-
_RequestHookT = typing.Optional[
162-
typing.Callable[
163-
[
164-
Span,
165-
urllib3.connectionpool.HTTPConnectionPool,
166-
RequestInfo,
167-
],
168-
None,
169-
]
156+
headers: Mapping[str, str] | None
157+
body: bytes | typing.IO[typing.Any] | typing.Iterable[bytes] | str | None
158+
159+
160+
_UrlFilterT = Optional[Callable[[str], str]]
161+
_RequestHookT = Optional[
162+
Callable[[Span, HTTPConnectionPool, RequestInfo], None]
170163
]
171-
_ResponseHookT = typing.Optional[
172-
typing.Callable[
173-
[
174-
Span,
175-
urllib3.connectionpool.HTTPConnectionPool,
176-
urllib3.response.HTTPResponse,
177-
],
178-
None,
179-
]
164+
_ResponseHookT = Optional[
165+
Callable[[Span, HTTPConnectionPool, HTTPResponse], None]
180166
]
181167

182168
_URL_OPEN_ARG_TO_INDEX_MAPPING = {
@@ -190,7 +176,7 @@ class URLLib3Instrumentor(BaseInstrumentor):
190176
def instrumentation_dependencies(self) -> Collection[str]:
191177
return _instruments
192178

193-
def _instrument(self, **kwargs):
179+
def _instrument(self, **kwargs: Any):
194180
"""Instruments the urllib3 module
195181
196182
Args:
@@ -286,7 +272,7 @@ def _instrument(self, **kwargs):
286272
sem_conv_opt_in_mode=sem_conv_opt_in_mode,
287273
)
288274

289-
def _uninstrument(self, **kwargs):
275+
def _uninstrument(self, **kwargs: Any):
290276
_uninstrument()
291277

292278

@@ -308,10 +294,15 @@ def _instrument(
308294
request_hook: _RequestHookT = None,
309295
response_hook: _ResponseHookT = None,
310296
url_filter: _UrlFilterT = None,
311-
excluded_urls: ExcludeList = None,
297+
excluded_urls: ExcludeList | None = None,
312298
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
313299
):
314-
def instrumented_urlopen(wrapped, instance, args, kwargs):
300+
def instrumented_urlopen(
301+
wrapped: Callable[..., HTTPResponse],
302+
instance: HTTPConnectionPool,
303+
args: list[Any],
304+
kwargs: dict[str, Any],
305+
):
315306
if not is_http_instrumentation_enabled():
316307
return wrapped(*args, **kwargs)
317308

@@ -397,7 +388,9 @@ def instrumented_urlopen(wrapped, instance, args, kwargs):
397388
)
398389

399390

400-
def _get_url_open_arg(name: str, args: typing.List, kwargs: typing.Mapping):
391+
def _get_url_open_arg(
392+
name: str, args: list[Any], kwargs: typing.Mapping[str, Any]
393+
):
401394
arg_idx = _URL_OPEN_ARG_TO_INDEX_MAPPING.get(name)
402395
if arg_idx is not None:
403396
try:
@@ -408,9 +401,9 @@ def _get_url_open_arg(name: str, args: typing.List, kwargs: typing.Mapping):
408401

409402

410403
def _get_url(
411-
instance: urllib3.connectionpool.HTTPConnectionPool,
412-
args: typing.List,
413-
kwargs: typing.Mapping,
404+
instance: HTTPConnectionPool,
405+
args: list[Any],
406+
kwargs: typing.Mapping[str, Any],
414407
url_filter: _UrlFilterT,
415408
) -> str:
416409
url_or_path = _get_url_open_arg("url", args, kwargs)
@@ -427,7 +420,7 @@ def _get_url(
427420
return url
428421

429422

430-
def _get_body_size(body: object) -> typing.Optional[int]:
423+
def _get_body_size(body: object) -> int | None:
431424
if body is None:
432425
return 0
433426
if isinstance(body, collections.abc.Sized):
@@ -437,7 +430,7 @@ def _get_body_size(body: object) -> typing.Optional[int]:
437430
return None
438431

439432

440-
def _should_append_port(scheme: str, port: typing.Optional[int]) -> bool:
433+
def _should_append_port(scheme: str, port: int | None) -> bool:
441434
if not port:
442435
return False
443436
if scheme == "http" and port == 80:
@@ -447,7 +440,7 @@ def _should_append_port(scheme: str, port: typing.Optional[int]) -> bool:
447440
return True
448441

449442

450-
def _prepare_headers(urlopen_kwargs: typing.Dict) -> typing.Dict:
443+
def _prepare_headers(urlopen_kwargs: dict[str, Any]) -> dict[str, Any]:
451444
headers = urlopen_kwargs.get("headers")
452445

453446
# avoid modifying original headers on inject
@@ -460,7 +453,7 @@ def _prepare_headers(urlopen_kwargs: typing.Dict) -> typing.Dict:
460453
def _set_status_code_attribute(
461454
span: Span,
462455
status_code: int,
463-
metric_attributes: dict = None,
456+
metric_attributes: dict[str, Any] | None = None,
464457
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
465458
) -> None:
466459
status_code_str = str(status_code)
@@ -483,9 +476,9 @@ def _set_status_code_attribute(
483476

484477

485478
def _set_metric_attributes(
486-
metric_attributes: dict,
487-
instance: urllib3.connectionpool.HTTPConnectionPool,
488-
response: urllib3.response.HTTPResponse,
479+
metric_attributes: dict[str, Any],
480+
instance: HTTPConnectionPool,
481+
response: HTTPResponse,
489482
method: str,
490483
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
491484
) -> None:
@@ -515,9 +508,9 @@ def _set_metric_attributes(
515508

516509

517510
def _filter_attributes_semconv(
518-
metric_attributes,
511+
metric_attributes: dict[str, object],
519512
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
520-
):
513+
) -> tuple[dict[str, object] | None, dict[str, object] | None]:
521514
duration_attrs_old = None
522515
duration_attrs_new = None
523516
if _report_old(sem_conv_opt_in_mode):
@@ -539,7 +532,7 @@ def _filter_attributes_semconv(
539532

540533

541534
def _record_metrics(
542-
metric_attributes: dict,
535+
metric_attributes: dict[str, object],
543536
duration_histogram_old: Histogram,
544537
duration_histogram_new: Histogram,
545538
request_size_histogram_old: Histogram,

instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/py.typed

Whitespace-only changes.

util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from re import IGNORECASE as RE_IGNORECASE
2020
from re import compile as re_compile
2121
from re import search
22-
from typing import Callable, Iterable, Optional
22+
from typing import Callable, Iterable, Optional, overload
2323
from urllib.parse import urlparse, urlunparse
2424

2525
from opentelemetry.semconv.trace import SpanAttributes
@@ -193,6 +193,14 @@ def normalise_response_header_name(header: str) -> str:
193193
return f"http.response.header.{key}"
194194

195195

196+
@overload
197+
def sanitize_method(method: str) -> str: ...
198+
199+
200+
@overload
201+
def sanitize_method(method: None) -> None: ...
202+
203+
196204
def sanitize_method(method: Optional[str]) -> Optional[str]:
197205
if method is None:
198206
return None

0 commit comments

Comments
 (0)