6161import os
6262import sys
6363import typing
64+ from typing import Dict , Any , Union , Optional , Union , cast , List
6465from json import dumps
6566from os import environ
6667from urllib import parse
67-
68+ from types import ModuleType
6869from opentelemetry .attributes import BoundedAttributes
70+
71+
6972from opentelemetry .sdk .environment_variables import (
7073 OTEL_EXPERIMENTAL_RESOURCE_DETECTORS ,
7174 OTEL_RESOURCE_ATTRIBUTES ,
7578from opentelemetry .util ._importlib_metadata import entry_points , version
7679from opentelemetry .util .types import AttributeValue
7780
81+ psutil : Optional [ModuleType ] = None
82+
7883try :
79- import psutil
84+ import psutil as pustil_module
85+ pustil = pustil_module
8086except ImportError :
81- psutil = None
87+ pass
8288
8389LabelValue = AttributeValue
8490Attributes = typing .Mapping [str , LabelValue ]
146152
147153class Resource :
148154 """A Resource is an immutable representation of the entity producing telemetry as Attributes."""
155+ _attributes : Dict [str , Union [str , int , float , bool ]] # Example: Adjust according to actual expected types
156+ _schema_url : str
149157
150158 def __init__ (
151159 self , attributes : Attributes , schema_url : typing .Optional [str ] = None
@@ -173,7 +181,7 @@ def create(
173181 if not attributes :
174182 attributes = {}
175183
176- resource_detectors = [ ]
184+ resource_detectors : List [ ResourceDetector ]
177185
178186 resource = _DEFAULT_RESOURCE
179187
@@ -182,20 +190,20 @@ def create(
182190 ).split ("," )
183191
184192 if "otel" not in otel_experimental_resource_detectors :
193+
185194 otel_experimental_resource_detectors .append ("otel" )
186195
187196 for resource_detector in otel_experimental_resource_detectors :
188- resource_detectors .append (
197+ resource_detectors .append (
189198 next (
190- iter (
191- entry_points (
192- group = "opentelemetry_resource_detector" ,
193- name = resource_detector .strip (),
194- )
195- )
196- ).load ()()
199+ iter (
200+ entry_points (
201+ group = "opentelemetry_resource_detector" ,
202+ name = resource_detector .strip (),
203+ )
197204 )
198-
205+ )
206+ )
199207 resource = get_aggregated_resources (
200208 resource_detectors , _DEFAULT_RESOURCE
201209 ).merge (Resource (attributes , schema_url ))
@@ -206,7 +214,7 @@ def create(
206214 PROCESS_EXECUTABLE_NAME , None
207215 )
208216 if process_executable_name :
209- default_service_name += ":" + process_executable_name
217+ default_service_name += ":" + str ( process_executable_name )
210218 resource = resource .merge (
211219 Resource ({SERVICE_NAME : default_service_name }, schema_url )
212220 )
@@ -218,13 +226,14 @@ def get_empty() -> "Resource":
218226
219227 @property
220228 def attributes (self ) -> Attributes :
221- return self ._attributes
229+ if self ._attributes is None :
230+ raise ValueError ("Attributes are not set." )
231+ return self ._attributes
222232
223233 @property
224234 def schema_url (self ) -> str :
225235 return self ._schema_url
226-
227- def merge (self , other : "Resource" ) -> "Resource" :
236+ def merge (self , other : 'Resource' ) -> 'Resource' :
228237 """Merges this resource and an updating resource into a new `Resource`.
229238
230239 If a key exists on both the old and updating resource, the value of the
@@ -241,9 +250,9 @@ def merge(self, other: "Resource") -> "Resource":
241250 Returns:
242251 The newly-created Resource.
243252 """
244- merged_attributes = self .attributes . copy ( )
253+ merged_attributes = dict ( self .attributes )
245254 merged_attributes .update (other .attributes )
246-
255+
247256 if self .schema_url == "" :
248257 schema_url = other .schema_url
249258 elif other .schema_url == "" :
@@ -257,8 +266,8 @@ def merge(self, other: "Resource") -> "Resource":
257266 other .schema_url ,
258267 )
259268 return self
260-
261269 return Resource (merged_attributes , schema_url )
270+
262271
263272 def __eq__ (self , other : object ) -> bool :
264273 if not isinstance (other , Resource ):
@@ -268,21 +277,17 @@ def __eq__(self, other: object) -> bool:
268277 and self ._schema_url == other ._schema_url
269278 )
270279
271- def __hash__ (self ):
272- return hash (
273- f"{ dumps (self ._attributes .copy (), sort_keys = True )} |{ self ._schema_url } "
274- )
280+ def __hash__ (self ) -> int :
281+ attributes_json = dumps (self ._attributes .copy (), sort_keys = True )
282+ return hash (f"{ attributes_json } |{ self ._schema_url } " )
275283
276- def to_json (self , indent = 4 ) -> str :
277- return dumps (
278- {
279- "attributes" : dict ( self . _attributes ) ,
284+ def to_json (self , indent : int = 4 ) -> str :
285+ attributes = dict ( self . _attributes )
286+ return dumps ( {
287+ "attributes" : attributes ,
280288 "schema_url" : self ._schema_url ,
281- },
282- indent = indent ,
283- )
284-
285-
289+ }, indent = indent )
290+
286291_EMPTY_RESOURCE = Resource ({})
287292_DEFAULT_RESOURCE = Resource (
288293 {
@@ -294,7 +299,7 @@ def to_json(self, indent=4) -> str:
294299
295300
296301class ResourceDetector (abc .ABC ):
297- def __init__ (self , raise_on_error = False ):
302+ def __init__ (self , raise_on_error : bool = False ) -> None :
298303 self .raise_on_error = raise_on_error
299304
300305 @abc .abstractmethod
@@ -343,7 +348,7 @@ def detect(self) -> "Resource":
343348 ),
344349 )
345350 )
346- _process_pid = os .getpid ()
351+ _process_pid = str ( os .getpid () )
347352 _process_executable_name = sys .executable
348353 _process_executable_path = os .path .dirname (_process_executable_name )
349354 _process_command = sys .argv [0 ]
@@ -358,23 +363,24 @@ def detect(self) -> "Resource":
358363 PROCESS_EXECUTABLE_PATH : _process_executable_path ,
359364 PROCESS_COMMAND : _process_command ,
360365 PROCESS_COMMAND_LINE : _process_command_line ,
361- PROCESS_COMMAND_ARGS : _process_command_args ,
366+ PROCESS_COMMAND_ARGS :"" . join ( _process_command_args ) ,
362367 }
363368 if hasattr (os , "getppid" ):
364369 # pypy3 does not have getppid()
365- resource_info [PROCESS_PARENT_PID ] = os .getppid ()
370+ resource_info [PROCESS_PARENT_PID ] = str ( os .getppid () )
366371
367372 if psutil is not None :
368373 process = psutil .Process ()
369- resource_info [PROCESS_OWNER ] = process .username ()
374+ username = cast (str , process .username ())
375+ resource_info [PROCESS_OWNER ] = username
370376
371377 return Resource (resource_info )
372378
373379
374380def get_aggregated_resources (
375381 detectors : typing .List ["ResourceDetector" ],
376382 initial_resource : typing .Optional [Resource ] = None ,
377- timeout = 5 ,
383+ timeout : int = 5 ,
378384) -> "Resource" :
379385 """Retrieves resources from detectors in the order that they were passed
380386
0 commit comments