Skip to content

Commit 406707b

Browse files
authored
Add type checker (#3116)
1 parent 8406e2e commit 406707b

File tree

5 files changed

+82
-11
lines changed

5 files changed

+82
-11
lines changed

.github/workflows/misc_0.yml

+18
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,21 @@ jobs:
152152

153153
- name: Run tests
154154
run: tox -e ruff
155+
156+
typecheck:
157+
name: typecheck
158+
runs-on: ubuntu-latest
159+
steps:
160+
- name: Checkout repo @ SHA - ${{ github.sha }}
161+
uses: actions/checkout@v4
162+
163+
- name: Set up Python 3.11
164+
uses: actions/setup-python@v5
165+
with:
166+
python-version: "3.11"
167+
168+
- name: Install tox
169+
run: pip install tox
170+
171+
- name: Run tests
172+
run: tox -e typecheck

dev-requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pylint==3.0.2
22
httpretty==1.1.4
3-
mypy==0.931
3+
pyright==v1.1.390
44
sphinx==7.1.2
55
sphinx-rtd-theme==2.0.0rc4
66
sphinx-autodoc-typehints==1.25.2

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

+36-9
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,29 @@
3535
run method or the executor's worker thread."
3636
"""
3737

38+
from __future__ import annotations
39+
3840
import threading
3941
from concurrent import futures
40-
from typing import Collection
42+
from typing import TYPE_CHECKING, Any, Callable, Collection
4143

42-
from wrapt import wrap_function_wrapper
44+
from wrapt import (
45+
wrap_function_wrapper, # type: ignore[reportUnknownVariableType]
46+
)
4347

4448
from opentelemetry import context
4549
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
4650
from opentelemetry.instrumentation.threading.package import _instruments
4751
from opentelemetry.instrumentation.utils import unwrap
4852

53+
if TYPE_CHECKING:
54+
from typing import Protocol, TypeVar
55+
56+
R = TypeVar("R")
57+
58+
class HasOtelContext(Protocol):
59+
_otel_context: context.Context
60+
4961

5062
class ThreadingInstrumentor(BaseInstrumentor):
5163
__WRAPPER_START_METHOD = "start"
@@ -55,12 +67,12 @@ class ThreadingInstrumentor(BaseInstrumentor):
5567
def instrumentation_dependencies(self) -> Collection[str]:
5668
return _instruments
5769

58-
def _instrument(self, **kwargs):
70+
def _instrument(self, **kwargs: Any):
5971
self._instrument_thread()
6072
self._instrument_timer()
6173
self._instrument_thread_pool()
6274

63-
def _uninstrument(self, **kwargs):
75+
def _uninstrument(self, **kwargs: Any):
6476
self._uninstrument_thread()
6577
self._uninstrument_timer()
6678
self._uninstrument_thread_pool()
@@ -117,12 +129,22 @@ def _uninstrument_thread_pool():
117129
)
118130

119131
@staticmethod
120-
def __wrap_threading_start(call_wrapped, instance, args, kwargs):
132+
def __wrap_threading_start(
133+
call_wrapped: Callable[[], None],
134+
instance: HasOtelContext,
135+
args: ...,
136+
kwargs: ...,
137+
) -> None:
121138
instance._otel_context = context.get_current()
122139
return call_wrapped(*args, **kwargs)
123140

124141
@staticmethod
125-
def __wrap_threading_run(call_wrapped, instance, args, kwargs):
142+
def __wrap_threading_run(
143+
call_wrapped: Callable[..., R],
144+
instance: HasOtelContext,
145+
args: tuple[Any, ...],
146+
kwargs: dict[str, Any],
147+
) -> R:
126148
token = None
127149
try:
128150
token = context.attach(instance._otel_context)
@@ -131,12 +153,17 @@ def __wrap_threading_run(call_wrapped, instance, args, kwargs):
131153
context.detach(token)
132154

133155
@staticmethod
134-
def __wrap_thread_pool_submit(call_wrapped, instance, args, kwargs):
156+
def __wrap_thread_pool_submit(
157+
call_wrapped: Callable[..., R],
158+
instance: futures.ThreadPoolExecutor,
159+
args: tuple[Callable[..., Any], ...],
160+
kwargs: dict[str, Any],
161+
) -> R:
135162
# obtain the original function and wrapped kwargs
136163
original_func = args[0]
137164
otel_context = context.get_current()
138165

139-
def wrapped_func(*func_args, **func_kwargs):
166+
def wrapped_func(*func_args: Any, **func_kwargs: Any) -> R:
140167
token = None
141168
try:
142169
token = context.attach(otel_context)
@@ -145,5 +172,5 @@ def wrapped_func(*func_args, **func_kwargs):
145172
context.detach(token)
146173

147174
# replace the original function with the wrapped function
148-
new_args = (wrapped_func,) + args[1:]
175+
new_args: tuple[Callable[..., Any], ...] = (wrapped_func,) + args[1:]
149176
return call_wrapped(*new_args, **kwargs)

pyproject.toml

+16
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,19 @@ known-third-party = [
3939
"opencensus",
4040
]
4141

42+
# https://github.com/microsoft/pyright/blob/main/docs/configuration.md#type-check-rule-overrides
43+
[tool.pyright]
44+
typeCheckingMode = "strict"
45+
reportUnnecessaryTypeIgnoreComment = true
46+
reportMissingTypeStubs = false
47+
pythonVersion = "3.8"
48+
reportPrivateUsage = false # Ignore private attributes added by instrumentation packages.
49+
# Add progressively instrumentation packages here.
50+
include = [
51+
"instrumentation/opentelemetry-instrumentation-threading/**/*.py"
52+
]
53+
# We should also add type hints to the test suite - It helps on finding bugs.
54+
# We are excluding for now because it's easier, and more important to add to the instrumentation packages.
55+
exclude = [
56+
"instrumentation/opentelemetry-instrumentation-threading/tests/**",
57+
]

tox.ini

+11-1
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ envlist =
404404
generate-workflows
405405
shellcheck
406406
ruff
407+
typecheck
407408

408409
[testenv]
409410
test_deps =
@@ -677,7 +678,6 @@ deps =
677678
util-http: -r {toxinidir}/util/opentelemetry-util-http/test-requirements.txt
678679
util-http: {toxinidir}/util/opentelemetry-util-http
679680
; FIXME: add coverage testing
680-
; FIXME: add mypy testing
681681
allowlist_externals =
682682
sh
683683

@@ -986,3 +986,13 @@ deps =
986986
pre-commit
987987
commands =
988988
pre-commit run --color=always --all-files {posargs}
989+
990+
[testenv:typecheck]
991+
deps =
992+
-c {toxinidir}/dev-requirements.txt
993+
pyright
994+
{[testenv]test_deps}
995+
{toxinidir}/opentelemetry-instrumentation
996+
{toxinidir}/util/opentelemetry-util-http
997+
commands =
998+
pyright

0 commit comments

Comments
 (0)