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

Add all PEP-585 names to UP006 rule #5454

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

Conversation

wookie184
Copy link
Contributor

Closes #3936

Summary

Building on #4420, adds the remaining PEP-585 names.

Test Plan

Added snapshot tests for a few cases.

@charliermarsh
Copy link
Member

Hmm, I believe these are already covered by the deprecated import rule that we have in pyupgrade. There’s clearly some overlap in responsibilities between the two.

@wookie184
Copy link
Contributor Author

Hmm, I believe these are already covered by the deprecated import rule that we have in pyupgrade. There’s clearly some overlap in responsibilities between the two.

Currently, UP035 detects imports of many deprecated names, while UP006 detects usage of just PEP 585 deprecated names. So e.g.

from typing import List  # Flagged by UP035
x: List  # Flagged by UP006

import typing
x: typing.List  # Flagged by UP006

It definitely seems like something that could be merged into one rule, or we could have two (one for pep 585 and one for other deprecated names) which share their implementation.


Also made me realise an issue with this PR currently:

import typing
from typing import Sequence

x: Sequence
x: typing.Sequence

causes an error

error: Failed to create fix for NonPEP585Annotation: Unable to insert `Sequence` into scope due to name conflict
error: Failed to create fix for NonPEP585Annotation: Unable to insert `Sequence` into scope due to name conflict
test.py:2:1: UP035 [*] Import from `collections.abc` instead: `Sequence`
test.py:4:4: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
test.py:5:4: UP006 Use `collections.abc.Sequence` instead of `typing.Sequence` for type annotation
Found 3 errors.
[*] 1 potentially fixable with the --fix option.

although weirdly when I actually run --fix it runs 2 fixes (including UP006) and does actually fix the code properly... I guess ruff reruns fixes until the output is stable?

@charliermarsh
Copy link
Member

I think this originally arose from pyupgrade, which has two separate "rules" for deprecated imports vs. PEP 585 rewrites (for builtins only). Most deprecated imports can be fixed by only modifying the import site, since they typically involve members that were moved from one module to another. Meanwhile, the PEP 585 built-in rewrites don't require changing imports at all, since they only change to list, set, etc., which are available as builtins. Later, when we added support for multi-location fixes, we added defaultdict and deque to the PEP 585 rule; and we added typing.List and friends to the deprecated import rule, even though it was already covered in a sense by the PEP 585 rule. Anyway, just explaining why this happened, not how we should deal with it.

The current setup honestly seems okay to me (the PEP 585 rule deals with members that need to be renamed; the deprecated imports rule only fixes imports), but I'd probably also be okay with removing the PEP 585 imports from "deprecated imports" and moving them into this rule. Though it might be sort of complicated to pull off given how different the implementations are, and some of the quirks around how they'd need to be gated (e.g., you can rewrite List to list if from __future__ import annotations is present, but you can't rewrite to a collections.abc import), at which point, I may question the value.

although weirdly when I actually run --fix it runs 2 fixes (including UP006) and does actually fix the code properly... I guess ruff reruns fixes until the output is stable?

Yeah, that's right -- we iteratively fix up to a certain number of iterations.

@wookie184
Copy link
Contributor Author

Thanks for explaining, I agree that it seems quite complicated to combine the rules, and removing the duplication of names would probably also require a decent amount of work. Maybe something that could be done at some point but I'm not sure it's necessary for this PR.

I fixed the issue with the name conflict when both types of import are already there (the autofix for this case still works, it just needs the UP035 autofix first).

Does this look alright?

@flying-sheep
Copy link
Contributor

Ah, this is great! It would be great to have this automated!

@zanieb
Copy link
Member

zanieb commented Oct 19, 2023

@charliermarsh I think this is probably reasonable as discussed?

@charliermarsh
Copy link
Member

I feel like this could be better suited to inclusion in UP035 -- since the deprecated imports flagged in there should be a superset of the PEP 585 changes.

@charliermarsh
Copy link
Member

charliermarsh commented Oct 21, 2023

As an example: if someone does import pipes; pipes.quote, we probably want to rewrite that to import shlex; shlex.quote. But that's unrelated to PEP 585.

@wookie184
Copy link
Contributor Author

I feel like this could be better suited to inclusion in UP035 -- since the deprecated imports flagged in there should be a superset of the PEP 585 changes.

I can't think of a case that you'd want to have a rule to detect/fix

from typing import List
x: List

but not

import typing
x: typing.List

I would expect them to be treated as equivalent by a rule attempting to update to PEP 585 annotations.

As an example: if someone does import pipes; pipes.quote, we probably want to rewrite that to import shlex; shlex.quote. But that's unrelated to PEP 585.

I think that just suggests that would make sense to implement for UP006 (ideally sharing implementation with UP035). IMO, the difference between UP006 and UP035 should just be what names are affected, not in what cases the names are changed, since that's not a helpful distinction for the user.

@charliermarsh charliermarsh self-requested a review December 1, 2023 01:56
@charliermarsh charliermarsh added the rule Implementing or modifying a lint rule label Dec 1, 2023
Copy link
Contributor

github-actions bot commented Dec 1, 2023

ruff-ecosystem results

Linter (stable)

ℹ️ ecosystem check detected linter changes. (+4 -0 violations, +0 -0 fixes in 2 projects; 53 projects unchanged)

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


pdm-project/pdm (+4 -0 violations, +0 -0 fixes)

+ src/pdm/cli/commands/cache.py:37:47: FA100 Add `from __future__ import annotations` to simplify `typing.Iterable`
+ src/pdm/cli/commands/cache.py:97:20: FA100 Add `from __future__ import annotations` to simplify `typing.Iterable`
+ src/pdm/cli/commands/config.py:102:36: FA100 Add `from __future__ import annotations` to simplify `typing.Mapping`
+ src/pdm/cli/commands/config.py:102:67: FA100 Add `from __future__ import annotations` to simplify `typing.Mapping`

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
FA100 4 4 0 0 0

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+2824 -0 violations, +0 -0 fixes in 22 projects; 33 projects unchanged)

