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

[flake8-type-checking] Expands TC006 docs to better explain itself #14749

Merged
merged 4 commits into from
Dec 4, 2024

Conversation

Daverball
Copy link
Contributor

Closes: #14676

I think the consensus generally was to keep the rule as-is, but expand the docs.

Summary

Expands the docs for TC006 with an explanation for why the type expression is always quoted, including mention of another potential benefit to this style.

Copy link
Contributor

github-actions bot commented Dec 3, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@Daverball Daverball marked this pull request as draft December 3, 2024 10:02
@Daverball
Copy link
Contributor Author

Let's see where the discussion goes first.

@Daverball Daverball marked this pull request as ready for review December 4, 2024 07:52
@Daverball
Copy link
Contributor Author

@AlexWaygood Is that explanation satisfactory? It might make sense to add a quote-casts setting in the same PR, so we can reference an alternative way to get just the unnecessary import overhead out of casts.

Comment on lines 14 to 18
/// `typing.cast()` does not do anything at runtime, so the time spent
/// on evaluating the type expression is wasted.
/// on evaluating the potentially complex type expression is wasted.
/// But it's also bad to be inconsistent, so this rule always quotes
/// the type expression even if its contribution to import/evaluation
/// time is negligible, as a matter of style.
Copy link
Member

Choose a reason for hiding this comment

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

From our conversation on the issue, my conclusion is that this rule should be thought of as primarily about enforcing stylistic consistency, since there will be other rules added in the future that will be better suited to deal with the performance aspects. I think the first sentence of these docs should reflect that, but the first sentence here still makes it sound like it's primarily focussed on performance :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure how to phrase this any differently, you're welcome to try.

Copy link
Member

Choose a reason for hiding this comment

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

How about this?

 /// ## What it does
-/// Checks for an unquoted type expression in `typing.cast()` calls.
+/// Checks for unquoted type expressions in `typing.cast()` calls.
 ///
 /// ## Why is this bad?
-/// `typing.cast()` does not do anything at runtime, so the time spent
-/// on evaluating the potentially complex type expression is wasted.
-/// But it's also bad to be inconsistent, so this rule always quotes
-/// the type expression even if its contribution to import/evaluation
-/// time is negligible, as a matter of style.
+/// This rule helps enforce a consistent style across your codebase.
+///
+/// It's often necessary to quote the first argument passed to `cast()`,
+/// as type expressions can involve forward references, or references
+/// to symbols which are only imported in `typing.TYPE_CHECKING` blocks.
+/// This can lead to a visual inconsistency across different `cast()` calls,
+/// where some type expressions are quoted but others are not. By enabling
+/// this rule, you ensure that all type expressions passed to `cast()` are
+/// quoted, enforcing stylistic consistency across all of your `cast()` calls.

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 seems fine to me. Although I'd eventually like to cross-reference performance-focused alternatives like a quote-casts setting for TC001-003 and/or a new rule to quote type expressions that create typing._GenericAlias instances. So if we completely stop explicitly mentioning performance that might come a bit out of left-field.

At least as long as we make the quoting sub-expressions part of TC001-003 and this potentially new rule opt-in. If it's always on (which should technically always be safe) then I don't think that's as necessary. But given your readability pushback I assume there are some people which would prefer to never quote their casts, regardless of any potential benefits.

So in that world I would like to give people enough information in order to make an informed decision about whether TC006, enabling quote-casts or doing neither would make more sense for them.

Copy link
Member

Choose a reason for hiding this comment

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

We could add a sentence to the end about performance?

 /// ## What it does
-/// Checks for an unquoted type expression in `typing.cast()` calls.
+/// Checks for unquoted type expressions in `typing.cast()` calls.
 ///
 /// ## Why is this bad?
-/// `typing.cast()` does not do anything at runtime, so the time spent
-/// on evaluating the potentially complex type expression is wasted.
-/// But it's also bad to be inconsistent, so this rule always quotes
-/// the type expression even if its contribution to import/evaluation
-/// time is negligible, as a matter of style.
+/// This rule helps enforce a consistent style across your codebase.
+///
+/// It's often necessary to quote the first argument passed to `cast()`,
+/// as type expressions can involve forward references, or references
+/// to symbols which are only imported in `typing.TYPE_CHECKING` blocks.
+/// This can lead to a visual inconsistency across different `cast()` calls,
+/// where some type expressions are quoted but others are not. By enabling
+/// this rule, you ensure that all type expressions passed to `cast()` are
+/// quoted, enforcing stylistic consistency across all of your `cast()` calls.
+///
+/// In some cases where `cast()` is used in a hot loop, this rule may also
+/// help avoid overhead from repeatedly evaluating complex type expressions at
+/// runtime.

You don't have to use my suggested rewrite exactly. But from the discussion on the issue, I do think the emphasis should be on style/consistency, rather than performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suppose we could lead into that with something like the following

/// Although quoting the type expression in `typing.cast` calls
/// will ensure that the runtime overhead is as small as possible
/// there are alternative rules and settings which will get you
/// most of the way there, while keeping quoted expressions to
/// a minimum.

So your text seems good enough for now.

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Thank you! Really appreciate it

@AlexWaygood AlexWaygood enabled auto-merge (squash) December 4, 2024 13:11
auto-merge was automatically disabled December 4, 2024 13:11

Head branch was pushed to by a user without write access

@AlexWaygood AlexWaygood enabled auto-merge (squash) December 4, 2024 13:12
@AlexWaygood AlexWaygood merged commit e67f7f2 into astral-sh:main Dec 4, 2024
20 checks passed
@Daverball Daverball deleted the docs/tc006 branch December 4, 2024 13:17
dcreager added a commit that referenced this pull request Dec 4, 2024
* main:
  [red-knot] Test: Hashable/Sized => A/B (#14769)
  [`flake8-type-checking`] Expands TC006 docs to better explain itself (#14749)
  [`pycodestyle`] Handle f-strings properly for `invalid-escape-sequence (W605)` (#14748)
  [red-knot] Add fuzzer to catch panics for invalid syntax (#14678)
  Check `AIR001` from builtin or providers `operators` module (#14631)
  [airflow]: extend removed names (AIR302) (#14734)
@AlexWaygood AlexWaygood added the documentation Improvements or additions to documentation label Dec 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TC006 in 0.8.1 is too broad
2 participants