Skip to content

[ruff] Added cls.__dict__.get('__annotations__') check (RUF063) #18233

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

Merged
merged 14 commits into from
Jun 20, 2025

Conversation

dericcrago
Copy link
Contributor

@dericcrago dericcrago commented May 20, 2025

Added cls.__dict__.get('__annotations__') check for Python 3.10+ and Python < 3.10 with typing-extensions enabled.

Closes #17853

Summary

Added cls.__dict__.get('__annotations__') check for Python 3.10+ and Python < 3.10 with typing-extensions enabled.

Test Plan

cargo test

@AlexWaygood AlexWaygood added the rule Implementing or modifying a lint rule label May 20, 2025
@AlexWaygood
Copy link
Member

AlexWaygood commented May 20, 2025

looks like you need to regenerate the JSON schema -- running cargo dev generate-all and committing the changes should fix it!

@dericcrago dericcrago force-pushed the 17853-cls-dict-annotations branch from 34602f5 to 8669fd7 Compare May 20, 2025 21:37
Copy link
Contributor

github-actions bot commented May 20, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@dericcrago
Copy link
Contributor Author

Thank you for the review @JelleZijlstra! I will work on these changes.

Copy link
Contributor

@JelleZijlstra JelleZijlstra left a comment

Choose a reason for hiding this comment

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

Looks good, thanks!

The error message might be a bit long with mentioning all the different get_annotations() functions.

#[derive_message_formats]
fn message(&self) -> String {
"Use `typing_extensions.get_annotations` (Python < 3.10 with \
`typing_extensions` enabled), `inspect.get_annotations` \
Copy link
Contributor

Choose a reason for hiding this comment

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

"enabled" is an odd word choice, is that used elsewhere in Ruff? I'd use "installed" (this also occurs a few other times in the file).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for taking another look @JelleZijlstra!

You're right, the original error message was a bit lengthy. I've trimmed about 25 characters off, but I'm happy to iterate on this further if you have other suggestions for conciseness.

Regarding "enabled" vs. "installed"; thanks for pointing that out. I think some distinction and mixed use might be necessary. For example, I think that:

Does this distinction for using 'enabled' in the context of the ruff setting seem reasonable to you? I'm open to suggestions if you still feel like "installed" makes more sense or if a different term would be clearer here.

I've pushed the above changes for review.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I see, didn't realize that was a reference to a Ruff setting.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's understandable, the code was a bit ambiguous regarding the typing-extensions module vs setting. I'm hopeful that the changes in the last commit make that distinction clearer. Please let me know if it's still not quite hitting the mark! Thanks for sticking with me @JelleZijlstra!

@MichaReiser MichaReiser requested a review from dylwil3 May 23, 2025 14:22
@MichaReiser
Copy link
Member

MichaReiser commented May 23, 2025

@dylwil3 could you review this PR (as the author of the issue and it being Python 3.14 related?)

@MichaReiser MichaReiser added the python314 Related to Python 3.14 label May 23, 2025
@ntBre ntBre self-requested a review May 30, 2025 16:09
Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

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

Thanks, this is looking great overall! I just have a few stylistic nits/suggestions.

@dericcrago dericcrago force-pushed the 17853-cls-dict-annotations branch 2 times, most recently from 8bfef8e to b5a45a8 Compare June 8, 2025 20:18
Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

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

Thanks, this looks great! Just a couple of small nits, the merge conflicts, and possibly extending the rule to __dict__["__annotations__"] as you said (and renaming). This is otherwise good to go!

dericcrago and others added 12 commits June 19, 2025 02:26
Python < 3.10 with `typing_extensions` enabled.
Co-authored-by: Brent Westbrook <[email protected]>
This commit renames the rule from `AnnotationsFromClassDict` to
`AccessAnnotationsFromClassDict` to better reflect its expanded scope.

The rule has been extended to detect direct subscript access
(e.g., `foo.__dict__["__annotations__"]`), in addition to the existing
check for `foo.__dict__.get("__annotations__")` method calls.

This change provides more comprehensive detection of this discouraged
access pattern.
@dericcrago dericcrago force-pushed the 17853-cls-dict-annotations branch from b5a45a8 to c31b5d6 Compare June 19, 2025 06:39
@MichaReiser MichaReiser requested a review from ntBre June 19, 2025 14:30
Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

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

This is great, thank you!

@ntBre ntBre changed the title Added cls.__dict__.get('__annotations__') check [ruff] Added cls.__dict__.get('__annotations__') check (RUF063) Jun 20, 2025
@ntBre ntBre merged commit e66f182 into astral-sh:main Jun 20, 2025
35 checks passed
@dericcrago dericcrago deleted the 17853-cls-dict-annotations branch June 20, 2025 13:39
dcreager added a commit that referenced this pull request Jun 20, 2025
* main: (21 commits)
  [`flake8-logging`] Avoid false positive for `exc_info=True` outside `logger.exception` (`LOG014`) (#18737)
  [`flake8-pie`] Small docs fix to `PIE794` (#18829)
  [`pylint`] Ignore __init__.py files in (PLC0414) (#18400)
  Avoid generating diagnostics with per-file ignores (#18801)
  [`flake8-simplify`] Fix false negatives for shadowed bindings  (`SIM910`, `SIM911`) (#18794)
  [ty] Fix panics when pulling types for `ClassVar` or `Final` parameterized with >1 argument (#18824)
  [`pylint`] add fix safety section (`PLR1714`) (#18415)
  [Perflint] Small docs improvement to `PERF401` (#18786)
  [`pylint`] Avoid flattening nested `min`/`max` when outer call has single argument (`PLW3301`) (#16885)
  [`ruff`] Added `cls.__dict__.get('__annotations__')` check (`RUF063`) (#18233)
  [ty] Use `HashTable` in `PlaceTable` (#18819)
  docs: Correct collections-named-tuple example to use PascalCase assignment (#16884)
  [ty] ecosystem-analyzer workflow (#18719)
  [ty] Add support for `@staticmethod`s (#18809)
  unnecessary_dict_kwargs doc - a note on type checking benefits (#18666)
  [`flake8-pytest-style`] Mark autofix for `PT001` and `PT023` as unsafe if there's comments in the decorator (#18792)
  [ty] Surface matched overload diagnostic directly (#18452)
  [ty] Report when a dataclass contains more than one `KW_ONLY` field (#18731)
  [`flake8-pie`] Add fix safety section to `PIE794` (#18802)
  [`pycodestyle`] Add fix safety section to `W291` and `W293`  (#18800)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
python314 Related to Python 3.14 rule Implementing or modifying a lint rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Warn users of Python 3.14+ against cls.__dict__.get("__annotations__", {})
5 participants