mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 18:28:24 +00:00
Expand documentation around flake8-type-checking rules for SQLAlchemy (#6570)
## Summary Not addressing the root issue as much as improving the documentation. Closes https://github.com/astral-sh/ruff/issues/6510.
This commit is contained in:
parent
5ddf143cae
commit
cd634a9489
6 changed files with 85 additions and 17 deletions
12
crates/ruff/resources/test/fixtures/flake8_type_checking/runtime_evaluated_base_classes_4.py
vendored
Normal file
12
crates/ruff/resources/test/fixtures/flake8_type_checking/runtime_evaluated_base_classes_4.py
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||
|
||||
|
||||
class Birthday(DeclarativeBase):
|
||||
|
||||
__tablename__ = "birthday"
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
day: Mapped[date]
|
|
@ -89,13 +89,20 @@ mod tests {
|
|||
Rule::TypingOnlyStandardLibraryImport,
|
||||
Path::new("runtime_evaluated_base_classes_3.py")
|
||||
)]
|
||||
#[test_case(
|
||||
Rule::TypingOnlyStandardLibraryImport,
|
||||
Path::new("runtime_evaluated_base_classes_4.py")
|
||||
)]
|
||||
fn runtime_evaluated_base_classes(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_type_checking").join(path).as_path(),
|
||||
&settings::Settings {
|
||||
flake8_type_checking: super::settings::Settings {
|
||||
runtime_evaluated_base_classes: vec!["pydantic.BaseModel".to_string()],
|
||||
runtime_evaluated_base_classes: vec![
|
||||
"pydantic.BaseModel".to_string(),
|
||||
"sqlalchemy.orm.DeclarativeBase".to_string(),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
..settings::Settings::for_rule(rule_code)
|
||||
|
|
|
@ -20,17 +20,25 @@ use crate::rules::isort::{categorize, ImportSection, ImportType};
|
|||
///
|
||||
/// ## Why is this bad?
|
||||
/// Unused imports add a performance overhead at runtime, and risk creating
|
||||
/// import cycles.
|
||||
/// import cycles. If an import is _only_ used in typing-only contexts, it can
|
||||
/// instead be imported conditionally under an `if TYPE_CHECKING:` block to
|
||||
/// minimize runtime overhead.
|
||||
///
|
||||
/// If a class _requires_ that type annotations be available at runtime (as is
|
||||
/// the case for Pydantic, SQLAlchemy, and other libraries), consider using
|
||||
/// the [`flake8-type-checking.runtime-evaluated-base-classes`] and
|
||||
/// [`flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
|
||||
/// as such.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// from __future__ import annotations
|
||||
///
|
||||
/// import A
|
||||
/// import local_module
|
||||
///
|
||||
///
|
||||
/// def foo(a: A) -> int:
|
||||
/// return len(a)
|
||||
/// def func(sized: local_module.Container) -> int:
|
||||
/// return len(sized)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
|
@ -40,13 +48,17 @@ use crate::rules::isort::{categorize, ImportSection, ImportType};
|
|||
/// from typing import TYPE_CHECKING
|
||||
///
|
||||
/// if TYPE_CHECKING:
|
||||
/// import A
|
||||
/// import local_module
|
||||
///
|
||||
///
|
||||
/// def foo(a: A) -> int:
|
||||
/// return len(a)
|
||||
/// def func(sized: local_module.Container) -> int:
|
||||
/// return len(sized)
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `flake8-type-checking.runtime-evaluated-base-classes`
|
||||
/// - `flake8-type-checking.runtime-evaluated-decorators`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
|
||||
#[violation]
|
||||
|
@ -76,7 +88,15 @@ impl Violation for TypingOnlyFirstPartyImport {
|
|||
///
|
||||
/// ## Why is this bad?
|
||||
/// Unused imports add a performance overhead at runtime, and risk creating
|
||||
/// import cycles.
|
||||
/// import cycles. If an import is _only_ used in typing-only contexts, it can
|
||||
/// instead be imported conditionally under an `if TYPE_CHECKING:` block to
|
||||
/// minimize runtime overhead.
|
||||
///
|
||||
/// If a class _requires_ that type annotations be available at runtime (as is
|
||||
/// the case for Pydantic, SQLAlchemy, and other libraries), consider using
|
||||
/// the [`flake8-type-checking.runtime-evaluated-base-classes`] and
|
||||
/// [`flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
|
||||
/// as such.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
@ -85,7 +105,7 @@ impl Violation for TypingOnlyFirstPartyImport {
|
|||
/// import pandas as pd
|
||||
///
|
||||
///
|
||||
/// def foo(df: pd.DataFrame) -> int:
|
||||
/// def func(df: pd.DataFrame) -> int:
|
||||
/// return len(df)
|
||||
/// ```
|
||||
///
|
||||
|
@ -99,10 +119,14 @@ impl Violation for TypingOnlyFirstPartyImport {
|
|||
/// import pandas as pd
|
||||
///
|
||||
///
|
||||
/// def foo(df: pd.DataFrame) -> int:
|
||||
/// def func(df: pd.DataFrame) -> int:
|
||||
/// return len(df)
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `flake8-type-checking.runtime-evaluated-base-classes`
|
||||
/// - `flake8-type-checking.runtime-evaluated-decorators`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
|
||||
#[violation]
|
||||
|
@ -132,7 +156,15 @@ impl Violation for TypingOnlyThirdPartyImport {
|
|||
///
|
||||
/// ## Why is this bad?
|
||||
/// Unused imports add a performance overhead at runtime, and risk creating
|
||||
/// import cycles.
|
||||
/// import cycles. If an import is _only_ used in typing-only contexts, it can
|
||||
/// instead be imported conditionally under an `if TYPE_CHECKING:` block to
|
||||
/// minimize runtime overhead.
|
||||
///
|
||||
/// If a class _requires_ that type annotations be available at runtime (as is
|
||||
/// the case for Pydantic, SQLAlchemy, and other libraries), consider using
|
||||
/// the [`flake8-type-checking.runtime-evaluated-base-classes`] and
|
||||
/// [`flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
|
||||
/// as such.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
|
@ -141,7 +173,7 @@ impl Violation for TypingOnlyThirdPartyImport {
|
|||
/// from pathlib import Path
|
||||
///
|
||||
///
|
||||
/// def foo(path: Path) -> str:
|
||||
/// def func(path: Path) -> str:
|
||||
/// return str(path)
|
||||
/// ```
|
||||
///
|
||||
|
@ -155,10 +187,14 @@ impl Violation for TypingOnlyThirdPartyImport {
|
|||
/// from pathlib import Path
|
||||
///
|
||||
///
|
||||
/// def foo(path: Path) -> str:
|
||||
/// def func(path: Path) -> str:
|
||||
/// return str(path)
|
||||
/// ```
|
||||
///
|
||||
/// ## Options
|
||||
/// - `flake8-type-checking.runtime-evaluated-base-classes`
|
||||
/// - `flake8-type-checking.runtime-evaluated-decorators`
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
|
||||
#[violation]
|
||||
|
|
|
@ -23,6 +23,7 @@ pub struct Options {
|
|||
)]
|
||||
/// Enforce TC001, TC002, and TC003 rules even when valid runtime imports
|
||||
/// are present for the same module.
|
||||
///
|
||||
/// See flake8-type-checking's [strict](https://github.com/snok/flake8-type-checking#strict) option.
|
||||
pub strict: Option<bool>,
|
||||
#[option(
|
||||
|
@ -39,11 +40,19 @@ pub struct Options {
|
|||
default = "[]",
|
||||
value_type = "list[str]",
|
||||
example = r#"
|
||||
runtime-evaluated-base-classes = ["pydantic.BaseModel"]
|
||||
runtime-evaluated-base-classes = ["pydantic.BaseModel", "sqlalchemy.orm.DeclarativeBase"]
|
||||
"#
|
||||
)]
|
||||
/// Exempt classes that list any of the enumerated classes as a base class
|
||||
/// from needing to be moved into type-checking blocks.
|
||||
///
|
||||
/// Common examples include Pydantic's `pydantic.BaseModel` and SQLAlchemy's
|
||||
/// `sqlalchemy.orm.DeclarativeBase`, but can also support user-defined
|
||||
/// classes that inherit from those base classes. For example, if you define
|
||||
/// a common `DeclarativeBase` subclass that's used throughout your project
|
||||
/// (e.g., `class Base(DeclarativeBase) ...` in `base.py`), you can add it to
|
||||
/// this list (`runtime-evaluated-base-classes = ["base.Base"]`) to exempt
|
||||
/// models from being moved into type-checking blocks.
|
||||
pub runtime_evaluated_base_classes: Option<Vec<String>>,
|
||||
#[option(
|
||||
default = "[]",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||
---
|
||||
|
4
ruff.schema.json
generated
4
ruff.schema.json
generated
|
@ -1090,7 +1090,7 @@
|
|||
}
|
||||
},
|
||||
"runtime-evaluated-base-classes": {
|
||||
"description": "Exempt classes that list any of the enumerated classes as a base class from needing to be moved into type-checking blocks.",
|
||||
"description": "Exempt classes that list any of the enumerated classes as a base class from needing to be moved into type-checking blocks.\n\nCommon examples include Pydantic's `pydantic.BaseModel` and SQLAlchemy's `sqlalchemy.orm.DeclarativeBase`, but can also support user-defined classes that inherit from those base classes. For example, if you define a common `DeclarativeBase` subclass that's used throughout your project (e.g., `class Base(DeclarativeBase) ...` in `base.py`), you can add it to this list (`runtime-evaluated-base-classes = [\"base.Base\"]`) to exempt models from being moved into type-checking blocks.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
|
@ -1110,7 +1110,7 @@
|
|||
}
|
||||
},
|
||||
"strict": {
|
||||
"description": "Enforce TC001, TC002, and TC003 rules even when valid runtime imports are present for the same module. See flake8-type-checking's [strict](https://github.com/snok/flake8-type-checking#strict) option.",
|
||||
"description": "Enforce TC001, TC002, and TC003 rules even when valid runtime imports are present for the same module.\n\nSee flake8-type-checking's [strict](https://github.com/snok/flake8-type-checking#strict) option.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue