Skip to content

Commit 2522ace

Browse files
committed
This PR is based on open-telemetry#3995.
Part of open-telemetry#1608 Addressing running mypy on opentelemetry-sdk iteratively so we don't have to make one big change addressing all mypy issues at once.
1 parent a67f5f8 commit 2522ace

File tree

3 files changed

+68
-53
lines changed

3 files changed

+68
-53
lines changed

opentelemetry-api/src/opentelemetry/attributes/__init__.py

+30-29
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
# type: ignore
1514

1615
import logging
1716
import threading
@@ -59,7 +58,7 @@ def _clean_attribute(
5958
cleaned_seq = []
6059

6160
for element in value:
62-
element = _clean_attribute_value(element, max_len)
61+
element = _clean_attribute_value(element, max_len) # type: ignore
6362
if element is None:
6463
cleaned_seq.append(element)
6564
continue
@@ -96,7 +95,7 @@ def _clean_attribute(
9695
cleaned_seq.append(element)
9796

9897
# Freeze mutable sequences defensively
99-
return tuple(cleaned_seq)
98+
return tuple(cleaned_seq) # type: ignore
10099

101100
_logger.warning(
102101
"Invalid type %s for attribute '%s' value. Expected one of %s or a "
@@ -126,7 +125,7 @@ def _clean_attribute_value(
126125
return value
127126

128127

129-
class BoundedAttributes(MutableMapping):
128+
class BoundedAttributes(MutableMapping): # type: ignore
130129
"""An ordered dict with a fixed max capacity.
131130
132131
Oldest elements are dropped when the dict is full and a new element is
@@ -149,53 +148,55 @@ def __init__(
149148
self.dropped = 0
150149
self.max_value_len = max_value_len
151150
# OrderedDict is not used until the maxlen is reached for efficiency.
152-
self._dict = {} # type: dict | OrderedDict
153-
self._lock = threading.RLock() # type: threading.RLock
151+
# self._dict type: dict | OrderedDict
152+
153+
self._dict = {} # type: ignore
154+
self._lock = threading.RLock()
154155
if attributes:
155156
for key, value in attributes.items():
156157
self[key] = value
157158
self._immutable = immutable
158159

159-
def __repr__(self):
160-
return f"{dict(self._dict)}"
160+
def __repr__(self) -> str:
161+
return f"{dict(self._dict)}" # type: ignore
161162

162-
def __getitem__(self, key):
163-
return self._dict[key]
163+
def __getitem__(self, key): # type: ignore
164+
return self._dict[key] # type: ignore
164165

165-
def __setitem__(self, key, value):
166-
if getattr(self, "_immutable", False):
166+
def __setitem__(self, key, value): # type: ignore
167+
if getattr(self, "_immutable", False): # type: ignore
167168
raise TypeError
168169
with self._lock:
169170
if self.maxlen is not None and self.maxlen == 0:
170171
self.dropped += 1
171172
return
172173

173-
value = _clean_attribute(key, value, self.max_value_len)
174-
if value is not None:
175-
if key in self._dict:
176-
del self._dict[key]
174+
value = _clean_attribute(key, value, self.max_value_len) # type: ignore
175+
if value is not None: # type: ignore
176+
if key in self._dict: # type: ignore
177+
del self._dict[key] # type: ignore
177178
elif (
178-
self.maxlen is not None and len(self._dict) == self.maxlen
179+
self.maxlen is not None and len(self._dict) == self.maxlen # type: ignore
179180
):
180-
if not isinstance(self._dict, OrderedDict):
181-
self._dict = OrderedDict(self._dict)
181+
if not isinstance(self._dict, OrderedDict): # type: ignore
182+
self._dict = OrderedDict(self._dict) # type: ignore
182183
self._dict.popitem(last=False)
183184
self.dropped += 1
184185

185-
self._dict[key] = value
186+
self._dict[key] = value # type: ignore
186187

187-
def __delitem__(self, key):
188-
if getattr(self, "_immutable", False):
188+
def __delitem__(self, key): # type: ignore
189+
if getattr(self, "_immutable", False): # type: ignore
189190
raise TypeError
190191
with self._lock:
191-
del self._dict[key]
192+
del self._dict[key] # type: ignore
192193

193-
def __iter__(self):
194+
def __iter__(self): # type: ignore
194195
with self._lock:
195-
return iter(self._dict.copy())
196+
return iter(self._dict.copy()) # type: ignore
196197

197-
def __len__(self):
198-
return len(self._dict)
198+
def __len__(self): # type: ignore
199+
return len(self._dict) # type: ignore
199200

200-
def copy(self):
201-
return self._dict.copy()
201+
def copy(self): # type: ignore
202+
return self._dict.copy() # type: ignore

opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py

+35-23
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
import typing
6464
from json import dumps
6565
from os import environ
66+
from types import ModuleType
67+
from typing import List, Optional
6668
from urllib import parse
6769

6870
from opentelemetry.attributes import BoundedAttributes
@@ -75,10 +77,14 @@
7577
from opentelemetry.util._importlib_metadata import entry_points, version
7678
from opentelemetry.util.types import AttributeValue
7779

80+
psutil: Optional[ModuleType] = None
81+
7882
try:
79-
import psutil
83+
import psutil as pustil_module
84+
85+
pustil = pustil_module
8086
except ImportError:
81-
psutil = None
87+
pass
8288

8389
LabelValue = AttributeValue
8490
Attributes = typing.Mapping[str, LabelValue]
@@ -141,12 +147,15 @@
141147
TELEMETRY_AUTO_VERSION = ResourceAttributes.TELEMETRY_AUTO_VERSION
142148
TELEMETRY_SDK_LANGUAGE = ResourceAttributes.TELEMETRY_SDK_LANGUAGE
143149

144-
_OPENTELEMETRY_SDK_VERSION = version("opentelemetry-sdk")
150+
_OPENTELEMETRY_SDK_VERSION: str = version("opentelemetry-sdk")
145151

146152

147153
class Resource:
148154
"""A Resource is an immutable representation of the entity producing telemetry as Attributes."""
149155

156+
_attributes: BoundedAttributes
157+
_schema_url: str
158+
150159
def __init__(
151160
self, attributes: Attributes, schema_url: typing.Optional[str] = None
152161
):
@@ -173,7 +182,7 @@ def create(
173182
if not attributes:
174183
attributes = {}
175184

176-
resource_detectors = []
185+
resource_detectors: List[ResourceDetector] = []
177186

178187
resource = _DEFAULT_RESOURCE
179188

@@ -182,20 +191,21 @@ def create(
182191
).split(",")
183192

184193
if "otel" not in otel_experimental_resource_detectors:
194+
185195
otel_experimental_resource_detectors.append("otel")
186196

197+
resource_detector: str
187198
for resource_detector in otel_experimental_resource_detectors:
188199
resource_detectors.append(
189200
next(
190201
iter(
191202
entry_points(
192203
group="opentelemetry_resource_detector",
193204
name=resource_detector.strip(),
194-
)
205+
) # type: ignore
195206
)
196-
).load()()
207+
)
197208
)
198-
199209
resource = get_aggregated_resources(
200210
resource_detectors, _DEFAULT_RESOURCE
201211
).merge(Resource(attributes, schema_url))
@@ -206,7 +216,7 @@ def create(
206216
PROCESS_EXECUTABLE_NAME, None
207217
)
208218
if process_executable_name:
209-
default_service_name += ":" + process_executable_name
219+
default_service_name += ":" + str(process_executable_name)
210220
resource = resource.merge(
211221
Resource({SERVICE_NAME: default_service_name}, schema_url)
212222
)
@@ -218,6 +228,8 @@ def get_empty() -> "Resource":
218228

219229
@property
220230
def attributes(self) -> Attributes:
231+
if self._attributes is None:
232+
raise ValueError("Attributes are not set.")
221233
return self._attributes
222234

223235
@property
@@ -241,7 +253,7 @@ def merge(self, other: "Resource") -> "Resource":
241253
Returns:
242254
The newly-created Resource.
243255
"""
244-
merged_attributes = self.attributes.copy()
256+
merged_attributes = dict(self.attributes)
245257
merged_attributes.update(other.attributes)
246258

247259
if self.schema_url == "":
@@ -257,7 +269,6 @@ def merge(self, other: "Resource") -> "Resource":
257269
other.schema_url,
258270
)
259271
return self
260-
261272
return Resource(merged_attributes, schema_url)
262273

263274
def __eq__(self, other: object) -> bool:
@@ -268,15 +279,15 @@ def __eq__(self, other: object) -> bool:
268279
and self._schema_url == other._schema_url
269280
)
270281

271-
def __hash__(self):
272-
return hash(
273-
f"{dumps(self._attributes.copy(), sort_keys=True)}|{self._schema_url}"
274-
)
282+
def __hash__(self) -> int:
283+
attributes_json = dumps(self._attributes.copy(), sort_keys=True) # type: ignore
284+
return hash(f"{attributes_json}|{self._schema_url}")
275285

276-
def to_json(self, indent=4) -> str:
286+
def to_json(self, indent: int = 4) -> str:
287+
attributes = dict(self._attributes) # type: ignore
277288
return dumps(
278289
{
279-
"attributes": dict(self._attributes),
290+
"attributes": attributes, # type: ignore
280291
"schema_url": self._schema_url,
281292
},
282293
indent=indent,
@@ -294,7 +305,7 @@ def to_json(self, indent=4) -> str:
294305

295306

296307
class ResourceDetector(abc.ABC):
297-
def __init__(self, raise_on_error=False):
308+
def __init__(self, raise_on_error: bool = False) -> None:
298309
self.raise_on_error = raise_on_error
299310

300311
@abc.abstractmethod
@@ -343,7 +354,7 @@ def detect(self) -> "Resource":
343354
),
344355
)
345356
)
346-
_process_pid = os.getpid()
357+
_process_pid = str(os.getpid())
347358
_process_executable_name = sys.executable
348359
_process_executable_path = os.path.dirname(_process_executable_name)
349360
_process_command = sys.argv[0]
@@ -358,23 +369,24 @@ def detect(self) -> "Resource":
358369
PROCESS_EXECUTABLE_PATH: _process_executable_path,
359370
PROCESS_COMMAND: _process_command,
360371
PROCESS_COMMAND_LINE: _process_command_line,
361-
PROCESS_COMMAND_ARGS: _process_command_args,
372+
PROCESS_COMMAND_ARGS: "".join(_process_command_args),
362373
}
363374
if hasattr(os, "getppid"):
364375
# pypy3 does not have getppid()
365-
resource_info[PROCESS_PARENT_PID] = os.getppid()
376+
resource_info[PROCESS_PARENT_PID] = str(os.getppid())
366377