aiven/aiven-client (+409 -0 violations, +0 -0 fixes)

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

+ aiven/client/argx.py:104:38: UP006 Use `collections.abc.Iterable` instead of `Iterable` for type annotation
+ aiven/client/argx.py:155:54: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ aiven/client/argx.py:171:45: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ aiven/client/argx.py:174:49: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ aiven/client/argx.py:241:29: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ aiven/client/argx.py:278:34: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ aiven/client/argx.py:278:44: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ aiven/client/argx.py:290:32: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
+ aiven/client/argx.py:300:29: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ aiven/client/argx.py:303:34: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
... 399 additional changes omitted for project

apache/airflow (+481 -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:34:24: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/parameters.py:87:24: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/parameters.py:90:52: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/parameters.py:90:78: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/security.py:114:6: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/security.py:161:54: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/security.py:180:53: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/security.py:199:57: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/security.py:218:54: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ airflow/api_connexion/security.py:237:6: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
... 471 additional changes omitted for project

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

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

+ scripts/check-env.py:37:40: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/advanced_data_type/types.py:58:21: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/advanced_data_type/types.py:59:23: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/cli/test_db.py:81:12: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/cli/test_db.py:88:38: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/commands/chart/export.py:80:30: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/commands/dashboard/export.py:168:30: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/commands/database/export.py:108:30: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/commands/dataset/export.py:87:30: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ superset/commands/dataset/importers/v0.py:129:22: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
... 157 additional changes omitted for project

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

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

+ release/action.py:27:31: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ release/action.py:27:52: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
+ release/action.py:35:47: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
+ release/build.py:144:22: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ release/credentials.py:37:22: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ release/credentials.py:40:38: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ release/pipeline.py:24:12: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ release/pipeline.py:34:31: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
+ release/ui.py:103:33: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
+ release/ui.py:24:17: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
... 240 additional changes omitted for project

ibis-project/ibis (+3 -0 violations, +0 -0 fixes)

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

+ ibis/common/tests/test_patterns.py:1122:13: UP006 [*] Use `collections.abc.Callable` instead of `Callable` for type annotation
+ ibis/common/tests/test_patterns.py:1125:10: UP006 [*] Use `collections.abc.Callable` instead of `Callable` for type annotation
+ ibis/common/tests/test_patterns.py:731:31: UP006 [*] Use `collections.abc.Callable` instead of `Callable` for type annotation

langchain-ai/langchain (+299 -0 violations, +0 -0 fixes)

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

+ libs/core/langchain_core/_api/beta_decorator.py:128:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/beta_decorator.py:186:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/beta_decorator.py:201:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/beta_decorator.py:30:30: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/beta_decorator.py:39:6: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/deprecation.py:202:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/deprecation.py:232:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/deprecation.py:252:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/deprecation.py:268:47: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ libs/core/langchain_core/_api/deprecation.py:300:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
... 289 additional changes omitted for project

lnbits/lnbits (+47 -0 violations, +0 -0 fixes)

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

+ lnbits/app.py:342:46: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ lnbits/app.py:352:47: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ lnbits/core/models.py:332:30: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ lnbits/core/models.py:333:31: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ lnbits/core/views/auth_api.py:340:49: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ lnbits/lnurl.py:24:36: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ lnbits/tasks.py:143:11: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ lnbits/tasks.py:143:31: UP006 Use `collections.abc.Coroutine` instead of `Coroutine` for type annotation
+ lnbits/tasks.py:144:19: UP006 Use `collections.abc.Coroutine` instead of `Coroutine` for type annotation
+ lnbits/tasks.py:144:6: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
... 37 additional changes omitted for project

milvus-io/pymilvus (+1 -0 violations, +0 -0 fixes)

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

+ _version_helper.py:32:17: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation

mlflow/mlflow (+101 -0 violations, +0 -0 fixes)

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

+ dev/clint/src/clint/linter.py:110:42: UP006 Use `collections.abc.Iterator` instead of `Iterator` for type annotation
+ dev/set_matrix.py:317:56: UP006 Use `collections.abc.Iterator` instead of `Iterator` for type annotation
+ mlflow/bedrock/_autolog.py:46:35: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ mlflow/bedrock/_autolog.py:46:58: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ mlflow/data/dataset_registry.py:122:48: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ mlflow/data/dataset_registry.py:18:31: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ mlflow/data/dataset_registry.py:63:47: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ mlflow/data/dataset_registry.py:93:42: UP006 Use `collections.abc.Callable` instead of `Callable` for type annotation
+ mlflow/data/huggingface_dataset.py:180:37: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
+ mlflow/data/huggingface_dataset.py:180:52: UP006 Use `collections.abc.Mapping` instead of `Mapping` for type annotation
... 91 additional changes omitted for project

pypa/build (+6 -0 violations, +0 -0 fixes)

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

+ src/build/_builder.py:120:14: UP006 Use `collections.abc.Sequence` instead of `Sequence` for type annotation
+ src/build/_builder.py:120:68: UP006 Use `collections.abc.Mapping` instead of `Mapping` for type annotation
+ src/build/_builder.py:39:28: UP006 Use `collections.abc.Mapping` instead of `Mapping` for type annotation
+ src/build/_builder.py:60:44: UP006 Use `collections.abc.Mapping` instead of `Mapping` for type annotation
+ src/build/_builder.py:74:47: UP006 Use `collections.abc.Mapping` instead of `Mapping` for type annotation
+ src/build/_builder.py:74:69: UP006 Use `collections.abc.Mapping` instead of `Mapping` for type annotation

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

Changes by rule (2 rules affected)

code total + violation - violation + fix - fix
UP006 2820 2820 0 0 0
FA100 4 4 0 0 0

@zanieb
Copy link
Member

zanieb commented Mar 12, 2024

@AlexWaygood @charliermarsh could you two work together to determine a path forward on this one?

@charliermarsh
Copy link
Member

Ok, I think it actually does make sense to add these here -- but they probably need to go under preview. You're right that it's silly that the first case triggers, but the second does not:

from typing import AbstractSet

def f(x: AbstractSet[str]) -> None:
    pass

import typing

def f(x: typing.AbstractSet[str]) -> None:
    pass

@charliermarsh
Copy link
Member

If you want to rebase and gate the new variants behind preview, I am happy to merge the change.

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

As of Charlie's comment

If you want to rebase and gate the new variants behind preview, I am happy to merge the change.

@dylwil3 dylwil3 force-pushed the more-UP006-detection branch from 3a46aeb to 2138d18 Compare December 17, 2024 03:06
@dylwil3 dylwil3 requested a review from MichaReiser December 23, 2024 22:53
Comment on lines +324 to +327
pub fn as_pep_585_generic(call_path: &[&str]) -> Option<ModuleMember> {
match call_path {
// Builtins
["typing" | "typing_extensions", "Tuple"] => Some(("", "tuple")),
Copy link
Member

Choose a reason for hiding this comment

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

nit: we can split this into two matches to short-circuit when the call path is not from typing / typing_extensions module like:

let ["typing" | "typing_extensions", member @ ..] = call_path else {
    return None;
};

match member {
    // Builtins
    ["Tuple"] => Some(("", "tuple")),
    ["List"] => Some(("", "list")),
	// ...
}

Copy link
Member

@dhruvmanila dhruvmanila 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

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

Successfully merging this pull request may close these issues.

Support flake8-pep585 for accesses from typing after import
7 participants