Solve and enforce ruff PYI rules#12533
Merged
berland merged 9 commits intoequinor:mainfrom Dec 22, 2025
Merged
Conversation
non-self-return-type (PYI034)
Derived from the **flake8-pyi** linter.
Fix is sometimes available.
* What it does
Checks for methods that are annotated with a fixed return type which
should instead be returning `Self`.
* Why is this bad?
If methods that generally return `self` at runtime are annotated with a
fixed return type, and the class is subclassed, type checkers will not be
able to infer the correct return type.
For example:
```python
class Shape:
def set_scale(self, scale: float) -> Shape:
self.scale = scale
return self
class Circle(Shape):
def set_radius(self, radius: float) -> Circle:
self.radius = radius
return self
* Type checker infers return type as `Shape`, not `Circle`.
Circle().set_scale(0.5)
* Thus, this expression is invalid, as `Shape` has no attribute `set_radius`.
Circle().set_scale(0.5).set_radius(2.7)
```
* collections-named-tuple (PYI024) Derived from the **flake8-pyi** linter. * What it does Checks for uses of `collections.namedtuple` in stub files. * Why is this bad? `typing.NamedTuple` is the "typed version" of `collections.namedtuple`. Inheriting from `typing.NamedTuple` creates a custom `tuple` subclass in the same way as using the `collections.namedtuple` factory function. However, using `typing.NamedTuple` allows you to provide a type annotation for each field in the class. This means that type checkers will have more information to work with, and will be able to analyze your code more precisely.
* redundant-numeric-union (PYI041) Derived from the **flake8-pyi** linter. Fix is sometimes available. * What it does Checks for parameter annotations that contain redundant unions between builtin numeric types (e.g., `int | float`). * Why is this bad? The [typing specification] states: > Python’s numeric types `complex`, `float` and `int` are not subtypes of > each other, but to support common use cases, the type system contains a > straightforward shortcut: when an argument is annotated as having type > `float`, an argument of type `int` is acceptable; similar, for an > argument annotated as having type `complex`, arguments of type `float` or > `int` are acceptable. As such, a union that includes both `int` and `float` is redundant in the specific context of a parameter annotation, as it is equivalent to a union that only includes `float`. For readability and clarity, unions should omit redundant elements.
* bad-exit-annotation (PYI036) Derived from the **flake8-pyi** linter. Fix is sometimes available. * What it does Checks for incorrect function signatures on `__exit__` and `__aexit__` methods. * Why is this bad? Improperly annotated `__exit__` and `__aexit__` methods can cause unexpected behavior when interacting with type checkers.
* any-eq-ne-annotation (PYI032) Derived from the **flake8-pyi** linter. Fix is always available. * What it does Checks for `__eq__` and `__ne__` implementations that use `typing.Any` as the type annotation for their second parameter. * Why is this bad? The Python documentation recommends the use of `object` to "indicate that a value could be any type in a typesafe manner". `Any`, on the other hand, should be seen as an "escape hatch when you need to mix dynamically and statically typed code". Since using `Any` allows you to write highly unsafe code, you should generally only use `Any` when the semantics of your code would otherwise be inexpressible to the type checker. The expectation in Python is that a comparison of two arbitrary objects using `==` or `!=` should never raise an exception. This contract can be fully expressed in the type system and does not involve requesting unsound behaviour from a type checker. As such, `object` is a more appropriate annotation than `Any` for the second parameter of the methods implementing these comparison operators -- `__eq__` and `__ne__`.
* custom-type-var-for-self (PYI019) Derived from the **flake8-pyi** linter. Fix is sometimes available. * What it does Checks for methods that use custom [`TypeVar`s][typing_TypeVar] in their annotations when they could use [`Self`][Self] instead. * Why is this bad? While the semantics are often identical, using `Self` is more intuitive and succinct (per [PEP 673]) than a custom `TypeVar`. For example, the use of `Self` will typically allow for the omission of type parameters on the `self` and `cls` arguments. This check currently applies to instance methods that return `self`, class methods that return an instance of `cls`, class methods that return `cls`, and `__new__` methods.
The examples used in literal had no effect on typing, include them as examples in the pydantic schema insteead. * redundant-literal-union (PYI051) Derived from the **flake8-pyi** linter. * What it does Checks for redundant unions between a `Literal` and a builtin supertype of that `Literal`. * Why is this bad? Using a `Literal` type in a union with its builtin supertype is redundant, as the supertype will be strictly more general than the `Literal` type. For example, `Literal["A"] | str` is equivalent to `str`, and `Literal[1] | int` is equivalent to `int`, as `str` and `int` are the supertypes of `"A"` and `1` respectively.
* pep484-style-positional-only-parameter (PYI063) Derived from the **flake8-pyi** linter. * What it does Checks for the presence of [PEP 484]-style positional-only parameters. * Why is this bad? Historically, [PEP 484] recommended prefixing parameter names with double underscores (`__`) to indicate to a type checker that they were positional-only. However, [PEP 570] (introduced in Python 3.8) introduced dedicated syntax for positional-only arguments. If a forward slash (`/`) is present in a function signature on Python 3.8+, all parameters prior to the slash are interpreted as positional-only. The new syntax should be preferred as it is more widely used, more concise and more readable. It is also respected by Python at runtime, whereas the old-style syntax was only understood by type checkers.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #12533 +/- ##
==========================================
- Coverage 90.67% 90.66% -0.02%
==========================================
Files 431 431
Lines 29720 29724 +4
==========================================
Hits 26948 26948
- Misses 2772 2776 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
CodSpeed Performance ReportMerging #12533 will not alter performanceComparing Summary
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue
Resolves many ruff issues
Approach
One commit pr ruff rule.
git rebase -i main --exec 'just rapid-tests')When applicable