Skip to content

Commit b63f643

Browse files
DylanRussellemdnetoaabmass
authored
Add exporter/opentelemetry-exporter-otlp-proto-grpc to the pyright include list. Fix all lint errors in that package. (#4566)
* Add `exporter/opentelemetry-exporter-otlp-proto-grpc` to the pyright include list. Fix all lint errors in that package. * Exclude exporter tests from pyright and update tox.ini * Fix docs presubmit * Switch pyright: to type: * Bump pyright to 1.1.400 * Fix typecheck and lint * Fix broken test * Address comment * Fix bug... --------- Co-authored-by: Emídio Neto <[email protected]> Co-authored-by: Aaron Abbott <[email protected]>
1 parent 6f97ed8 commit b63f643

File tree

11 files changed

+170
-107
lines changed

11 files changed

+170
-107
lines changed

dev-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pylint==3.3.4
22
httpretty==1.1.4
3-
pyright==1.1.396
3+
pyright==1.1.405
44
sphinx==7.1.2
55
sphinx-rtd-theme==2.0.0rc4
66
sphinx-autodoc-typehints==1.25.2

docs/conf.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@
115115
"py:class",
116116
"opentelemetry.trace._LinkBase",
117117
),
118+
(
119+
"py:class",
120+
"opentelemetry.proto.collector.trace.v1.trace_service_pb2_grpc.TraceServiceStub",
121+
),
122+
(
123+
"py:class",
124+
"opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc.MetricsServiceStub",
125+
),
126+
(
127+
"py:class",
128+
"opentelemetry.proto.collector.logs.v1.logs_service_pb2_grpc.LogsServiceStub",
129+
),
118130
(
119131
"py:class",
120132
"opentelemetry.exporter.otlp.proto.grpc.exporter.OTLPExporterMixin",

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# limitations under the License.
1313

1414
from os import environ
15-
from typing import Dict, Optional, Sequence, Tuple, Union
15+
from typing import Dict, Literal, Optional, Sequence, Tuple, Union
1616
from typing import Sequence as TypingSequence
1717

1818
from grpc import ChannelCredentials, Compression
@@ -29,7 +29,6 @@
2929
LogsServiceStub,
3030
)
3131
from opentelemetry.sdk._logs import LogData
32-
from opentelemetry.sdk._logs import LogRecord as SDKLogRecord
3332
from opentelemetry.sdk._logs.export import LogExporter, LogExportResult
3433
from opentelemetry.sdk.environment_variables import (
3534
_OTEL_PYTHON_EXPORTER_OTLP_GRPC_LOGS_CREDENTIAL_PROVIDER,
@@ -46,11 +45,13 @@
4645

4746
class OTLPLogExporter(
4847
LogExporter,
49-
OTLPExporterMixin[SDKLogRecord, ExportLogsServiceRequest, LogExportResult],
48+
OTLPExporterMixin[
49+
Sequence[LogData],
50+
ExportLogsServiceRequest,
51+
LogExportResult,
52+
LogsServiceStub,
53+
],
5054
):
51-
_result = LogExportResult
52-
_stub = LogsServiceStub
53-
5455
def __init__(
5556
self,
5657
endpoint: Optional[str] = None,
@@ -61,12 +62,11 @@ def __init__(
6162
] = None,
6263
timeout: Optional[float] = None,
6364
compression: Optional[Compression] = None,
64-
channel_options: Optional[TypingSequence[Tuple[str, str]]] = None,
65+
channel_options: Optional[Tuple[Tuple[str, str]]] = None,
6566
):
66-
if insecure is None:
67-
insecure = environ.get(OTEL_EXPORTER_OTLP_LOGS_INSECURE)
68-
if insecure is not None:
69-
insecure = insecure.lower() == "true"
67+
insecure_logs = environ.get(OTEL_EXPORTER_OTLP_LOGS_INSECURE)
68+
if insecure is None and insecure_logs is not None:
69+
insecure = insecure_logs.lower() == "true"
7070

7171
if (
7272
not insecure
@@ -90,29 +90,30 @@ def __init__(
9090
if compression is None
9191
else compression
9292
)
93-
endpoint = endpoint or environ.get(OTEL_EXPORTER_OTLP_LOGS_ENDPOINT)
94-
95-
headers = headers or environ.get(OTEL_EXPORTER_OTLP_LOGS_HEADERS)
9693

97-
super().__init__(
98-
**{
99-
"endpoint": endpoint,
100-
"insecure": insecure,
101-
"credentials": credentials,
102-
"headers": headers,
103-
"timeout": timeout or environ_timeout,
104-
"compression": compression,
105-
"channel_options": channel_options,
106-
}
94+
OTLPExporterMixin.__init__(
95+
self,
96+
endpoint=endpoint or environ.get(OTEL_EXPORTER_OTLP_LOGS_ENDPOINT),
97+
insecure=insecure,
98+
credentials=credentials,
99+
headers=headers or environ.get(OTEL_EXPORTER_OTLP_LOGS_HEADERS),
100+
timeout=timeout or environ_timeout,
101+
compression=compression,
102+
stub=LogsServiceStub,
103+
result=LogExportResult,
104+
channel_options=channel_options,
107105
)
108106

109107
def _translate_data(
110108
self, data: Sequence[LogData]
111109
) -> ExportLogsServiceRequest:
112110
return encode_logs(data)
113111

114-
def export(self, batch: Sequence[LogData]) -> LogExportResult:
115-
return self._export(batch)
112+
def export( # type: ignore [reportIncompatibleMethodOverride]
113+
self,
114+
batch: Sequence[LogData],
115+
) -> Literal[LogExportResult.SUCCESS, LogExportResult.FAILURE]:
116+
return OTLPExporterMixin._export(self, batch)
116117

117118
def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
118119
OTLPExporterMixin.shutdown(self, timeout_millis=timeout_millis)

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py

Lines changed: 78 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
Dict,
2828
Generic,
2929
List,
30+
Literal,
31+
NewType,
3032
Optional,
3133
Tuple,
34+
Type,
3235
TypeVar,
3336
Union,
3437
)
@@ -53,12 +56,32 @@
5356
from opentelemetry.exporter.otlp.proto.grpc import (
5457
_OTLP_GRPC_CHANNEL_OPTIONS,
5558
)
59+
from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import (
60+
ExportLogsServiceRequest,
61+
)
62+
from opentelemetry.proto.collector.logs.v1.logs_service_pb2_grpc import (
63+
LogsServiceStub,
64+
)
65+
from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (
66+
ExportMetricsServiceRequest,
67+
)
68+
from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc import (
69+
MetricsServiceStub,
70+
)
71+
from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (
72+
ExportTraceServiceRequest,
73+
)
74+
from opentelemetry.proto.collector.trace.v1.trace_service_pb2_grpc import (
75+
TraceServiceStub,
76+
)
5677
from opentelemetry.proto.common.v1.common_pb2 import ( # noqa: F401
5778
AnyValue,
5879
ArrayValue,
5980
KeyValue,
6081
)
6182
from opentelemetry.proto.resource.v1.resource_pb2 import Resource # noqa: F401
83+
from opentelemetry.sdk._logs import LogData
84+
from opentelemetry.sdk._logs.export import LogExportResult
6285
from opentelemetry.sdk._shared_internal import DuplicateFilter
6386
from opentelemetry.sdk.environment_variables import (
6487
_OTEL_PYTHON_EXPORTER_OTLP_GRPC_CREDENTIAL_PROVIDER,
@@ -71,9 +94,10 @@
7194
OTEL_EXPORTER_OTLP_INSECURE,
7295
OTEL_EXPORTER_OTLP_TIMEOUT,
7396
)
74-
from opentelemetry.sdk.metrics.export import MetricsData
97+
from opentelemetry.sdk.metrics.export import MetricExportResult, MetricsData
7598
from opentelemetry.sdk.resources import Resource as SDKResource
7699
from opentelemetry.sdk.trace import ReadableSpan
100+
from opentelemetry.sdk.trace.export import SpanExportResult
77101
from opentelemetry.util._importlib_metadata import entry_points
78102
from opentelemetry.util.re import parse_env_headers
79103

@@ -92,11 +116,29 @@
92116
logger = getLogger(__name__)
93117
# This prevents logs generated when a log fails to be written to generate another log which fails to be written etc. etc.
94118
logger.addFilter(DuplicateFilter())
95-
SDKDataT = TypeVar("SDKDataT")
119+
SDKDataT = TypeVar(
120+
"SDKDataT",
121+
TypingSequence[LogData],
122+
MetricsData,
123+
TypingSequence[ReadableSpan],
124+
)
96125
ResourceDataT = TypeVar("ResourceDataT")
97126
TypingResourceT = TypeVar("TypingResourceT")
98-
ExportServiceRequestT = TypeVar("ExportServiceRequestT")
99-
ExportResultT = TypeVar("ExportResultT")
127+
ExportServiceRequestT = TypeVar(
128+
"ExportServiceRequestT",
129+
ExportTraceServiceRequest,
130+
ExportMetricsServiceRequest,
131+
ExportLogsServiceRequest,
132+
)
133+
ExportResultT = TypeVar(
134+
"ExportResultT",
135+
LogExportResult,
136+
MetricExportResult,
137+
SpanExportResult,
138+
)
139+
ExportStubT = TypeVar(
140+
"ExportStubT", TraceServiceStub, MetricsServiceStub, LogsServiceStub
141+
)
100142

101143
_ENVIRON_TO_COMPRESSION = {
102144
None: None,
@@ -119,7 +161,10 @@ def environ_to_compression(environ_key: str) -> Optional[Compression]:
119161
if environ_key in environ
120162
else None
121163
)
122-
if environ_value not in _ENVIRON_TO_COMPRESSION:
164+
if (
165+
environ_value not in _ENVIRON_TO_COMPRESSION
166+
and environ_value is not None
167+
):
123168
raise InvalidCompressionValueException(environ_key, environ_value)
124169
return _ENVIRON_TO_COMPRESSION[environ_value]
125170

@@ -151,7 +196,7 @@ def _load_credentials(
151196
certificate_file: Optional[str],
152197
client_key_file: Optional[str],
153198
client_certificate_file: Optional[str],
154-
) -> Optional[ChannelCredentials]:
199+
) -> ChannelCredentials:
155200
root_certificates = (
156201
_read_file(certificate_file) if certificate_file else None
157202
)
@@ -214,7 +259,7 @@ def _get_credentials(
214259

215260
# pylint: disable=no-member
216261
class OTLPExporterMixin(
217-
ABC, Generic[SDKDataT, ExportServiceRequestT, ExportResultT]
262+
ABC, Generic[SDKDataT, ExportServiceRequestT, ExportResultT, ExportStubT]
218263
):
219264
"""OTLP span exporter
220265
@@ -230,6 +275,8 @@ class OTLPExporterMixin(
230275

231276
def __init__(
232277
self,
278+
stub: ExportStubT,
279+
result: ExportResultT,
233280
endpoint: Optional[str] = None,
234281
insecure: Optional[bool] = None,
235282
credentials: Optional[ChannelCredentials] = None,
@@ -238,10 +285,11 @@ def __init__(
238285
] = None,
239286
timeout: Optional[float] = None,
240287
compression: Optional[Compression] = None,
241-
channel_options: Optional[TypingSequence[Tuple[str, str]]] = None,
288+
channel_options: Optional[Tuple[Tuple[str, str]]] = None,
242289
):
243290
super().__init__()
244-
291+
self._result = result
292+
self._stub = stub
245293
self._endpoint = endpoint or environ.get(
246294
OTEL_EXPORTER_OTLP_ENDPOINT, "http://localhost:4317"
247295
)
@@ -250,15 +298,12 @@ def __init__(
250298

251299
if parsed_url.scheme == "https":
252300
insecure = False
301+
insecure_exporter = environ.get(OTEL_EXPORTER_OTLP_INSECURE)
253302
if insecure is None:
254-
insecure = environ.get(OTEL_EXPORTER_OTLP_INSECURE)
255-
if insecure is not None:
256-
insecure = insecure.lower() == "true"
303+
if insecure_exporter is not None:
304+
insecure = insecure_exporter.lower() == "true"
257305
else:
258-
if parsed_url.scheme == "http":
259-
insecure = True
260-
else:
261-
insecure = False
306+
insecure = parsed_url.scheme == "http"
262307

263308
if parsed_url.netloc:
264309
self._endpoint = parsed_url.netloc
@@ -277,12 +322,12 @@ def __init__(
277322
overridden_options = {
278323
opt_name for (opt_name, _) in channel_options
279324
}
280-
default_options = [
325+
default_options = tuple(
281326
(opt_name, opt_value)
282327
for opt_name, opt_value in _OTLP_GRPC_CHANNEL_OPTIONS
283328
if opt_name not in overridden_options
284-
]
285-
self._channel_options = tuple(default_options) + channel_options
329+
)
330+
self._channel_options = default_options + channel_options
286331
else:
287332
self._channel_options = tuple(_OTLP_GRPC_CHANNEL_OPTIONS)
288333

@@ -317,24 +362,25 @@ def __init__(
317362
compression=compression,
318363
options=self._channel_options,
319364
)
320-
self._client = self._stub(self._channel)
365+
self._client = self._stub(self._channel) # type: ignore [reportCallIssue]
321366

322367
self._shutdown_in_progress = threading.Event()
323368
self._shutdown = False
324369

325370
@abstractmethod
326371
def _translate_data(
327-
self, data: TypingSequence[SDKDataT]
372+
self,
373+
data: SDKDataT,
328374
) -> ExportServiceRequestT:
329375
pass
330376

331377
def _export(
332378
self,
333-
data: Union[TypingSequence[ReadableSpan], MetricsData],
379+
data: SDKDataT,
334380
) -> ExportResultT:
335381
if self._shutdown:
336382
logger.warning("Exporter already shutdown, ignoring batch")
337-
return self._result.FAILURE
383+
return self._result.FAILURE # type: ignore [reportReturnType]
338384

339385
# FIXME remove this check if the export type for traces
340386
# gets updated to a class that represents the proto
@@ -347,10 +393,10 @@ def _export(
347393
metadata=self._headers,
348394
timeout=deadline_sec - time(),
349395
)
350-
return self._result.SUCCESS
396+
return self._result.SUCCESS # type: ignore [reportReturnType]
351397
except RpcError as error:
352-
retry_info_bin = dict(error.trailing_metadata()).get(
353-
"google.rpc.retryinfo-bin"
398+
retry_info_bin = dict(error.trailing_metadata()).get( # type: ignore [reportAttributeAccessIssue]
399+
"google.rpc.retryinfo-bin" # type: ignore [reportArgumentType]
354400
)
355401
# multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
356402
backoff_seconds = 2**retry_num * random.uniform(0.8, 1.2)
@@ -362,7 +408,7 @@ def _export(
362408
+ retry_info.retry_delay.nanos / 1.0e9
363409
)
364410
if (
365-
error.code() not in _RETRYABLE_ERROR_CODES
411+
error.code() not in _RETRYABLE_ERROR_CODES # type: ignore [reportAttributeAccessIssue]
366412
or retry_num + 1 == _MAX_RETRYS
367413
or backoff_seconds > (deadline_sec - time())
368414
or self._shutdown
@@ -371,13 +417,13 @@ def _export(
371417
"Failed to export %s to %s, error code: %s",
372418
self._exporting,
373419
self._endpoint,
374-
error.code(),
375-
exc_info=error.code() == StatusCode.UNKNOWN,
420+
error.code(), # type: ignore [reportAttributeAccessIssue]
421+
exc_info=error.code() == StatusCode.UNKNOWN, # type: ignore [reportAttributeAccessIssue]
376422
)
377-
return self._result.FAILURE
423+
return self._result.FAILURE # type: ignore [reportReturnType]
378424
logger.warning(
379425
"Transient error %s encountered while exporting %s to %s, retrying in %.2fs.",
380-
error.code(),
426+
error.code(), # type: ignore [reportAttributeAccessIssue]
381427
self._exporting,
382428
self._endpoint,
383429
backoff_seconds,
@@ -387,7 +433,7 @@ def _export(
387433
logger.warning("Shutdown in progress, aborting retry.")
388434
break
389435
# Not possible to reach here but the linter is complaining.
390-
return self._result.FAILURE
436+
return self._result.FAILURE # type: ignore [reportReturnType]
391437

392438
def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
393439
if self._shutdown:

0 commit comments

Comments
 (0)