Make Instances of SpanContext Immutable#1134
Make Instances of SpanContext Immutable#1134codeboten merged 7 commits intoopen-telemetry:masterfrom
Conversation
c7f2675 to
e6de321
Compare
|
Please add a CHANGELOG entry as this may break users who have already been trying to modify spancontext. |
02d7b3f to
b9f0d20
Compare
|
|
||
| is_valid = trace_id != INVALID_TRACE_ID and span_id != INVALID_SPAN_ID | ||
|
|
||
| return tuple.__new__( |
There was a problem hiding this comment.
Since we have to override setattr anyways is there an advantage of using tuple vs normal fields set with super.setattr? Latter might be a bit simpler.
There was a problem hiding this comment.
Hmm, if I understand correctly, I think the advantage of inheriting from a tuple is that it doesn't allow something like object.__setattr__(context, "trace_id", 2) (while not inheriting does). I'm not sure if that's something we want to avoid or if we should just keep it simple.
There was a problem hiding this comment.
@anuraaga Hmm, it actually seems a lot cleaner and I dont think the case I mentioned above is something that needs to be avoided. But, because mypy doesn't actually run the code, it's not able to determine that SpanContext actually has the attributes, so I get the following errors:
opentelemetry-api/src/opentelemetry/trace/span.py:200: error: "SpanContext" has no attribute "trace_id"
opentelemetry-api/src/opentelemetry/trace/span.py:200: error: Expression has type "Any"
opentelemetry-api/src/opentelemetry/trace/span.py:201: error: "SpanContext" has no attribute "span_id"
opentelemetry-api/src/opentelemetry/trace/span.py:201: error: Expression has type "Any"
opentelemetry-api/src/opentelemetry/trace/span.py:202: error: "SpanContext" has no attribute "trace_state"
opentelemetry-api/src/opentelemetry/trace/span.py:202: error: Expression has type "Any"
opentelemetry-api/src/opentelemetry/trace/span.py:203: error: "SpanContext" has no attribute "is_remote"
opentelemetry-api/src/opentelemetry/trace/span.py:203: error: Expression has type "Any"
I haven't found a good way around this yet (as only Python 3.6+ supports annotating variables with types).
There was a problem hiding this comment.
I see - in that case no worries :)
There was a problem hiding this comment.
Hmm, if I understand correctly, I think the advantage of inheriting from a tuple is that it doesn't allow something like object.setattr(context, "trace_id", 2) (while not inheriting does). I'm not sure if that's something we want to avoid or if we should just keep it simple.
Do we want to make it impossible to use __setattr__? This should be immutable to prevent users from the mistake of using SpanContext to additional information around. I think making that impossible to do through the public API serves that purpose and self-documents the class. I don't think we need to make it literally impossible to modify the object. Given this is Python, I think anyone included to do it will find a way. We should just make sure we inform the person that they shouldn't do it. If they want to go out of their way and still modify, I think we should probably allow that.
I'm personally fine with using tuple for this but if it is causing too much trouble with tooling and needs a lot of other machinery, perhaps we could use a simpler way that protect modifications through public API but doesn't actually try to make it impossible for users to modify the object.
There was a problem hiding this comment.
@owais @anuraaga Hmm, I think I solved the tooling issues now (the ignores should be inline). There seems to be a false-positive for pylint in determining if SpanContext was instantiated as a tuple (here: https://github.com/open-telemetry/opentelemetry-python/pull/1134/files#diff-36ec0e77c55d7f4a4caef71eda0b3191R187). The issue for testing if we could change the attributes was also fixed inline (here: https://github.com/open-telemetry/opentelemetry-python/pull/1134/files#diff-0924a59286313e337f50e00112a27df8R46-R51).
I'm not sure if it's worth it to go through with the change as it seems like Python doesn't support immutability very well, but all the tooling changes that I made globally were removed.
4106fa7 to
920e75e
Compare
.pylintrc
Outdated
| line-too-long, # Leave this up to black | ||
| exec-used | ||
| exec-used, | ||
| unsubscriptable-object |
There was a problem hiding this comment.
I was getting unsubscriptable-object errors through the linter for the self[0] lines. I tried using getattr instead, but that gave me mypy errors for the attribute types. Couldn't find a better way to get around this change.
There was a problem hiding this comment.
Do you know what true negatives we end up with because of these changes? Ideally we don't reduce the robustness of the tooling significantly by making this small change. This relates to a comment I made on another PR I think in that it's important to make sure the SDK as a whole is optimized for, and not individual suggestions. Actually I've recently found the spec might have too much detail that makes it hard to reconcile with language-specific design like here - open-telemetry/opentelemetry-specification#969. If immutable types aren't idiomatic in Python and cause our tooling to break, we need to consider whether it's actually worth it.
There was a problem hiding this comment.
Hmm, it's true that immutable types aren't idiomatic in Python. From @lzchen's comment below, it seems like it might be possible to disable pylint specifically for just the self[0] lines (as above) which I'll try first. However, it does seem like pylint does have a lot of false positive issues with the unsubscriptable-object error (like here).
279c428 to
4ee86cb
Compare
codeboten
left a comment
There was a problem hiding this comment.
@JasonXZLiu if you resolve the conflict, I can merge today
4ee86cb to
e20c5c4
Compare
Description
This PR makes instances of SpanContext Immutable to match the OpenTelemetry specifications.
Fixes #: #1002
Type of change
How Has This Been Tested?
Unit tests have been added to test the following behavior:
Checklist:
Note: documentation did not need updating as SpanContext is already assumed to be Immutable (from the specifications).