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] Adds implementation for TC006 #14511

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Daverball
Copy link
Contributor

@Daverball Daverball commented Nov 21, 2024

Now that TCH has been renamed to TC and the redirect from TCH006 to TCH010 can no longer bite us, I've added an implementation for this very simple rule.

Summary

TC006 checks for non-string literal arguments to typing.cast which adds unnecessary runtime overhead, since the function doesn't do anything at runtime.

This PR has a very tiny overlap with my other PR for TCH007/TCH008 in flake8_type_checking/helpers.rs for adding the quote_type_expression function, but the two changes don't really depend on one another, so they can be merged in any order.

Test Plan

cargo nextest run

Copy link
Contributor

github-actions bot commented Nov 21, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+571 -0 violations, +0 -0 fixes in 10 projects; 44 projects unchanged)

DisnakeDev/disnake (+11 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ disnake/abc.py:1249:25: TC006 [*] Add quotes to type expression in `typing.cast()`
+ disnake/abc.py:299:25: TC006 [*] Add quotes to type expression in `typing.cast()`
+ disnake/components.py:755:27: TC006 [*] Add quotes to type expression in `typing.cast()`
+ disnake/ext/commands/base_core.py:196:43: TC006 [*] Add quotes to type expression in `typing.cast()`
+ disnake/ext/commands/core.py:1950:19: TC006 [*] Add quotes to type expression in `typing.cast()`
+ disnake/ext/commands/core.py:1980:19: TC006 [*] Add quotes to type expression in `typing.cast()`
+ disnake/interactions/base.py:197:37: TC006 [*] Add quotes to type expression in `typing.cast()`
+ docs/extensions/fulltoc.py:122:34: TC006 [*] Add quotes to type expression in `typing.cast()`
+ tests/test_abc.py:165:30: TC006 [*] Add quotes to type expression in `typing.cast()`
+ tests/test_abc.py:166:30: TC006 [*] Add quotes to type expression in `typing.cast()`
... 1 additional changes omitted for project

apache/airflow (+176 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ airflow/api/auth/backend/deny_all.py:44:17: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/endpoints/request_dict.py:26:17: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/parameters.py:106:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:107:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:156:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:175:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:194:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:213:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:229:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:250:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_connexion/security.py:88:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/api_fastapi/core_api/app.py:86:29: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/cli/commands/task_command.py:596:25: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/dag_processing/manager.py:1172:34: TC006 [*] Add quotes to type expression in `typing.cast()`
+ airflow/decorators/base.py:486:32: TC006 [*] Add quotes to type expression in `typing.cast()`
... 161 additional changes omitted for project

apache/superset (+80 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ superset/charts/api.py:588:22: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/charts/api.py:710:22: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/dashboard/filter_state/create.py:39:22: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/dashboard/filter_state/update.py:36:22: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/database/tables.py:136:28: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/distributed_lock/get.py:45:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/explore/get.py:116:26: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/explore/get.py:130:52: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/sql_lab/export.py:101:44: TC006 [*] Add quotes to type expression in `typing.cast()`
+ superset/commands/sql_lab/results.py:111:44: TC006 [*] Add quotes to type expression in `typing.cast()`
... 70 additional changes omitted for project

bokeh/bokeh (+60 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ src/bokeh/core/serialization.py:428:26: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:537:50: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:539:53: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:541:53: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:543:52: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:545:50: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:547:50: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:549:52: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:551:52: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/bokeh/core/serialization.py:553:58: TC006 [*] Add quotes to type expression in `typing.cast()`
... 50 additional changes omitted for project

latchbio/latch (+7 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ src/latch/registry/table.py:501:35: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/latch/registry/table.py:678:34: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/latch/registry/utils.py:38:26: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/latch/registry/utils.py:54:28: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/latch/registry/utils.py:64:22: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/latch_cli/services/register/utils.py:157:32: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/latch_cli/services/register/utils.py:159:24: TC006 [*] Add quotes to type expression in `typing.cast()`

pandas-dev/pandas (+138 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ pandas/core/algorithms.py:27:5: TC001 Move application import `pandas._typing.AnyArrayLike` into a type-checking block
+ pandas/core/algorithms.py:28:5: TC001 Move application import `pandas._typing.ArrayLike` into a type-checking block
+ pandas/core/algorithms.py:29:5: TC001 Move application import `pandas._typing.ArrayLikeT` into a type-checking block
+ pandas/core/algorithms.py:30:5: TC001 Move application import `pandas._typing.AxisInt` into a type-checking block
+ pandas/core/algorithms.py:31:5: TC001 Move application import `pandas._typing.DtypeObj` into a type-checking block
+ pandas/core/algorithms.py:32:5: TC001 Move application import `pandas._typing.TakeIndexer` into a type-checking block
... 110 additional changes omitted for rule TC001
+ pandas/core/dtypes/dtypes.py:967:89: E501 Line too long (89 > 88)
+ pandas/core/frame.py:17:5: TC003 Move standard library import `collections.abc.Callable` into a type-checking block
+ pandas/core/frame.py:18:5: TC003 Move standard library import `collections.abc.Hashable` into a type-checking block
+ pandas/core/frame.py:19:5: TC003 Move standard library import `collections.abc.Iterable` into a type-checking block
+ pandas/core/frame.py:20:5: TC003 Move standard library import `collections.abc.Iterator` into a type-checking block
+ pandas/core/frame.py:21:5: TC003 Move standard library import `collections.abc.Mapping` into a type-checking block
... 126 additional changes omitted for project

rotki/rotki (+51 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ rotkehlchen/accounting/history_base_entries.py:105:29: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/accounting/history_base_entries.py:109:34: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/api/rest.py:649:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/api/v1/schemas.py:2861:18: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/api/v1/schemas.py:2892:27: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/chain/aggregator.py:1488:41: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/chain/arbitrum_one/node_inquirer.py:63:31: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/chain/base/node_inquirer.py:63:31: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/chain/bitcoin/hdkey.py:283:36: TC006 [*] Add quotes to type expression in `typing.cast()`
+ rotkehlchen/chain/bitcoin/hdkey.py:284:27: TC006 [*] Add quotes to type expression in `typing.cast()`
... 41 additional changes omitted for project

scikit-build/scikit-build-core (+8 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ src/scikit_build_core/hatch/plugin.py:50:29: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/scikit_build_core/settings/sources.py:642:29: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/scikit_build_core/settings/sources.py:643:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ src/scikit_build_core/settings/sources.py:644:21: TC006 [*] Add quotes to type expression in `typing.cast()`
+ tests/test_builder.py:108:26: TC006 [*] Add quotes to type expression in `typing.cast()`
+ tests/test_builder.py:128:26: TC006 [*] Add quotes to type expression in `typing.cast()`
+ tests/test_builder.py:141:28: TC006 [*] Add quotes to type expression in `typing.cast()`
+ tests/test_pyproject_pep660.py:14:24: TC006 [*] Add quotes to type expression in `typing.cast()`

... Truncated remaining completed project reports due to GitHub comment length restrictions

Changes by rule (5 rules affected)

code total + violation - violation + fix - fix
TC006 431 431 0 0 0
TC001 117 117 0 0 0
TC003 21 21 0 0 0
E501 1 1 0 0 0
TC002 1 1 0 0 0

@Daverball
Copy link
Contributor Author

Daverball commented Nov 21, 2024

The extra hits for the other rules make sense to me, since fixing TC006 can result in subsequent TC001-003 errors (or E501 for a very long annotation).

In the case of SIM115 the fix for TC006 causes the SIM115 violation to shift by two characters. But the actual violation doesn't change.

@MichaReiser MichaReiser added rule Implementing or modifying a lint rule preview Related to preview mode features labels Nov 22, 2024
Comment on lines +66 to +79
#[test_case(Rule::RuntimeCastValue, Path::new("TC006.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("preview__{}_{}", rule_code.as_ref(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("flake8_type_checking").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}

Copy link
Member

Choose a reason for hiding this comment

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

I know this is a pattern that we have in other linter-groups too, but I don't think it's actually necessary to test a preview-rule. It's only necessary if the rule depends on any other preview-only behavior

Comment on lines +57 to +67
let edit = quote_type_expression(type_expr, checker.semantic(), checker.stylist()).ok();
if let Some(edit) = edit.as_ref() {
if checker
.comment_ranges()
.has_comments(type_expr, checker.source())
{
diagnostic.set_fix(Fix::unsafe_edit(edit.clone()));
} else {
diagnostic.set_fix(Fix::safe_edit(edit.clone()));
}
}
Copy link
Member

Choose a reason for hiding this comment

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

The clone calls here seem unnecessary

Suggested change
let edit = quote_type_expression(type_expr, checker.semantic(), checker.stylist()).ok();
if let Some(edit) = edit.as_ref() {
if checker
.comment_ranges()
.has_comments(type_expr, checker.source())
{
diagnostic.set_fix(Fix::unsafe_edit(edit.clone()));
} else {
diagnostic.set_fix(Fix::safe_edit(edit.clone()));
}
}
let edit = quote_type_expression(type_expr, checker.semantic(), checker.stylist()).ok();
if let Some(edit) = edit {
if checker
.comment_ranges()
.has_comments(type_expr, checker.source())
{
diagnostic.set_fix(Fix::unsafe_edit(edit));
} else {
diagnostic.set_fix(Fix::safe_edit(edit));
}
}

@MichaReiser
Copy link
Member

Thanks for contributing this rule. The code changes look good to me.

I want to wait for updated ecosystem checks. I don't see why this PR should result in any new diagnostics other than TC006.

def f():
import typing as t

t.cast(int, 3.0) # TC006
Copy link
Member

@MichaReiser MichaReiser Nov 22, 2024

Choose a reason for hiding this comment

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

Could we add a test where parts of the type are quoted?

Suggested change
t.cast(int, 3.0) # TC006
t.cast(Literal["3.0", '3'], 3.0) # TC006

@MichaReiser
Copy link
Member

I'm a bit confused by the ecosystem checks. I understand that we run ruff exactly once and don't apply any fixes. That makes it unclear to me why there would be any changed diagnostics other than for TC006.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
preview Related to preview mode features rule Implementing or modifying a lint rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants