-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[pyupgrade] Fix false positive for TypeVar with default on Python <3.13 (UP046,UP047)
#21045
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
Conversation
|
ntBre
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! The code change and new comments look great, but would you mind converting your manual tests into regression tests in the repo?
If you already have separate Python files, they would fit nicely as new test cases alongside files like UP046_1.py and test_case entries here:
ruff/crates/ruff_linter/src/rules/pyupgrade/mod.rs
Lines 114 to 126 in 83a3bc4
| #[test_case(Rule::NonPEP695GenericFunction, Path::new("UP047.py"))] | |
| #[test_case(Rule::PrivateTypeParameter, Path::new("UP049_0.py"))] | |
| #[test_case(Rule::PrivateTypeParameter, Path::new("UP049_1.py"))] | |
| #[test_case(Rule::UselessClassMetaclassType, Path::new("UP050.py"))] | |
| fn rules(rule_code: Rule, path: &Path) -> Result<()> { | |
| let snapshot = path.to_string_lossy().to_string(); | |
| let diagnostics = test_path( | |
| Path::new("pyupgrade").join(path).as_path(), | |
| &settings::LinterSettings::for_rule(rule_code), | |
| )?; | |
| assert_diagnostics!(snapshot, diagnostics); | |
| Ok(()) | |
| } |
Although you may need a separate test function so that you can set the version like we do here:
| unresolved_target_version: PythonVersion::PY37.into(), |
|
Thanks for the review! As an update - I got busy with festivals around; I plan to complete this in the next 2-3 days. |
….13 (`UP046`,`UP047`) Type default for Type parameter was added in Python 3.13 (PEP 696). `typing_extensions.TypeVar` backports the default argument to earlier versions. `UP046` & `UP047` were getting triggered when typing_extensions.TypeVar with `default` argument was used on python version < 3.13 It shouldn't be triggered for python version < 3.13 This commit fixes the bug by adding a python version check before triggering them. Fixes astral-sh#20929. Signed-off-by: Prakhar Pratyush <[email protected]>
056c130 to
a559cb8
Compare
|
@ntBre I've added tests. Ready to review. |
ntBre
left a comment
There was a problem hiding this 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!
pyupgrade] Fix false positive for TypeVar with default on Python<3.13 (UP046,UP047)pyupgrade] Fix false positive for TypeVar with default on Python <3.13 (UP046,UP047)
* origin/main: (21 commits) [ty] Update "constraint implication" relation to work on constraints between two typevars (#21068) [`flake8-type-checking`] Fix `TC003` false positive with `future-annotations` (#21125) [ty] Fix lookup of `__new__` on instances (#21147) Fix syntax error false positive on nested alternative patterns (#21104) [`pyupgrade`] Fix false positive for `TypeVar` with default on Python <3.13 (`UP046`,`UP047`) (#21045) [ty] Reachability and narrowing for enum methods (#21130) [ty] Use `range` instead of custom `IntIterable` (#21138) [`ruff`] Add support for additional eager conversion patterns (`RUF065`) (#20657) [`ruff-ecosystem`] Fix CLI crash on Python 3.14 (#21092) [ty] Infer type of `self` for decorated methods and properties (#21123) [`flake8-bandit`] Fix correct example for `S308` (#21128) [ty] Dont provide goto definition for definitions which are not reexported in builtins (#21127) [`airflow`] warning `airflow....DAG.create_dagrun` has been removed (`AIR301`) (#21093) [ty] follow the breaking API changes made in salsa-rs/salsa#1015 (#21117) [ty] Rename `Type::into_nominal_instance` (#21124) [ty] Filter out "unimported" from the current module [ty] Add evaluation test for auto-import including symbols in current module [ty] Refactor `ty_ide` completion tests [ty] Render `import <...>` in completions when "label details" isn't supported [`refurb`] Preserve digit separators in `Decimal` constructor (`FURB157`) (#20588) ...
Summary
Type default for Type parameter was added in Python 3.13 (PEP 696).
typing_extensions.TypeVarbackports the default argument to earlier versions.UP046&UP047were getting triggered whentyping_extensions.TypeVarwithdefaultargument was used on python version < 3.13It shouldn't be triggered for python version < 3.13
This commit fixes the bug by adding a python version check before triggering them.
Fixes #20929.
Test Plan
Manual testing 1
As the issue author pointed out in #20929 (comment), ran the following on
mainbranch:Output
Compiling ruff_linter v0.14.1 (/Users/prakhar/ruff/crates/ruff_linter) Compiling ruff v0.14.1 (/Users/prakhar/ruff/crates/ruff) Compiling ruff_graph v0.1.0 (/Users/prakhar/ruff/crates/ruff_graph) Compiling ruff_workspace v0.0.0 (/Users/prakhar/ruff/crates/ruff_workspace) Compiling ruff_server v0.2.2 (/Users/prakhar/ruff/crates/ruff_server) Finished `dev` profile [unoptimized + debuginfo] target(s) in 6.72s Running `target/debug/ruff check ../efax/ --target-version py312 --no-cache` UP046 Generic class `ExpectationParametrization` uses `Generic` subclass instead of type parameters --> /Users/prakhar/efax/efax/_src/expectation_parametrization.py:17:48 | 17 | class ExpectationParametrization(Distribution, Generic[NP]): | ^^^^^^^^^^^ 18 | """The expectation parametrization of an exponential family distribution. | help: Use type parameters UP046 Generic class `ExpToNat` uses `Generic` subclass instead of type parameters --> /Users/prakhar/efax/efax/_src/mixins/exp_to_nat/exp_to_nat.py:27:68 | 26 | @dataclass 27 | class ExpToNat(ExpectationParametrization[NP], SimpleDistribution, Generic[NP]): | ^^^^^^^^^^^ 28 | """This mixin implements the conversion from expectation to natural parameters. | help: Use type parameters UP046 Generic class `HasEntropyEP` uses `Generic` subclass instead of type parameters --> /Users/prakhar/efax/efax/_src/mixins/has_entropy.py:25:20 | 23 | HasEntropy, 24 | JaxAbstractClass, 25 | Generic[NP]): | ^^^^^^^^^^^ 26 | @abstract_jit 27 | @abstractmethod | help: Use type parameters UP046 Generic class `HasEntropyNP` uses `Generic` subclass instead of type parameters --> /Users/prakhar/efax/efax/_src/mixins/has_entropy.py:64:20 | 62 | class HasEntropyNP(NaturalParametrization[EP], 63 | HasEntropy, 64 | Generic[EP]): | ^^^^^^^^^^^ 65 | @jit 66 | @final | help: Use type parameters UP046 Generic class `NaturalParametrization` uses `Generic` subclass instead of type parameters --> /Users/prakhar/efax/efax/_src/natural_parametrization.py:43:30 | 41 | class NaturalParametrization(Distribution, 42 | JaxAbstractClass, 43 | Generic[EP, Domain]): | ^^^^^^^^^^^^^^^^^^^ 44 | """The natural parametrization of an exponential family distribution. | help: Use type parameters UP046 Generic class `Structure` uses `Generic` subclass instead of type parameters --> /Users/prakhar/efax/efax/_src/structure/structure.py:31:17 | 30 | @dataclass 31 | class Structure(Generic[P]): | ^^^^^^^^^^ 32 | """This class generalizes the notion of type for Distribution objects. | help: Use type parameters UP046 Generic class `DistributionInfo` uses `Generic` subclass instead of type parameters --> /Users/prakhar/efax/tests/distribution_info.py:20:24 | 20 | class DistributionInfo(Generic[NP, EP, Domain]): | ^^^^^^^^^^^^^^^^^^^^^^^ 21 | def __init__(self, dimensions: int = 1, safety: float = 0.0) -> None: 22 | super().__init__() | help: Use type parameters Found 7 errors. No fixes available (7 hidden fixes can be enabled with the `--unsafe-fixes` option).Running it after the changes:
ruff % cargo run -p ruff -- check ../efax/ --target-version py312 --no-cache Compiling ruff_linter v0.14.1 (/Users/prakhar/ruff/crates/ruff_linter) Compiling ruff v0.14.1 (/Users/prakhar/ruff/crates/ruff) Compiling ruff_graph v0.1.0 (/Users/prakhar/ruff/crates/ruff_graph) Compiling ruff_workspace v0.0.0 (/Users/prakhar/ruff/crates/ruff_workspace) Compiling ruff_server v0.2.2 (/Users/prakhar/ruff/crates/ruff_server) Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.86s Running `target/debug/ruff check ../efax/ --target-version py312 --no-cache` All checks passed!Manual testing 2
Ran the check on the following script (mainly to verify
UP047):On
mainbranch:Output
Compiling ruff_linter v0.14.1 (/Users/prakhar/ruff/crates/ruff_linter) Compiling ruff v0.14.1 (/Users/prakhar/ruff/crates/ruff) Compiling ruff_graph v0.1.0 (/Users/prakhar/ruff/crates/ruff_graph) Compiling ruff_workspace v0.0.0 (/Users/prakhar/ruff/crates/ruff_workspace) Compiling ruff_server v0.2.2 (/Users/prakhar/ruff/crates/ruff_server) Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.43s Running `target/debug/ruff check /Users/prakhar/up046.py --target-version py312 --preview --no-cache` UP047 Generic function `generic_function` should use type parameters --> /Users/prakhar/up046.py:10:5 | 10 | def generic_function(var: T) -> T: | ^^^^^^^^^^^^^^^^^^^^^^^^ 11 | return var | help: Use type parameters UP046 Generic class `GenericClass` uses `Generic` subclass instead of type parameters --> /Users/prakhar/up046.py:17:20 | 17 | class GenericClass(Generic[Q]): | ^^^^^^^^^^ 18 | var: Q | help: Use type parameters Found 2 errors. No fixes available (2 hidden fixes can be enabled with the `--unsafe-fixes` option).After the fix (this branch):