diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b925076a..90d2cf829b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- `opentelemetry-api`: Fix `AttributeError` on Python 3.9 when invalid type passed to attributes + ([#4933](https://github.com/open-telemetry/opentelemetry-python/pull/4933)) - `opentelemetry-sdk`: Drop unused Jaeger exporter environment variables (exporter removed in 1.22.0) ([#4918](https://github.com/open-telemetry/opentelemetry-python/issues/4918)) - `opentelemetry-sdk`: Clarify timeout units in environment variable documentation diff --git a/opentelemetry-api/src/opentelemetry/attributes/__init__.py b/opentelemetry-api/src/opentelemetry/attributes/__init__.py index 5116c2fdd8..0602c11100 100644 --- a/opentelemetry-api/src/opentelemetry/attributes/__init__.py +++ b/opentelemetry-api/src/opentelemetry/attributes/__init__.py @@ -39,6 +39,15 @@ _logger = logging.getLogger(__name__) +def _get_type_name(tp: type) -> str: + """Get the name of a type, handling typing module edge cases on Python 3.9.""" + name = getattr(tp, "__name__", None) + if name is None: + # Handle typing module types like Sequence, Mapping that don't have __name__ on Python 3.9 + name = getattr(tp, "_name", str(tp)) + return name + + def _clean_attribute( key: str, value: types.AttributeValue, max_len: Optional[int] ) -> Optional[Union[types.AttributeValue, Tuple[Union[str, int, float], ...]]]: @@ -113,7 +122,7 @@ def _clean_attribute( "sequence of those types", type(value).__name__, key, - [valid_type.__name__ for valid_type in _VALID_ATTR_VALUE_TYPES], + [_get_type_name(valid_type) for valid_type in _VALID_ATTR_VALUE_TYPES], ) return None @@ -190,7 +199,7 @@ def _clean_extended_attribute_value( # pylint: disable=too-many-branches except Exception: raise TypeError( f"Invalid type {type(value).__name__} for attribute value. " - f"Expected one of {[valid_type.__name__ for valid_type in _VALID_ANY_VALUE_TYPES]} or a " + f"Expected one of {[_get_type_name(valid_type) for valid_type in _VALID_ANY_VALUE_TYPES]} or a " "sequence of those types", )