Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make immutable attributes consistent #1909

3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Updated `opentelemetry-opencensus-exporter` to use `service_name` of spans instead of resource
([#1897](https://github.com/open-telemetry/opentelemetry-python/pull/1897))
- Attributes for `Link` and `Resource` are immutable as they are for `Event`, which means
any attempt to modify attributes directly will result in a `TypeError` exception.
([#1909](https://github.com/open-telemetry/opentelemetry-python/pull/1909))

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

Expand Down
3 changes: 2 additions & 1 deletion opentelemetry-api/src/opentelemetry/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
from typing import Iterator, Optional, Sequence, cast

from opentelemetry import context as context_api
from opentelemetry.attributes import _create_immutable_attributes
from opentelemetry.context.context import Context
from opentelemetry.environment_variables import OTEL_PYTHON_TRACER_PROVIDER
from opentelemetry.trace.propagation import (
Expand Down Expand Up @@ -139,7 +140,7 @@ def __init__(
attributes: types.Attributes = None,
) -> None:
super().__init__(context)
self._attributes = attributes
self._attributes = _create_immutable_attributes(attributes)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the docstring for Link and Event about immutability like we do for Resource?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, done.


@property
def attributes(self) -> types.Attributes:
Expand Down
13 changes: 8 additions & 5 deletions opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@

import pkg_resources

from opentelemetry.attributes import _filter_attributes
from opentelemetry.attributes import (
_create_immutable_attributes,
_filter_attributes,
)
from opentelemetry.sdk.environment_variables import (
OTEL_RESOURCE_ATTRIBUTES,
OTEL_SERVICE_NAME,
Expand Down Expand Up @@ -145,7 +148,7 @@ def __init__(
self, attributes: Attributes, schema_url: typing.Optional[str] = None
):
_filter_attributes(attributes)
self._attributes = attributes.copy()
self._attributes = _create_immutable_attributes(attributes)
if schema_url is None:
schema_url = ""
self._schema_url = schema_url
Expand Down Expand Up @@ -187,7 +190,7 @@ def get_empty() -> "Resource":

@property
def attributes(self) -> Attributes:
return self._attributes.copy()
return self._attributes

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

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

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


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ def to_json(self, indent=4):
f_span["attributes"] = self._format_attributes(self._attributes)
f_span["events"] = self._format_events(self._events)
f_span["links"] = self._format_links(self._links)
f_span["resource"] = self._resource.attributes
f_span["resource"] = self._format_attributes(self._resource.attributes)

return json.dumps(f_span, indent=indent)

Expand Down
3 changes: 2 additions & 1 deletion opentelemetry-sdk/tests/resources/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ def test_immutability(self):
resource = resources.Resource.create(attributes)
self.assertEqual(resource.attributes, attributes_copy)

resource.attributes["has_bugs"] = False
with self.assertRaises(TypeError):
resource.attributes["has_bugs"] = False
self.assertEqual(resource.attributes, attributes_copy)

attributes["cost"] = 999.91
Expand Down
5 changes: 4 additions & 1 deletion opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ def test_links(self):
self.assertEqual(
root.links[0].context.span_id, other_context1.span_id
)
self.assertEqual(root.links[0].attributes, None)
self.assertEqual(0, len(root.links[0].attributes))
self.assertEqual(
root.links[1].context.trace_id, other_context2.trace_id
)
Expand All @@ -814,6 +814,9 @@ def test_links(self):
)
self.assertEqual(root.links[1].attributes, {"name": "neighbor"})

with self.assertRaises(TypeError):
root.links[1].attributes["name"] = "new_neighbour"

def test_update_name(self):
with self.tracer.start_as_current_span("root") as root:
# name
Expand Down