Skip to content

sdk: tighten ReadableSpan.attributes to non-Optional Mapping (#4569) - #5183

Open
WatchTree-19 wants to merge 4 commits into
open-telemetry:mainfrom
WatchTree-19:fix/readable-span-attributes-non-optional
Open

sdk: tighten ReadableSpan.attributes to non-Optional Mapping (#4569)#5183
WatchTree-19 wants to merge 4 commits into
open-telemetry:mainfrom
WatchTree-19:fix/readable-span-attributes-non-optional

Conversation

@WatchTree-19

Copy link
Copy Markdown

Description

ReadableSpan.attributes is annotated as types.Attributes, which resolves to Optional[Mapping[str, AttributeValue]]. The implementation always returns MappingProxyType(self._attributes or {}) - the or {} fallback ensures we never return None at runtime.

Pyright / Pylance flags Object of type "None" is not subscriptable on span.attributes["key"], forcing assert span.attributes is not None boilerplate at every call site.

This PR tightens the return annotation on ReadableSpan.attributes to the non-Optional Mapping[str, types.AttributeValue]. Implementation unchanged. Mapping is already imported in the file.

Scope:

  • ReadableSpan.attributes only. Inherited by Span and _Span, no further changes needed.
  • Event.attributes and Link.attributes return self._attributes directly (which can be None) and stay Optional.
  • types.Attributes global alias is unchanged for the same reason.

Per the comment thread on #4569 from @exekis and @tekumara, the implementation has never returned None from ReadableSpan.attributes, so this is type-system tightening rather than a behaviour change. Technically a breaking change for any caller explicitly handling None on the return; in practice there shouldn't be any.

Fixes #4569

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • patched file parses cleanly via python -m ast
  • existing call sites are unchanged, only the return-type annotation is narrower
  • have not run the project test suite locally; happy to chase a green CI here if anything trips

Does This PR Require a Contrib Repo Change?

  • Yes. - Link to PR:
  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

@WatchTree-19
WatchTree-19 requested a review from a team as a code owner May 7, 2026 14:57
@linux-foundation-easycla

linux-foundation-easycla Bot commented May 7, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

WatchTree-19 added a commit to WatchTree-19/opentelemetry-python that referenced this pull request May 8, 2026

@MikeGoldsmith MikeGoldsmith left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @WatchTree-19 - left some feedback on things we need to tidy up

Comment thread CHANGELOG.md Outdated

## Unreleased

- `opentelemetry-sdk`: tighten `ReadableSpan.attributes` annotation to non-Optional `Mapping` so callers don't need `assert ... is not None` boilerplate; runtime guarantee was already in place via `MappingProxyType(self._attributes or {})`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks like you got some other changelog entries in here - please can you clean this up?

@property
def attributes(self) -> types.Attributes:
def attributes(self) -> Mapping[str, types.AttributeValue]:
# The implementation always returns a MappingProxyType, never None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is very verbose, can we tighten this up?


@property
def attributes(self) -> types.Attributes:
def attributes(self) -> Mapping[str, types.AttributeValue]:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do / should we update the API definition too?

@github-project-automation github-project-automation Bot moved this to Reviewed PRs that need fixes in Python PR digest May 11, 2026
WatchTree-19 added a commit to WatchTree-19/opentelemetry-python that referenced this pull request May 12, 2026
…try#5183)

Signed-off-by: WatchTree-19 <119982314+WatchTree-19@users.noreply.github.com>
@WatchTree-19

Copy link
Copy Markdown
Author

thanks @MikeGoldsmith. pushed a follow-up addressing all three:

  1. CHANGELOG.md: hadn't realised the repo had moved to towncrier since my first commit went up - sorry for the noise. reverted the CHANGELOG.md edit to upstream/main and added .changelog/5183.changed as a one-line fragment per CONTRIBUTING.md.

  2. docstring: tightened to a single line.

@property
def attributes(self) -> Mapping[str, types.AttributeValue]:
    # `or {}` keeps the return non-None; see #4569.
    return MappingProxyType(self._attributes or {})
  1. API definition: looked at opentelemetry-api/src/opentelemetry/trace/span.py. the abstract trace_api.Span class defines set_attributes and set_attribute but no attributes property - that's only on the SDK's ReadableSpan. so no parallel API change is needed; the narrower annotation lives entirely in the SDK layer. happy to add a @property to the abstract API with the same Mapping[str, types.AttributeValue] return type if you'd prefer the surface symmetrical, but that'd be an API addition rather than a fix.

let me know if there's anything else.

@emdneto

emdneto commented May 12, 2026

Copy link
Copy Markdown
Member

Thanks for the PR!

Just a heads-up: we no longer update CHANGELOG.md directly. The changelog is now generated from changelog fragments using Towncrier.

Please add the appropriate changelog fragment for this change instead of editing CHANGELOG.md manually. You can find the instructions and expected format in CONTRIBUTING.md.

@WatchTree-19

Copy link
Copy Markdown
Author

@emdneto already addressed in the follow-up - reverted the CHANGELOG.md edit and added .changelog/5183.changed per CONTRIBUTING.md. see the latest commit + comment above.

@WatchTree-19
WatchTree-19 force-pushed the fix/readable-span-attributes-non-optional branch from 6b96015 to 6e05d7d Compare May 17, 2026 12:43
@WatchTree-19

Copy link
Copy Markdown
Author

@MikeGoldsmith @emdneto gentle bump - rebased onto current main to clear the CHANGELOG.md conflict that came in with the towncrier migration. branch is now one commit (SDK annotation tightening + .changelog/5183.changed fragment), DCO signed. ready for another look when you have time.

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment.
If you're still working on this, please add a comment or push new commits.

@github-actions github-actions Bot added the Stale label Jun 1, 2026
@WatchTree-19

Copy link
Copy Markdown
Author

still active. branch is rebased onto current main, single commit (SDK annotation
tightening + .changelog/5183.changed), DCO signed. awaiting review from
@MikeGoldsmith or @emdneto when there's a window. happy to address any
remaining concerns.

@github-actions github-actions Bot removed the Stale label Jun 3, 2026
@github-actions

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment.
If you're still working on this, please add a comment or push new commits.

@github-actions github-actions Bot added the Stale label Jun 18, 2026
@WatchTree-19
WatchTree-19 force-pushed the fix/readable-span-attributes-non-optional branch from 6e05d7d to 29614aa Compare June 24, 2026 16:32
@WatchTree-19

Copy link
Copy Markdown
Author

@MikeGoldsmith thanks - addressed both points:

  • "tighten this up": removed the explanatory comment entirely. MappingProxyType(self._attributes or {}) already makes the non-None guarantee self-evident, and the rationale lives in the changelog fragment / commit message, so the diff is now just the annotation change.

  • "update the API definition too?": nothing to update on the API side. ReadableSpan is SDK-only, and the API Span interface (opentelemetry-api) only exposes attribute setters, not a readable attributes getter, so there's no abstract to narrow. the shared types.Attributes alias stays Optional on purpose - it's used for attribute inputs across the codebase (EventBase.attributes, span-creation params, etc.) that legitimately accept None. so this change is deliberately scoped to the one ReadableSpan.attributes return, where the implementation guarantees a Mapping.

re-requesting review. branch is behind main but conflict-free - happy to update it if you'd rather it be current before merge.

@github-actions github-actions Bot removed the Stale label Jun 25, 2026
@github-actions

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment.
If you're still working on this, please add a comment or push new commits.

@github-actions github-actions Bot added the Stale label Jul 10, 2026
@github-actions github-actions Bot removed the Stale label Jul 11, 2026
…n-telemetry#4569)

The implementation always returns a `MappingProxyType`, never `None`,
because `self._attributes or {}` falls back to an empty dict. Tightening
the return annotation lets callers index `span.attributes["key"]` without
type-checker complaints. Adds the towncrier fragment per CONTRIBUTING.

Signed-off-by: WatchTree-19 <119982314+WatchTree-19@users.noreply.github.com>
@WatchTree-19
WatchTree-19 force-pushed the fix/readable-span-attributes-non-optional branch from 29614aa to 11369be Compare July 20, 2026 19:44
@WatchTree-19

Copy link
Copy Markdown
Author

Rebased onto current main (11369be1) — the branch was showing behind, it's now clean and still a single commit.

Where this actually stands, since it's been round the stale-bot loop a few times:

  • @tekumara approved 10 days ago.
  • The only thing formally blocking is the CHANGES_REQUESTED from 70 days ago. Both points in it were addressed — the explanatory comment was dropped entirely, so the diff is now purely the annotation change, and there's no parallel API change to make because ReadableSpan is SDK-only (the API Span exposes attribute setters, not a readable getter). types.Attributes deliberately stays Optional, since it's the input alias used where None is legitimate.

@MikeGoldsmith — could you either re-review or dismiss the stale review if you're happy? Genuinely no rush on my side, but the review can't clear itself and the bot keeps threatening to bin it.

And if on reflection this isn't a change the SDK wants — narrowing a public return annotation is a real (if small) compatibility surface — I'd rather close it than keep it cycling. Just say and I'll take care of it.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 days of this comment.
If you're still working on this, please add a comment or push new commits.

@github-actions github-actions Bot added the Stale label Aug 4, 2026
@WatchTree-19

Copy link
Copy Markdown
Author

gentle nudge before the stale bot closes this. the change request predates the rework, i tightened the annotation and @tekumara approved on the current shape. @MikeGoldsmith would you re-review when you get a chance? happy to adjust if anything still reads wrong.

@github-actions github-actions Bot removed the Stale label Aug 13, 2026
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Aug 14, 2026

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-08-22 21:24 UTC

Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):

  • Inline threads: 1
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

@WatchTree-19
WatchTree-19 force-pushed the fix/readable-span-attributes-non-optional branch from 3297186 to 4188951 Compare August 20, 2026 13:02
@opentelemetry-pr-dashboard

Copy link
Copy Markdown

Hi @WatchTree-19 — just a friendly reminder that this pull request is waiting on you. The dashboard status comment has the open items and is kept current.

  • Replying is enough to hand it off — answer, explain why no change is needed, or ask a follow-up. The dashboard routes it onward once nothing on the list is waiting on you.
  • To hand it back for any other reason, including the dashboard getting this wrong, comment /dashboard route:reviewers.

@WatchTree-19

Copy link
Copy Markdown
Author

@MikeGoldsmith friendly ping on this one, I think all three points are covered now:

  • Changelog: cleaned up, it's a single .changelog/5183.changed fragment for this change only.
  • Verbosity: the diff is down to the one line on ReadableSpan.attributes.
  • API definition: the API Span has no attributes property, only set_attributes, so there's nothing to tighten there. ReadableSpan is SDK-only.

Rebased on main and green, and @tekumara approved in July. Mind taking another look when you get a chance?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Reviewed PRs that need fixes

Development

Successfully merging this pull request may close these issues.

Object of type "None" is not subscriptable

4 participants