Skip to content

Commit 32b83a0

Browse files
author
alrex
authored
make immutable attributes consistent (#1909)
1 parent bab5011 commit 32b83a0

6 files changed

Lines changed: 27 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Ignore calls to `Span.set_status` with `StatusCode.UNSET` and also if previous status already
1313
had `StatusCode.OK`.
1414
([#1902](https://github.com/open-telemetry/opentelemetry-python/pull/1902))
15+
- Attributes for `Link` and `Resource` are immutable as they are for `Event`, which means
16+
any attempt to modify attributes directly will result in a `TypeError` exception.
17+
([#1909](https://github.com/open-telemetry/opentelemetry-python/pull/1909))
1518

1619
## [1.3.0-0.22b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.3.0-0.22b0) - 2021-06-01
1720

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@
8282
from typing import Iterator, Optional, Sequence, cast
8383

8484
from opentelemetry import context as context_api
85+
from opentelemetry.attributes import ( # type: ignore
86+
_create_immutable_attributes,
87+
)
8588
from opentelemetry.context.context import Context
8689
from opentelemetry.environment_variables import OTEL_PYTHON_TRACER_PROVIDER
8790
from opentelemetry.trace.propagation import (
@@ -126,7 +129,7 @@ def attributes(self) -> types.Attributes:
126129

127130

128131
class Link(_LinkBase):
129-
"""A link to a `Span`.
132+
"""A link to a `Span`. The attributes of a Link are immutable.
130133
131134
Args:
132135
context: `SpanContext` of the `Span` to link to.
@@ -139,7 +142,9 @@ def __init__(
139142
attributes: types.Attributes = None,
140143
) -> None:
141144
super().__init__(context)
142-
self._attributes = attributes
145+
self._attributes = _create_immutable_attributes(
146+
attributes
147+
) # type: types.Attributes
143148

144149
@property
145150
def attributes(self) -> types.Attributes:

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@
6464

6565
import pkg_resources
6666

67-
from opentelemetry.attributes import _filter_attributes
67+
from opentelemetry.attributes import (
68+
_create_immutable_attributes,
69+
_filter_attributes,
70+
)
6871
from opentelemetry.sdk.environment_variables import (
6972
OTEL_RESOURCE_ATTRIBUTES,
7073
OTEL_SERVICE_NAME,
@@ -145,7 +148,7 @@ def __init__(
145148
self, attributes: Attributes, schema_url: typing.Optional[str] = None
146149
):
147150
_filter_attributes(attributes)
148-
self._attributes = attributes.copy()
151+
self._attributes = _create_immutable_attributes(attributes)
149152
if schema_url is None:
150153
schema_url = ""
151154
self._schema_url = schema_url
@@ -187,7 +190,7 @@ def get_empty() -> "Resource":
187190

188191
@property
189192
def attributes(self) -> Attributes:
190-
return self._attributes.copy()
193+
return self._attributes
191194

192195
@property
193196
def schema_url(self) -> str:
@@ -210,7 +213,7 @@ def merge(self, other: "Resource") -> "Resource":
210213
Returns:
211214
The newly-created Resource.
212215
"""
213-
merged_attributes = self.attributes
216+
merged_attributes = self.attributes.copy()
214217
merged_attributes.update(other.attributes)
215218

216219
if self.schema_url == "":
@@ -239,7 +242,7 @@ def __eq__(self, other: object) -> bool:
239242

240243
def __hash__(self):
241244
return hash(
242-
f"{dumps(self._attributes, sort_keys=True)}|{self._schema_url}"
245+
f"{dumps(self._attributes.copy(), sort_keys=True)}|{self._schema_url}"
243246
)
244247

245248

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ def attributes(self) -> types.Attributes:
296296

297297

298298
class Event(EventBase):
299-
"""A text annotation with a set of attributes.
299+
"""A text annotation with a set of attributes. The attributes of an event
300+
are immutable.
300301
301302
Args:
302303
name: Name of the event.
@@ -456,7 +457,7 @@ def to_json(self, indent=4):
456457
f_span["attributes"] = self._format_attributes(self._attributes)
457458
f_span["events"] = self._format_events(self._events)
458459
f_span["links"] = self._format_links(self._links)
459-
f_span["resource"] = self._resource.attributes
460+
f_span["resource"] = self._format_attributes(self._resource.attributes)
460461

461462
return json.dumps(f_span, indent=indent)
462463

opentelemetry-sdk/tests/resources/test_resources.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ def test_immutability(self):
188188
resource = resources.Resource.create(attributes)
189189
self.assertEqual(resource.attributes, attributes_copy)
190190

191-
resource.attributes["has_bugs"] = False
191+
with self.assertRaises(TypeError):
192+
resource.attributes["has_bugs"] = False
192193
self.assertEqual(resource.attributes, attributes_copy)
193194

194195
attributes["cost"] = 999.91

opentelemetry-sdk/tests/trace/test_trace.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ def test_links(self):
805805
self.assertEqual(
806806
root.links[0].context.span_id, other_context1.span_id
807807
)
808-
self.assertEqual(root.links[0].attributes, None)
808+
self.assertEqual(0, len(root.links[0].attributes))
809809
self.assertEqual(
810810
root.links[1].context.trace_id, other_context2.trace_id
811811
)
@@ -814,6 +814,9 @@ def test_links(self):
814814
)
815815
self.assertEqual(root.links[1].attributes, {"name": "neighbor"})
816816

817+
with self.assertRaises(TypeError):
818+
root.links[1].attributes["name"] = "new_neighbour"
819+
817820
def test_update_name(self):
818821
with self.tracer.start_as_current_span("root") as root:
819822
# name

0 commit comments

Comments
 (0)