From c7f267569a90ee8cf73620e944f7f9356c7ed516 Mon Sep 17 00:00:00 2001 From: JasonXZLiu Date: Wed, 16 Sep 2020 20:41:24 -0700 Subject: [PATCH] Override setattr and delattr for SpanContext + add tests --- .../src/opentelemetry/trace/span.py | 53 ++++++++++++---- .../tests/trace/test_immutablespancontext.py | 62 +++++++++++++++++++ 2 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 opentelemetry-api/tests/trace/test_immutablespancontext.py diff --git a/opentelemetry-api/src/opentelemetry/trace/span.py b/opentelemetry-api/src/opentelemetry/trace/span.py index 27bbc223368..b9724028836 100644 --- a/opentelemetry-api/src/opentelemetry/trace/span.py +++ b/opentelemetry-api/src/opentelemetry/trace/span.py @@ -143,7 +143,7 @@ def get_default(cls) -> "TraceState": DEFAULT_TRACE_STATE = TraceState.get_default() -class SpanContext: +class SpanContext(tuple): """The state of a Span to propagate between processes. This class includes the immutable attributes of a :class:`.Span` that must @@ -157,8 +157,8 @@ class SpanContext: is_remote: True if propagated from a remote parent. """ - def __init__( - self, + def __new__( + cls, trace_id: int, span_id: int, is_remote: bool, @@ -169,16 +169,47 @@ def __init__( trace_flags = DEFAULT_TRACE_OPTIONS if trace_state is None: trace_state = DEFAULT_TRACE_STATE - self.trace_id = trace_id - self.span_id = span_id - self.trace_flags = trace_flags - self.trace_state = trace_state - self.is_remote = is_remote - self.is_valid = ( - self.trace_id != INVALID_TRACE_ID - and self.span_id != INVALID_SPAN_ID + + is_valid = ( + trace_id != INVALID_TRACE_ID + and span_id != INVALID_SPAN_ID ) + return tuple.__new__(cls, (trace_id, span_id, trace_flags, trace_state, is_remote, is_valid)) + + @property + def trace_id(self): + return tuple.__getitem__(self, 0) + + @property + def span_id(self): + return tuple.__getitem__(self, 1) + + @property + def trace_flags(self): + return tuple.__getitem__(self, 2) + + @property + def trace_state(self): + return tuple.__getitem__(self, 3) + + @property + def is_remote(self): + return tuple.__getitem__(self, 4) + + @property + def is_valid(self): + return tuple.__getitem__(self, 5) + + def __getattr__(self, *args): + raise TypeError + + def __setattr__(self, *args): + raise TypeError + + def __delattr__(self, *args): + raise TypeError + def __repr__(self) -> str: return ( "{}(trace_id={}, span_id={}, trace_state={!r}, is_remote={})" diff --git a/opentelemetry-api/tests/trace/test_immutablespancontext.py b/opentelemetry-api/tests/trace/test_immutablespancontext.py new file mode 100644 index 00000000000..cc99a359e6e --- /dev/null +++ b/opentelemetry-api/tests/trace/test_immutablespancontext.py @@ -0,0 +1,62 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +from opentelemetry import trace + + +class TestImmutableSpanContext(unittest.TestCase): + def test_ctor(self): + context = trace.SpanContext( + 1, + 1, + is_remote=False, + trace_flags=trace.DEFAULT_TRACE_OPTIONS, + trace_state=trace.DEFAULT_TRACE_STATE, + ) + + self.assertEqual(context.trace_id, 1) + self.assertEqual(context.span_id, 1) + self.assertEqual(context.is_remote, False) + self.assertEqual(context.trace_flags, trace.DEFAULT_TRACE_OPTIONS) + self.assertEqual(context.trace_state, trace.DEFAULT_TRACE_STATE) + + def test_attempt_change_attributes(self): + context = trace.SpanContext( + 1, + 1, + is_remote=False, + trace_flags=trace.DEFAULT_TRACE_OPTIONS, + trace_state=trace.DEFAULT_TRACE_STATE, + ) + + with self.assertRaises(TypeError): + context.trace_id = 2 + with self.assertRaises(TypeError): + context.span_id = 2 + with self.assertRaises(TypeError): + context.is_remote = True + with self.assertRaises(TypeError): + context.trace_flags = 2 + with self.assertRaises(TypeError): + context.trace_state = 2 + + self.assertEqual(context.trace_id, 1) + self.assertEqual(context.span_id, 1) + self.assertEqual(context.is_remote, False) + self.assertEqual(context.trace_flags, trace.DEFAULT_TRACE_OPTIONS) + self.assertEqual(context.trace_state, trace.DEFAULT_TRACE_STATE) + + self.assertEqual(context.trace_id, 1)