367378
if psutil is not None:
368-
process = psutil.Process()
369-
resource_info[PROCESS_OWNER] = process.username()
379+
process: pustil_module.Process = psutil.Process()
380+
username = process.username()
381+
resource_info[PROCESS_OWNER] = username
370382

371383
return Resource(resource_info)
372384

373385

374386
def get_aggregated_resources(
375387
detectors: typing.List["ResourceDetector"],
376388
initial_resource: typing.Optional[Resource] = None,
377-
timeout=5,
389+
timeout: int = 5,
378390
) -> "Resource":
379391
"""Retrieves resources from detectors in the order that they were passed
380392

tox.ini

+3-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ setenv =
125125
; i.e: CONTRIB_REPO_SHA=dde62cebffe519c35875af6d06fae053b3be65ec tox -e <env to test>
126126
CONTRIB_REPO_SHA={env:CONTRIB_REPO_SHA:main}
127127
CONTRIB_REPO=git+https://github.com/open-telemetry/opentelemetry-python-contrib.git@{env:CONTRIB_REPO_SHA}
128-
mypy: MYPYPATH={toxinidir}/opentelemetry-api/src/:{toxinidir}/tests/opentelemetry-test-utils/src/
128+
mypy: MYPYPATH={toxinidir}/opentelemetry-api/src/:{toxinidir}/opentelemetry-semantic-conventions/src/:{toxinidir}/opentelemetry-sdk/src/:{toxinidir}/tests/opentelemetry-test-utils/src/
129129

130130
commands_pre =
131131

@@ -331,7 +331,9 @@ commands =
331331

332332
coverage: {toxinidir}/scripts/coverage.sh
333333

334+
mypy: mypy --version
334335
mypy: mypy --install-types --non-interactive --namespace-packages --explicit-package-bases opentelemetry-api/src/opentelemetry/
336+
mypy: mypy --install-types --non-interactive --namespace-packages --explicit-package-bases opentelemetry-sdk/src/opentelemetry/sdk/resources
335337
mypy: mypy --install-types --non-interactive --namespace-packages --explicit-package-bases opentelemetry-semantic-conventions/src/opentelemetry/semconv/
336338

337339
; For test code, we don't want to enforce the full mypy strictness

0 commit comments

Comments
 (0)