mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 06:11:43 +00:00
Spruce up docs for flake8-pyi rules (#10422)
This commit is contained in:
parent
162d2eb723
commit
ae0ff9b029
17 changed files with 173 additions and 115 deletions
|
@ -8,28 +8,34 @@ use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `__eq__` and `__ne__` implementations that use `typing.Any` as
|
/// Checks for `__eq__` and `__ne__` implementations that use `typing.Any` as
|
||||||
/// the type annotation for the `obj` parameter.
|
/// the type annotation for their second parameter.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// The Python documentation recommends the use of `object` to "indicate that a
|
/// The Python documentation recommends the use of `object` to "indicate that a
|
||||||
/// value could be any type in a typesafe manner", while `Any` should be used to
|
/// value could be any type in a typesafe manner". `Any`, on the other hand,
|
||||||
/// "indicate that a value is dynamically typed."
|
/// 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 semantics of `__eq__` and `__ne__` are such that the `obj` parameter
|
/// The expectation in Python is that a comparison of two arbitrary objects
|
||||||
/// should be any type, as opposed to a dynamically typed value. Therefore, the
|
/// using `==` or `!=` should never raise an exception. This contract can be
|
||||||
/// `object` type annotation is more appropriate.
|
/// 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__`.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// class Foo:
|
/// class Foo:
|
||||||
/// def __eq__(self, obj: typing.Any):
|
/// def __eq__(self, obj: typing.Any) -> bool:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// class Foo:
|
/// class Foo:
|
||||||
/// def __eq__(self, obj: object):
|
/// def __eq__(self, obj: object) -> bool:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
/// ## References
|
/// ## References
|
||||||
|
|
|
@ -13,16 +13,17 @@ use crate::checkers::ast::Checker;
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// `typing.NamedTuple` is the "typed version" of `collections.namedtuple`.
|
/// `typing.NamedTuple` is the "typed version" of `collections.namedtuple`.
|
||||||
///
|
///
|
||||||
/// The class generated by subclassing `typing.NamedTuple` is equivalent to
|
/// Inheriting from `typing.NamedTuple` creates a custom `tuple` subclass in
|
||||||
/// `collections.namedtuple`, with the exception that `typing.NamedTuple`
|
/// the same way as using the `collections.namedtuple` factory function.
|
||||||
/// includes an `__annotations__` attribute, which allows type checkers to
|
/// However, using `typing.NamedTuple` allows you to provide a type annotation
|
||||||
/// infer the types of the fields.
|
/// 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.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// from collections import namedtuple
|
/// from collections import namedtuple
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// person = namedtuple("Person", ["name", "age"])
|
/// person = namedtuple("Person", ["name", "age"])
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -20,18 +20,28 @@ use crate::checkers::ast::Checker;
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
/// from typing import TypeAlias
|
||||||
|
///
|
||||||
/// a = b = int
|
/// a = b = int
|
||||||
/// a.b = int
|
///
|
||||||
|
///
|
||||||
|
/// class Klass:
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// Klass.X: TypeAlias = int
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
|
/// from typing import TypeAlias
|
||||||
|
///
|
||||||
/// a: TypeAlias = int
|
/// a: TypeAlias = int
|
||||||
/// b: TypeAlias = int
|
/// b: TypeAlias = int
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// class a:
|
/// class Klass:
|
||||||
/// b: int
|
/// X: TypeAlias = int
|
||||||
/// ```
|
/// ```
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct ComplexAssignmentInStub;
|
pub struct ComplexAssignmentInStub;
|
||||||
|
|
|
@ -10,16 +10,16 @@ use crate::checkers::ast::Checker;
|
||||||
/// Checks for `if` statements with complex conditionals in stubs.
|
/// Checks for `if` statements with complex conditionals in stubs.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Stub files support simple conditionals to test for differences in Python
|
/// Type checkers understand simple conditionals to express variations between
|
||||||
/// versions and platforms. However, type checkers only understand a limited
|
/// different Python versions and platforms. However, complex tests may not be
|
||||||
/// subset of these conditionals; complex conditionals may result in false
|
/// understood by a type checker, leading to incorrect inferences when they
|
||||||
/// positives or false negatives.
|
/// analyze your code.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import sys
|
/// import sys
|
||||||
///
|
///
|
||||||
/// if (2, 7) < sys.version_info < (3, 5):
|
/// if (3, 10) <= sys.version_info < (3, 12):
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -27,9 +27,12 @@ use crate::checkers::ast::Checker;
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import sys
|
/// import sys
|
||||||
///
|
///
|
||||||
/// if sys.version_info < (3, 5):
|
/// if sys.version_info >= (3, 10) and sys.version_info < (3, 12):
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## References
|
||||||
|
/// The [typing documentation on stub files](https://typing.readthedocs.io/en/latest/source/stubs.html#version-and-platform-checks)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct ComplexIfStatementInStub;
|
pub struct ComplexIfStatementInStub;
|
||||||
|
|
||||||
|
|
|
@ -19,25 +19,32 @@ use crate::checkers::ast::Checker;
|
||||||
/// methods.
|
/// methods.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Improperly-annotated `__exit__` and `__aexit__` methods can cause
|
/// Improperly annotated `__exit__` and `__aexit__` methods can cause
|
||||||
/// unexpected behavior when interacting with type checkers.
|
/// unexpected behavior when interacting with type checkers.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
/// from types import TracebackType
|
||||||
|
///
|
||||||
|
///
|
||||||
/// class Foo:
|
/// class Foo:
|
||||||
/// def __exit__(self, typ, exc, tb, extra_arg) -> None:
|
/// def __exit__(
|
||||||
|
/// self, typ: BaseException, exc: BaseException, tb: TracebackType
|
||||||
|
/// ) -> None:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
|
/// from types import TracebackType
|
||||||
|
///
|
||||||
|
///
|
||||||
/// class Foo:
|
/// class Foo:
|
||||||
/// def __exit__(
|
/// def __exit__(
|
||||||
/// self,
|
/// self,
|
||||||
/// typ: type[BaseException] | None,
|
/// typ: type[BaseException] | None,
|
||||||
/// exc: BaseException | None,
|
/// exc: BaseException | None,
|
||||||
/// tb: TracebackType | None,
|
/// tb: TracebackType | None,
|
||||||
/// extra_arg: int = 0,
|
|
||||||
/// ) -> None:
|
/// ) -> None:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -10,9 +10,10 @@ use crate::checkers::ast::Checker;
|
||||||
/// statement in stub files.
|
/// statement in stub files.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Stub files are already evaluated under `annotations` semantics. As such,
|
/// Stub files natively support forward references in all contexts, as stubs are
|
||||||
/// the `from __future__ import annotations` import statement has no effect
|
/// never executed at runtime. (They should be thought of as "data files" for
|
||||||
/// and should be omitted.
|
/// type checkers.) As such, the `from __future__ import annotations` import
|
||||||
|
/// statement has no effect and should be omitted.
|
||||||
///
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Static Typing with Python: Type Stubs](https://typing.readthedocs.io/en/latest/source/stubs.html)
|
/// - [Static Typing with Python: Type Stubs](https://typing.readthedocs.io/en/latest/source/stubs.html)
|
||||||
|
|
|
@ -15,24 +15,46 @@ use crate::checkers::ast::Checker;
|
||||||
/// `__iter__` methods should always should return an `Iterator` of some kind,
|
/// `__iter__` methods should always should return an `Iterator` of some kind,
|
||||||
/// not an `Iterable`.
|
/// not an `Iterable`.
|
||||||
///
|
///
|
||||||
/// In Python, an `Iterator` is an object that has a `__next__` method, which
|
/// In Python, an `Iterable` is an object that has an `__iter__` method; an
|
||||||
/// provides a consistent interface for sequentially processing elements from
|
/// `Iterator` is an object that has `__iter__` and `__next__` methods. All
|
||||||
/// a sequence or other iterable object. Meanwhile, an `Iterable` is an object
|
/// `__iter__` methods are expected to return `Iterator`s. Type checkers may
|
||||||
/// with an `__iter__` method, which itself returns an `Iterator`.
|
/// not always recognize an object as being iterable if its `__iter__` method
|
||||||
|
/// does not return an `Iterator`.
|
||||||
///
|
///
|
||||||
/// Every `Iterator` is an `Iterable`, but not every `Iterable` is an `Iterator`.
|
/// Every `Iterator` is an `Iterable`, but not every `Iterable` is an `Iterator`.
|
||||||
/// By returning an `Iterable` from `__iter__`, you may end up returning an
|
/// For example, `list` is an `Iterable`, but not an `Iterator`; you can obtain
|
||||||
/// object that doesn't implement `__next__`, which will cause a `TypeError`
|
/// an iterator over a list's elements by passing the list to `iter()`:
|
||||||
/// at runtime. For example, returning a `list` from `__iter__` will cause
|
///
|
||||||
/// a `TypeError` when you call `__next__` on it, as a `list` is an `Iterable`,
|
/// ```pycon
|
||||||
/// but not an `Iterator`.
|
/// >>> import collections.abc
|
||||||
|
/// >>> x = [42]
|
||||||
|
/// >>> isinstance(x, collections.abc.Iterable)
|
||||||
|
/// True
|
||||||
|
/// >>> isinstance(x, collections.abc.Iterator)
|
||||||
|
/// False
|
||||||
|
/// >>> next(x)
|
||||||
|
/// Traceback (most recent call last):
|
||||||
|
/// File "<stdin>", line 1, in <module>
|
||||||
|
/// TypeError: 'list' object is not an iterator
|
||||||
|
/// >>> y = iter(x)
|
||||||
|
/// >>> isinstance(y, collections.abc.Iterable)
|
||||||
|
/// True
|
||||||
|
/// >>> isinstance(y, collections.abc.Iterator)
|
||||||
|
/// True
|
||||||
|
/// >>> next(y)
|
||||||
|
/// 42
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using `Iterable` rather than `Iterator` as a return type for an `__iter__`
|
||||||
|
/// methods would imply that you would not necessarily be able to call `next()`
|
||||||
|
/// on the returned object, violating the expectations of the interface.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// import collections.abc
|
/// import collections.abc
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// class Class:
|
/// class Klass:
|
||||||
/// def __iter__(self) -> collections.abc.Iterable[str]:
|
/// def __iter__(self) -> collections.abc.Iterable[str]:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -42,7 +64,7 @@ use crate::checkers::ast::Checker;
|
||||||
/// import collections.abc
|
/// import collections.abc
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// class Class:
|
/// class Klass:
|
||||||
/// def __iter__(self) -> collections.abc.Iterator[str]:
|
/// def __iter__(self) -> collections.abc.Iterator[str]:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -9,19 +9,22 @@ use crate::checkers::ast::Checker;
|
||||||
use crate::settings::types::PythonVersion::Py311;
|
use crate::settings::types::PythonVersion::Py311;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `typing.NoReturn` (and `typing_extensions.NoReturn`) in
|
/// Checks for uses of `typing.NoReturn` (and `typing_extensions.NoReturn`) for
|
||||||
/// stubs.
|
/// parameter annotations.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Prefer `typing.Never` (or `typing_extensions.Never`) over `typing.NoReturn`,
|
/// Prefer `Never` over `NoReturn` for parameter annotations. `Never` has a
|
||||||
/// as the former is more explicit about the intent of the annotation. This is
|
/// clearer name in these contexts, since it makes little sense to talk about a
|
||||||
/// a purely stylistic choice, as the two are semantically equivalent.
|
/// parameter annotation "not returning".
|
||||||
|
///
|
||||||
|
/// This is a purely stylistic lint: the two types have identical semantics for
|
||||||
|
/// type checkers. Both represent Python's "[bottom type]" (a type that has no
|
||||||
|
/// members).
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// from typing import NoReturn
|
/// from typing import NoReturn
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// def foo(x: NoReturn): ...
|
/// def foo(x: NoReturn): ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -29,13 +32,14 @@ use crate::settings::types::PythonVersion::Py311;
|
||||||
/// ```python
|
/// ```python
|
||||||
/// from typing import Never
|
/// from typing import Never
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// def foo(x: Never): ...
|
/// def foo(x: Never): ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: `typing.Never`](https://docs.python.org/3/library/typing.html#typing.Never)
|
/// - [Python documentation: `typing.Never`](https://docs.python.org/3/library/typing.html#typing.Never)
|
||||||
/// - [Python documentation: `typing.NoReturn`](https://docs.python.org/3/library/typing.html#typing.NoReturn)
|
/// - [Python documentation: `typing.NoReturn`](https://docs.python.org/3/library/typing.html#typing.NoReturn)
|
||||||
|
///
|
||||||
|
/// [bottom type]: https://en.wikipedia.org/wiki/Bottom_type
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct NoReturnArgumentAnnotationInStub {
|
pub struct NoReturnArgumentAnnotationInStub {
|
||||||
module: TypingModule,
|
module: TypingModule,
|
||||||
|
|
|
@ -10,9 +10,9 @@ use crate::checkers::ast::Checker;
|
||||||
/// Checks for non-empty function stub bodies.
|
/// Checks for non-empty function stub bodies.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Stub files are meant to be used as a reference for the interface of a
|
/// Stub files are never executed at runtime; they should be thought of as
|
||||||
/// module, and should not contain any implementation details. Thus, the
|
/// "data files" for type checkers or IDEs. Function bodies are redundant
|
||||||
/// body of a stub function should be empty.
|
/// for this purpose.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -26,7 +26,8 @@ use crate::checkers::ast::Checker;
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [PEP 484 – Type Hints: Stub Files](https://www.python.org/dev/peps/pep-0484/#stub-files)
|
/// - [The recommended style for stub functions and methods](https://typing.readthedocs.io/en/latest/source/stubs.html#id6)
|
||||||
|
/// in the typing docs.
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct NonEmptyStubBody;
|
pub struct NonEmptyStubBody;
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ use ruff_python_semantic::{ScopeKind, SemanticModel};
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for methods that are annotated with a fixed return type, which
|
/// Checks for methods that are annotated with a fixed return type which
|
||||||
/// should instead be returning `self`.
|
/// should instead be returning `Self`.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// If methods like `__new__` or `__enter__` are annotated with a fixed return
|
/// If methods that generally return `self` at runtime are annotated with a
|
||||||
/// type, and the class is subclassed, type checkers will not be able to infer
|
/// fixed return type, and the class is subclassed, type checkers will not be
|
||||||
/// the correct return type.
|
/// able to infer the correct return type.
|
||||||
///
|
///
|
||||||
/// For example:
|
/// For example:
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -30,7 +30,7 @@ use crate::checkers::ast::Checker;
|
||||||
/// self.radius = radius
|
/// self.radius = radius
|
||||||
/// return self
|
/// return self
|
||||||
///
|
///
|
||||||
/// # This returns `Shape`, not `Circle`.
|
/// # Type checker infers return type as `Shape`, not `Circle`.
|
||||||
/// Circle().set_scale(0.5)
|
/// Circle().set_scale(0.5)
|
||||||
///
|
///
|
||||||
/// # Thus, this expression is invalid, as `Shape` has no attribute `set_radius`.
|
/// # Thus, this expression is invalid, as `Shape` has no attribute `set_radius`.
|
||||||
|
@ -40,7 +40,7 @@ use crate::checkers::ast::Checker;
|
||||||
/// Specifically, this check enforces that the return type of the following
|
/// Specifically, this check enforces that the return type of the following
|
||||||
/// methods is `Self`:
|
/// methods is `Self`:
|
||||||
///
|
///
|
||||||
/// 1. In-place binary operations, like `__iadd__`, `__imul__`, etc.
|
/// 1. In-place binary-operation dunder methods, like `__iadd__`, `__imul__`, etc.
|
||||||
/// 1. `__new__`, `__enter__`, and `__aenter__`, if those methods return the
|
/// 1. `__new__`, `__enter__`, and `__aenter__`, if those methods return the
|
||||||
/// class name.
|
/// class name.
|
||||||
/// 1. `__iter__` methods that return `Iterator`, despite the class inheriting
|
/// 1. `__iter__` methods that return `Iterator`, despite the class inheriting
|
||||||
|
@ -51,16 +51,16 @@ use crate::checkers::ast::Checker;
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// class Foo:
|
/// class Foo:
|
||||||
/// def __new__(cls, *args: Any, **kwargs: Any) -> Bad:
|
/// def __new__(cls, *args: Any, **kwargs: Any) -> Foo:
|
||||||
/// ...
|
/// ...
|
||||||
///
|
///
|
||||||
/// def __enter__(self) -> Bad:
|
/// def __enter__(self) -> Foo:
|
||||||
/// ...
|
/// ...
|
||||||
///
|
///
|
||||||
/// async def __aenter__(self) -> Bad:
|
/// async def __aenter__(self) -> Foo:
|
||||||
/// ...
|
/// ...
|
||||||
///
|
///
|
||||||
/// def __iadd__(self, other: Bad) -> Bad:
|
/// def __iadd__(self, other: Foo) -> Foo:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -79,11 +79,11 @@ use crate::checkers::ast::Checker;
|
||||||
/// async def __aenter__(self) -> Self:
|
/// async def __aenter__(self) -> Self:
|
||||||
/// ...
|
/// ...
|
||||||
///
|
///
|
||||||
/// def __iadd__(self, other: Bad) -> Self:
|
/// def __iadd__(self, other: Foo) -> Self:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [PEP 673](https://peps.python.org/pep-0673/)
|
/// - [`typing.Self` documentation](https://docs.python.org/3/library/typing.html#typing.Self)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct NonSelfReturnType {
|
pub struct NonSelfReturnType {
|
||||||
class_name: String,
|
class_name: String,
|
||||||
|
|
|
@ -12,14 +12,15 @@ use crate::checkers::ast::Checker;
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// If a function has a default value where the literal representation is
|
/// If a function has a default value where the literal representation is
|
||||||
/// greater than 50 characters, it is likely to be an implementation detail or
|
/// greater than 50 characters, the value is likely to be an implementation
|
||||||
/// a constant that varies depending on the system you're running on.
|
/// detail or a constant that varies depending on the system you're running on.
|
||||||
///
|
///
|
||||||
/// Consider replacing such constants with ellipses (`...`).
|
/// Default values like these should generally be omitted from stubs. Use
|
||||||
|
/// ellipses (`...`) instead.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// def foo(arg: int = 12345678901) -> None:
|
/// def foo(arg: int = 693568516352839939918568862861217771399698285293568) -> None:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
|
@ -7,31 +7,25 @@ use crate::checkers::ast::Checker;
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for the presence of the `pass` statement within a class body
|
/// Checks for the presence of the `pass` statement in non-empty class bodies
|
||||||
/// in a stub (`.pyi`) file.
|
/// in `.pyi` files.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// In stub files, class definitions are intended to provide type hints, but
|
/// The `pass` statement is always unnecessary in non-empty class bodies in
|
||||||
/// are never actually evaluated. As such, it's unnecessary to include a `pass`
|
/// stubs.
|
||||||
/// statement in a class body, since it has no effect.
|
|
||||||
///
|
|
||||||
/// Instead of `pass`, prefer `...` to indicate that the class body is empty
|
|
||||||
/// and adhere to common stub file conventions.
|
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// class MyClass:
|
/// class MyClass:
|
||||||
|
/// x: int
|
||||||
/// pass
|
/// pass
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// class MyClass:
|
/// class MyClass:
|
||||||
/// ...
|
/// x: int
|
||||||
/// ```
|
/// ```
|
||||||
///
|
|
||||||
/// ## References
|
|
||||||
/// - [Mypy documentation: Stub files](https://mypy.readthedocs.io/en/stable/stubs.html)
|
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct PassInClassBody;
|
pub struct PassInClassBody;
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,22 @@ use crate::checkers::ast::Checker;
|
||||||
/// Checks for `pass` statements in empty stub bodies.
|
/// Checks for `pass` statements in empty stub bodies.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// For consistency, empty stub bodies should contain `...` instead of `pass`.
|
/// For stylistic consistency, `...` should always be used rather than `pass`
|
||||||
///
|
/// in stub files.
|
||||||
/// Additionally, an ellipsis better conveys the intent of the stub body (that
|
|
||||||
/// the body has been implemented, but has been intentionally left blank to
|
|
||||||
/// document the interface).
|
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// def foo(bar: int) -> list[int]:
|
/// def foo(bar: int) -> list[int]: pass
|
||||||
/// pass
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// def foo(bar: int) -> list[int]: ...
|
/// def foo(bar: int) -> list[int]: ...
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## References
|
||||||
|
/// The [recommended style for functions and methods](https://typing.readthedocs.io/en/latest/source/stubs.html#functions-and-methods)
|
||||||
|
/// in the typing docs.
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct PassStatementStubBody;
|
pub struct PassStatementStubBody;
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,12 @@ impl fmt::Display for VarKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks that type `TypeVar`, `ParamSpec`, and `TypeVarTuple` definitions in
|
/// Checks that type `TypeVar`s, `ParamSpec`s, and `TypeVarTuple`s in stubs
|
||||||
/// stubs are prefixed with `_`.
|
/// have names prefixed with `_`.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// By prefixing type parameters with `_`, we can avoid accidentally exposing
|
/// Prefixing type parameters with `_` avoids accidentally exposing names
|
||||||
/// names internal to the stub.
|
/// internal to the stub.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
|
|
@ -9,10 +9,10 @@ use crate::checkers::ast::Checker;
|
||||||
/// Checks for quoted type annotations in stub (`.pyi`) files, which should be avoided.
|
/// Checks for quoted type annotations in stub (`.pyi`) files, which should be avoided.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Stub files are evaluated using `annotations` semantics, as if
|
/// Stub files natively support forward references in all contexts, as stubs
|
||||||
/// `from __future__ import annotations` were included in the file. As such,
|
/// are never executed at runtime. (They should be thought of as "data files"
|
||||||
/// quotes are never required for type annotations in stub files, and should be
|
/// for type checkers and IDEs.) As such, quotes are never required for type
|
||||||
/// omitted.
|
/// annotations in stub files, and should be omitted.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
@ -25,6 +25,9 @@ use crate::checkers::ast::Checker;
|
||||||
/// def function() -> int:
|
/// def function() -> int:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## References
|
||||||
|
/// - [Static Typing with Python: Type Stubs](https://typing.readthedocs.io/en/latest/source/stubs.html)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct QuotedAnnotationInStub;
|
pub struct QuotedAnnotationInStub;
|
||||||
|
|
||||||
|
|
|
@ -13,30 +13,28 @@ use crate::checkers::ast::Checker;
|
||||||
use crate::fix::snippet::SourceCodeSnippet;
|
use crate::fix::snippet::SourceCodeSnippet;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for the presence of redundant `Literal` types and builtin super
|
/// Checks for redundant unions between a `Literal` and a builtin supertype of
|
||||||
/// types in an union.
|
/// that `Literal`.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// The use of `Literal` types in a union with the builtin super type of one of
|
/// Using a `Literal` type in a union with its builtin supertype is redundant,
|
||||||
/// its literal members is redundant, as the super type is strictly more
|
/// as the supertype will be strictly more general than the `Literal` type.
|
||||||
/// general than the `Literal` type.
|
|
||||||
///
|
|
||||||
/// For example, `Literal["A"] | str` is equivalent to `str`, and
|
/// For example, `Literal["A"] | str` is equivalent to `str`, and
|
||||||
/// `Literal[1] | int` is equivalent to `int`, as `str` and `int` are the super
|
/// `Literal[1] | int` is equivalent to `int`, as `str` and `int` are the
|
||||||
/// types of `"A"` and `1` respectively.
|
/// supertypes of `"A"` and `1` respectively.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// from typing import Literal
|
/// from typing import Literal
|
||||||
///
|
///
|
||||||
/// A: Literal["A"] | str
|
/// x: Literal["A", b"B"] | str
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// from typing import Literal
|
/// from typing import Literal
|
||||||
///
|
///
|
||||||
/// A: Literal["A"]
|
/// x: Literal[b"B"] | str
|
||||||
/// ```
|
/// ```
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct RedundantLiteralUnion {
|
pub struct RedundantLiteralUnion {
|
||||||
|
|
|
@ -7,34 +7,41 @@ use ruff_text_size::Ranged;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for union annotations that contain redundant numeric types (e.g.,
|
/// Checks for parameter annotations that contain redundant unions between
|
||||||
/// `int | float`).
|
/// builtin numeric types (e.g., `int | float`).
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// In Python, `int` is a subtype of `float`, and `float` is a subtype of
|
/// The [typing specification] states:
|
||||||
/// `complex`. As such, a union that includes both `int` and `float` is
|
|
||||||
/// redundant, as it is equivalent to a union that only includes `float`.
|
|
||||||
///
|
///
|
||||||
/// For more, see [PEP 3141], which defines Python's "numeric tower".
|
/// > 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.
|
||||||
///
|
///
|
||||||
/// Unions with redundant elements are less readable than unions without them.
|
/// 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.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// def foo(x: float | int) -> None:
|
/// def foo(x: float | int | str) -> None:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// def foo(x: float) -> None:
|
/// def foo(x: float | str) -> None:
|
||||||
/// ...
|
/// ...
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: The numeric tower](https://docs.python.org/3/library/numbers.html#the-numeric-tower)
|
/// - [The typing specification](https://docs.python.org/3/library/numbers.html#the-numeric-tower)
|
||||||
|
/// - [PEP 484: The numeric tower](https://peps.python.org/pep-0484/#the-numeric-tower)
|
||||||
///
|
///
|
||||||
/// [PEP 3141]: https://peps.python.org/pep-3141/
|
/// [typing specification]: https://typing.readthedocs.io/en/latest/spec/special-types.html#special-cases-for-float-and-complex
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct RedundantNumericUnion {
|
pub struct RedundantNumericUnion {
|
||||||
redundancy: Redundancy,
|
redundancy: Redundancy,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue