diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a35f9d763..b55b878f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- `opentelemetry-api`: Fix `AttributeError` instead of `TypeError` when invalid type is passed + to `_clean_extended_attribute_value` on Python 3.9 due to `typing.Mapping`/`typing.Sequence` + lacking `__name__` + ([#4821](https://github.com/open-telemetry/opentelemetry-python/issues/4821)) + - `opentelemetry-sdk`: Add `create_resource` and `create_propagator`/`configure_propagator` to declarative file configuration, enabling Resource and propagator instantiation from config files without reading env vars ([#4979](https://github.com/open-telemetry/opentelemetry-python/pull/4979)) - `opentelemetry-sdk`: Map Python `CRITICAL` log level to OTel `FATAL` severity text per the specification diff --git a/opentelemetry-api/src/opentelemetry/attributes/__init__.py b/opentelemetry-api/src/opentelemetry/attributes/__init__.py index ad6dab5935..5a3d6a878e 100644 --- a/opentelemetry-api/src/opentelemetry/attributes/__init__.py +++ b/opentelemetry-api/src/opentelemetry/attributes/__init__.py @@ -191,7 +191,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 {[getattr(valid_type, '__name__', getattr(valid_type, '_name', str(valid_type))) for valid_type in _VALID_ANY_VALUE_TYPES]} or a " "sequence of those types", ) diff --git a/opentelemetry-api/tests/attributes/test_attributes.py b/opentelemetry-api/tests/attributes/test_attributes.py index 40d04fbe7d..83940143c8 100644 --- a/opentelemetry-api/tests/attributes/test_attributes.py +++ b/opentelemetry-api/tests/attributes/test_attributes.py @@ -22,6 +22,7 @@ BoundedAttributes, _clean_attribute, _clean_extended_attribute, + _clean_extended_attribute_value, ) @@ -183,6 +184,19 @@ def test_mapping(self): _clean_extended_attribute("headers", mapping, None), expected ) + def test_invalid_type_raises_type_error_not_attribute_error(self): + # On Python 3.9, typing generics like Mapping/Sequence lack __name__, + # which previously caused AttributeError instead of TypeError (#4821). + class NoStr: + def __str__(self): + raise Exception("cannot stringify") + + with self.assertRaises(TypeError) as ctx: + _clean_extended_attribute_value(NoStr(), None) + + self.assertIn("Invalid type", str(ctx.exception)) + self.assertIn("Expected one of", str(ctx.exception)) + class TestBoundedAttributes(unittest.TestCase): # pylint: disable=consider-using-dict-items