Skip to content

Commit

Permalink
This PR is based on open-telemetry#3995.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Attila Sasvari authored and asasvari committed Jul 13, 2024
1 parent a67f5f8 commit a8bce5a
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 20 deletions.
53 changes: 33 additions & 20 deletions opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
import typing
from json import dumps
from os import environ
from types import ModuleType
from typing import Dict, List, Optional, Union, cast
from urllib import parse

from opentelemetry.attributes import BoundedAttributes
Expand All @@ -75,10 +77,14 @@
from opentelemetry.util._importlib_metadata import entry_points, version
from opentelemetry.util.types import AttributeValue

psutil: Optional[ModuleType] = None

try:
import psutil
import psutil as pustil_module

pustil = pustil_module
except ImportError:
psutil = None
pass

LabelValue = AttributeValue
Attributes = typing.Mapping[str, LabelValue]
Expand Down Expand Up @@ -147,6 +153,11 @@
class Resource:
"""A Resource is an immutable representation of the entity producing telemetry as Attributes."""

_attributes: Dict[
str, Union[str, int, float, bool]
] # Example: Adjust according to actual expected types
_schema_url: str

def __init__(
self, attributes: Attributes, schema_url: typing.Optional[str] = None
):
Expand All @@ -173,7 +184,7 @@ def create(
if not attributes:
attributes = {}

resource_detectors = []
resource_detectors: List[ResourceDetector] = []

resource = _DEFAULT_RESOURCE

Expand All @@ -182,6 +193,7 @@ def create(
).split(",")

if "otel" not in otel_experimental_resource_detectors:

otel_experimental_resource_detectors.append("otel")

for resource_detector in otel_experimental_resource_detectors:
Expand All @@ -193,9 +205,8 @@ def create(
name=resource_detector.strip(),
)
)
).load()()
)
)

resource = get_aggregated_resources(
resource_detectors, _DEFAULT_RESOURCE
).merge(Resource(attributes, schema_url))
Expand All @@ -206,7 +217,7 @@ def create(
PROCESS_EXECUTABLE_NAME, None
)
if process_executable_name:
default_service_name += ":" + process_executable_name
default_service_name += ":" + str(process_executable_name)
resource = resource.merge(
Resource({SERVICE_NAME: default_service_name}, schema_url)
)
Expand All @@ -218,6 +229,8 @@ def get_empty() -> "Resource":

@property
def attributes(self) -> Attributes:
if self._attributes is None:
raise ValueError("Attributes are not set.")
return self._attributes

@property
Expand All @@ -241,7 +254,7 @@ def merge(self, other: "Resource") -> "Resource":
Returns:
The newly-created Resource.
"""
merged_attributes = self.attributes.copy()
merged_attributes = dict(self.attributes)
merged_attributes.update(other.attributes)

if self.schema_url == "":
Expand All @@ -257,7 +270,6 @@ def merge(self, other: "Resource") -> "Resource":
other.schema_url,
)
return self

return Resource(merged_attributes, schema_url)

def __eq__(self, other: object) -> bool:
Expand All @@ -268,15 +280,15 @@ def __eq__(self, other: object) -> bool:
and self._schema_url == other._schema_url
)

def __hash__(self):
return hash(
f"{dumps(self._attributes.copy(), sort_keys=True)}|{self._schema_url}"
)
def __hash__(self) -> int:
attributes_json = dumps(self._attributes.copy(), sort_keys=True)
return hash(f"{attributes_json}|{self._schema_url}")

def to_json(self, indent=4) -> str:
def to_json(self, indent: int = 4) -> str:
attributes = dict(self._attributes)
return dumps(
{
"attributes": dict(self._attributes),
"attributes": attributes,
"schema_url": self._schema_url,
},
indent=indent,
Expand All @@ -294,7 +306,7 @@ def to_json(self, indent=4) -> str:


class ResourceDetector(abc.ABC):
def __init__(self, raise_on_error=False):
def __init__(self, raise_on_error: bool = False) -> None:
self.raise_on_error = raise_on_error

@abc.abstractmethod
Expand Down Expand Up @@ -343,7 +355,7 @@ def detect(self) -> "Resource":
),
)
)
_process_pid = os.getpid()
_process_pid = str(os.getpid())
_process_executable_name = sys.executable
_process_executable_path = os.path.dirname(_process_executable_name)
_process_command = sys.argv[0]
Expand All @@ -358,23 +370,24 @@ def detect(self) -> "Resource":
PROCESS_EXECUTABLE_PATH: _process_executable_path,
PROCESS_COMMAND: _process_command,
PROCESS_COMMAND_LINE: _process_command_line,
PROCESS_COMMAND_ARGS: _process_command_args,
PROCESS_COMMAND_ARGS: "".join(_process_command_args),
}
if hasattr(os, "getppid"):
# pypy3 does not have getppid()
resource_info[PROCESS_PARENT_PID] = os.getppid()
resource_info[PROCESS_PARENT_PID] = str(os.getppid())

if psutil is not None:
process = psutil.Process()
resource_info[PROCESS_OWNER] = process.username()
username = cast(str, process.username())
resource_info[PROCESS_OWNER] = username

return Resource(resource_info)


def get_aggregated_resources(
detectors: typing.List["ResourceDetector"],
initial_resource: typing.Optional[Resource] = None,
timeout=5,
timeout: int = 5,
) -> "Resource":
"""Retrieves resources from detectors in the order that they were passed
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ commands =
coverage: {toxinidir}/scripts/coverage.sh

mypy: mypy --install-types --non-interactive --namespace-packages --explicit-package-bases opentelemetry-api/src/opentelemetry/
mypy: mypy --install-types --non-interactive --namespace-packages --explicit-package-bases opentelemetry-sdk/src/opentelemetry/sdk/resources
mypy: mypy --install-types --non-interactive --namespace-packages --explicit-package-bases opentelemetry-semantic-conventions/src/opentelemetry/semconv/

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

0 comments on commit a8bce5a

Please sign in to comment.