Compare commits
38 Commits
0.11.11
...
david/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49c077d5d4 | ||
|
|
4e68dd96a6 | ||
|
|
b25b642371 | ||
|
|
175402aa75 | ||
|
|
d8216fa328 | ||
|
|
d51f6940fe | ||
|
|
66b082ff71 | ||
|
|
5d93d619f3 | ||
|
|
e1b662bf5d | ||
|
|
f885cb8a2f | ||
|
|
4ef2c223c9 | ||
|
|
d078ecff37 | ||
|
|
7eca6f96e3 | ||
|
|
fbaf826a9d | ||
|
|
d8a5b9de17 | ||
|
|
c3feb8ce27 | ||
|
|
97ff015c88 | ||
|
|
1f7134f727 | ||
|
|
6a0b93170e | ||
|
|
cc59ff8aad | ||
|
|
2b90e7fcd7 | ||
|
|
a43f5b2129 | ||
|
|
f3fb7429ca | ||
|
|
83498b95fb | ||
|
|
03d7be3747 | ||
|
|
d95b029862 | ||
|
|
14c3755445 | ||
|
|
83a036960b | ||
|
|
be76fadb05 | ||
|
|
e293411679 | ||
|
|
53d19f8368 | ||
|
|
a1399656c9 | ||
|
|
6392dccd24 | ||
|
|
93ac0934dd | ||
|
|
aae4482c55 | ||
|
|
d02c9ada5d | ||
|
|
6c0a59ea78 | ||
|
|
0b181bc2ad |
32
.github/workflows/ci.yaml
vendored
32
.github/workflows/ci.yaml
vendored
@@ -237,13 +237,13 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install mold"
|
||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
||||
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||
- name: "Install cargo nextest"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-nextest
|
||||
- name: "Install cargo insta"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-insta
|
||||
- name: ty mdtests (GitHub annotations)
|
||||
@@ -295,13 +295,13 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install mold"
|
||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
||||
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||
- name: "Install cargo nextest"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-nextest
|
||||
- name: "Install cargo insta"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-insta
|
||||
- name: "Run tests"
|
||||
@@ -324,7 +324,7 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install cargo nextest"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-nextest
|
||||
- name: "Run tests"
|
||||
@@ -380,7 +380,7 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install mold"
|
||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
||||
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||
- name: "Build"
|
||||
run: cargo build --release --locked
|
||||
|
||||
@@ -405,13 +405,13 @@ jobs:
|
||||
MSRV: ${{ steps.msrv.outputs.value }}
|
||||
run: rustup default "${MSRV}"
|
||||
- name: "Install mold"
|
||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
||||
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||
- name: "Install cargo nextest"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-nextest
|
||||
- name: "Install cargo insta"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-insta
|
||||
- name: "Run tests"
|
||||
@@ -459,7 +459,7 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
name: Download Ruff binary to test
|
||||
id: download-cached-binary
|
||||
@@ -660,7 +660,7 @@ jobs:
|
||||
branch: ${{ github.event.pull_request.base.ref }}
|
||||
workflow: "ci.yaml"
|
||||
check_artifacts: true
|
||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||
- name: Fuzz
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
@@ -730,7 +730,7 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
@@ -773,7 +773,7 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||
- name: "Install Insiders dependencies"
|
||||
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
|
||||
run: uv pip install -r docs/requirements-insiders.txt --system
|
||||
@@ -910,7 +910,7 @@ jobs:
|
||||
run: rustup show
|
||||
|
||||
- name: "Install codspeed"
|
||||
uses: taiki-e/install-action@941e8a4d9d7cdb696bd4f017cf54aca281f8ffff # v2.51.2
|
||||
uses: taiki-e/install-action@6c6479b49816fcc0975a31af977bdc1f847c2920 # v2.52.1
|
||||
with:
|
||||
tool: cargo-codspeed
|
||||
|
||||
|
||||
4
.github/workflows/daily_fuzz.yaml
vendored
4
.github/workflows/daily_fuzz.yaml
vendored
@@ -34,11 +34,11 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
- uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install mold"
|
||||
uses: rui314/setup-mold@e16410e7f8d9e167b74ad5697a9089a35126eb50 # v1
|
||||
uses: rui314/setup-mold@67424c1b3680e35255d95971cbd5de0047bf31c3 # v1
|
||||
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||
- name: Build ruff
|
||||
# A debug build means the script runs slower once it gets started,
|
||||
|
||||
2
.github/workflows/mypy_primer.yaml
vendored
2
.github/workflows/mypy_primer.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||
|
||||
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||
with:
|
||||
|
||||
2
.github/workflows/publish-pypi.yml
vendored
2
.github/workflows/publish-pypi.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: "Install uv"
|
||||
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
|
||||
uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
pattern: wheels-*
|
||||
|
||||
@@ -80,7 +80,7 @@ repos:
|
||||
pass_filenames: false # This makes it a lot faster
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.10
|
||||
rev: v0.11.11
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
- id: ruff
|
||||
@@ -98,7 +98,7 @@ repos:
|
||||
# zizmor detects security vulnerabilities in GitHub Actions workflows.
|
||||
# Additional configuration for the tool is found in `.github/zizmor.yml`
|
||||
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
||||
rev: v1.7.0
|
||||
rev: v1.8.0
|
||||
hooks:
|
||||
- id: zizmor
|
||||
|
||||
|
||||
35
Cargo.lock
generated
35
Cargo.lock
generated
@@ -486,7 +486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -495,7 +495,7 @@ version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -909,7 +909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1444,7 +1444,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
|
||||
dependencies = [
|
||||
"hermit-abi 0.5.1",
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1498,9 +1498,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
|
||||
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"jiff-tzdb-platform",
|
||||
@@ -1508,14 +1508,14 @@ dependencies = [
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
|
||||
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3081,6 +3081,7 @@ dependencies = [
|
||||
"ruff_workspace",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"uuid",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
@@ -3162,7 +3163,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3531,7 +3532,7 @@ dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4003,6 +4004,7 @@ dependencies = [
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"rustc-hash 2.1.1",
|
||||
"salsa",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
@@ -4071,6 +4073,7 @@ dependencies = [
|
||||
"ty_ide",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
"uuid",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
@@ -4240,9 +4243,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"js-sys",
|
||||
@@ -4253,9 +4256,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uuid-macro-internal"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72dcd78c4f979627a754f5522cea6e6a25e55139056535fe6e69c506cd64a862"
|
||||
checksum = "26b682e8c381995ea03130e381928e0e005b7c9eb483c6c8682f50e07b33c2b7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4523,7 +4526,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -179,7 +179,6 @@ uuid = { version = "1.6.1", features = [
|
||||
"v4",
|
||||
"fast-rng",
|
||||
"macro-diagnostics",
|
||||
"js",
|
||||
] }
|
||||
walkdir = { version = "2.3.2" }
|
||||
wasm-bindgen = { version = "0.2.92" }
|
||||
@@ -188,7 +187,7 @@ wild = { version = "2" }
|
||||
zip = { version = "0.6.6", default-features = false }
|
||||
|
||||
[workspace.metadata.cargo-shear]
|
||||
ignored = ["getrandom", "ruff_options_metadata"]
|
||||
ignored = ["getrandom", "ruff_options_metadata", "uuid"]
|
||||
|
||||
|
||||
[workspace.lints.rust]
|
||||
|
||||
@@ -34,8 +34,7 @@ An extremely fast Python linter and code formatter, written in Rust.
|
||||
- 🔧 Fix support, for automatic error correction (e.g., automatically remove unused imports)
|
||||
- 📏 Over [800 built-in rules](https://docs.astral.sh/ruff/rules/), with native re-implementations
|
||||
of popular Flake8 plugins, like flake8-bugbear
|
||||
- ⌨️ First-party [editor integrations](https://docs.astral.sh/ruff/integrations/) for
|
||||
[VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://docs.astral.sh/ruff/editors/setup)
|
||||
- ⌨️ First-party [editor integrations](https://docs.astral.sh/ruff/editors) for [VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://docs.astral.sh/ruff/editors/setup)
|
||||
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://docs.astral.sh/ruff/configuration/#config-file-discovery)
|
||||
|
||||
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
|
||||
|
||||
@@ -131,7 +131,7 @@ fn benchmark_incremental(criterion: &mut Criterion) {
|
||||
fn setup() -> Case {
|
||||
let case = setup_tomllib_case();
|
||||
|
||||
let result: Vec<_> = case.db.check().unwrap();
|
||||
let result: Vec<_> = case.db.check();
|
||||
|
||||
assert_diagnostics(&case.db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
|
||||
|
||||
@@ -159,7 +159,7 @@ fn benchmark_incremental(criterion: &mut Criterion) {
|
||||
None,
|
||||
);
|
||||
|
||||
let result = db.check().unwrap();
|
||||
let result = db.check();
|
||||
|
||||
assert_eq!(result.len(), EXPECTED_TOMLLIB_DIAGNOSTICS.len());
|
||||
}
|
||||
@@ -179,7 +179,7 @@ fn benchmark_cold(criterion: &mut Criterion) {
|
||||
setup_tomllib_case,
|
||||
|case| {
|
||||
let Case { db, .. } = case;
|
||||
let result: Vec<_> = db.check().unwrap();
|
||||
let result: Vec<_> = db.check();
|
||||
|
||||
assert_diagnostics(db, &result, EXPECTED_TOMLLIB_DIAGNOSTICS);
|
||||
},
|
||||
@@ -293,7 +293,7 @@ fn benchmark_many_string_assignments(criterion: &mut Criterion) {
|
||||
},
|
||||
|case| {
|
||||
let Case { db, .. } = case;
|
||||
let result = db.check().unwrap();
|
||||
let result = db.check();
|
||||
assert_eq!(result.len(), 0);
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
@@ -339,7 +339,7 @@ fn benchmark_many_tuple_assignments(criterion: &mut Criterion) {
|
||||
},
|
||||
|case| {
|
||||
let Case { db, .. } = case;
|
||||
let result = db.check().unwrap();
|
||||
let result = db.check();
|
||||
assert_eq!(result.len(), 0);
|
||||
},
|
||||
BatchSize::SmallInput,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::any::Any;
|
||||
use std::backtrace::BacktraceStatus;
|
||||
use std::cell::Cell;
|
||||
use std::panic::Location;
|
||||
@@ -24,17 +25,25 @@ impl Payload {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn downcast_ref<R: Any>(&self) -> Option<&R> {
|
||||
self.0.downcast_ref::<R>()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PanicError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "panicked at")?;
|
||||
write!(f, "panicked at")?;
|
||||
if let Some(location) = &self.location {
|
||||
write!(f, " {location}")?;
|
||||
}
|
||||
if let Some(payload) = self.payload.as_str() {
|
||||
write!(f, ":\n{payload}")?;
|
||||
}
|
||||
if let Some(query_trace) = self.salsa_backtrace.as_ref() {
|
||||
let _ = writeln!(f, "{query_trace}");
|
||||
}
|
||||
|
||||
if let Some(backtrace) = &self.backtrace {
|
||||
match backtrace.status() {
|
||||
BacktraceStatus::Disabled => {
|
||||
@@ -49,6 +58,7 @@ impl std::fmt::Display for PanicError {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,44 +18,43 @@ const FIX_SYMBOL: &str = "🛠️";
|
||||
const PREVIEW_SYMBOL: &str = "🧪";
|
||||
const REMOVED_SYMBOL: &str = "❌";
|
||||
const WARNING_SYMBOL: &str = "⚠️";
|
||||
const STABLE_SYMBOL: &str = "✔️";
|
||||
const SPACER: &str = " ";
|
||||
|
||||
/// Style for the rule's fixability and status icons.
|
||||
const SYMBOL_STYLE: &str = "style='width: 1em; display: inline-block;'";
|
||||
/// Style for the container wrapping the fixability and status icons.
|
||||
const SYMBOLS_CONTAINER: &str = "style='display: flex; gap: 0.5rem; justify-content: end;'";
|
||||
|
||||
fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>, linter: &Linter) {
|
||||
table_out.push_str("| Code | Name | Message | |");
|
||||
table_out.push_str("| Code | Name | Message | |");
|
||||
table_out.push('\n');
|
||||
table_out.push_str("| ---- | ---- | ------- | ------: |");
|
||||
table_out.push_str("| ---- | ---- | ------- | -: |");
|
||||
table_out.push('\n');
|
||||
for rule in rules {
|
||||
let status_token = match rule.group() {
|
||||
RuleGroup::Removed => {
|
||||
format!("<span title='Rule has been removed'>{REMOVED_SYMBOL}</span>")
|
||||
format!(
|
||||
"<span {SYMBOL_STYLE} title='Rule has been removed'>{REMOVED_SYMBOL}</span>"
|
||||
)
|
||||
}
|
||||
RuleGroup::Deprecated => {
|
||||
format!("<span title='Rule has been deprecated'>{WARNING_SYMBOL}</span>")
|
||||
format!(
|
||||
"<span {SYMBOL_STYLE} title='Rule has been deprecated'>{WARNING_SYMBOL}</span>"
|
||||
)
|
||||
}
|
||||
RuleGroup::Preview => {
|
||||
format!("<span title='Rule is in preview'>{PREVIEW_SYMBOL}</span>")
|
||||
}
|
||||
RuleGroup::Stable => {
|
||||
// A full opacity checkmark is a bit aggressive for indicating stable
|
||||
format!("<span title='Rule is stable' style='opacity: 0.6'>{STABLE_SYMBOL}</span>")
|
||||
format!("<span {SYMBOL_STYLE} title='Rule is in preview'>{PREVIEW_SYMBOL}</span>")
|
||||
}
|
||||
RuleGroup::Stable => format!("<span {SYMBOL_STYLE}></span>"),
|
||||
};
|
||||
|
||||
let fix_token = match rule.fixable() {
|
||||
FixAvailability::Always | FixAvailability::Sometimes => {
|
||||
format!("<span title='Automatic fix available'>{FIX_SYMBOL}</span>")
|
||||
}
|
||||
FixAvailability::None => {
|
||||
format!(
|
||||
"<span title='Automatic fix not available' style='opacity: 0.1' aria-hidden='true'>{FIX_SYMBOL}</span>"
|
||||
)
|
||||
format!("<span {SYMBOL_STYLE} title='Automatic fix available'>{FIX_SYMBOL}</span>")
|
||||
}
|
||||
FixAvailability::None => format!("<span {SYMBOL_STYLE}></span>"),
|
||||
};
|
||||
|
||||
let tokens = format!("{status_token} {fix_token}");
|
||||
|
||||
let rule_name = rule.as_ref();
|
||||
|
||||
// If the message ends in a bracketed expression (like: "Use {replacement}"), escape the
|
||||
@@ -82,15 +81,14 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
|
||||
#[expect(clippy::or_fun_call)]
|
||||
let _ = write!(
|
||||
table_out,
|
||||
"| {ss}{0}{1}{se} {{ #{0}{1} }} | {ss}{2}{se} | {ss}{3}{se} | {ss}{4}{se} |",
|
||||
linter.common_prefix(),
|
||||
linter.code_for_rule(rule).unwrap(),
|
||||
rule.explanation()
|
||||
"| {ss}{prefix}{code}{se} {{ #{prefix}{code} }} | {ss}{explanation}{se} | {ss}{message}{se} | <div {SYMBOLS_CONTAINER}>{status_token}{fix_token}</div>|",
|
||||
prefix = linter.common_prefix(),
|
||||
code = linter.code_for_rule(rule).unwrap(),
|
||||
explanation = rule
|
||||
.explanation()
|
||||
.is_some()
|
||||
.then_some(format_args!("[{rule_name}](rules/{rule_name}.md)"))
|
||||
.unwrap_or(format_args!("{rule_name}")),
|
||||
message,
|
||||
tokens,
|
||||
);
|
||||
table_out.push('\n');
|
||||
}
|
||||
@@ -104,12 +102,6 @@ pub(crate) fn generate() -> String {
|
||||
table_out.push_str("### Legend");
|
||||
table_out.push('\n');
|
||||
|
||||
let _ = write!(
|
||||
&mut table_out,
|
||||
"{SPACER}{STABLE_SYMBOL}{SPACER} The rule is stable."
|
||||
);
|
||||
table_out.push_str("<br />");
|
||||
|
||||
let _ = write!(
|
||||
&mut table_out,
|
||||
"{SPACER}{PREVIEW_SYMBOL}{SPACER} The rule is unstable and is in [\"preview\"](faq.md#what-is-preview)."
|
||||
@@ -132,7 +124,8 @@ pub(crate) fn generate() -> String {
|
||||
&mut table_out,
|
||||
"{SPACER}{FIX_SYMBOL}{SPACER} The rule is automatically fixable by the `--fix` command-line option."
|
||||
);
|
||||
table_out.push_str("<br />");
|
||||
table_out.push_str("\n\n");
|
||||
table_out.push_str("All rules not marked as preview, deprecated or removed are stable.");
|
||||
table_out.push('\n');
|
||||
|
||||
for linter in Linter::iter() {
|
||||
|
||||
@@ -80,6 +80,7 @@ fn generate() -> String {
|
||||
|
||||
let mut parents = Vec::new();
|
||||
|
||||
output.push_str("<!-- WARNING: This file is auto-generated (cargo dev generate-all). Edit the doc comments in 'crates/ty/src/args.rs' if you want to change anything here. -->\n\n");
|
||||
output.push_str("# CLI Reference\n\n");
|
||||
generate_command(&mut output, &ty, &mut parents);
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ pub(crate) fn main(args: &Args) -> anyhow::Result<()> {
|
||||
let file_name = "crates/ty/docs/configuration.md";
|
||||
let markdown_path = PathBuf::from(ROOT_DIR).join(file_name);
|
||||
|
||||
output.push_str(
|
||||
"<!-- WARNING: This file is auto-generated (cargo dev generate-all). Update the doc comments on the 'Options' struct in 'crates/ty_project/src/metadata/options.rs' if you want to change anything here. -->\n\n",
|
||||
);
|
||||
|
||||
generate_set(
|
||||
&mut output,
|
||||
Set::Toplevel(Options::metadata()),
|
||||
|
||||
@@ -56,6 +56,10 @@ fn generate_markdown() -> String {
|
||||
|
||||
let mut output = String::new();
|
||||
|
||||
let _ = writeln!(
|
||||
&mut output,
|
||||
"<!-- WARNING: This file is auto-generated (cargo dev generate-all). Edit the lint-declarations in 'crates/ty_python_semantic/src/types/diagnostic.rs' if you want to change anything here. -->\n"
|
||||
);
|
||||
let _ = writeln!(&mut output, "# Rules\n");
|
||||
|
||||
let mut lints: Vec<_> = registry.lints().iter().collect();
|
||||
|
||||
@@ -114,16 +114,11 @@ from airflow.sensors.sql_sensor import SqlSensor
|
||||
SqlSensor()
|
||||
|
||||
|
||||
from airflow.operators.jdbc_operator import JdbcOperator
|
||||
from airflow.operators.mssql_operator import MsSqlOperator
|
||||
from airflow.operators.mysql_operator import MySqlOperator
|
||||
from airflow.operators.oracle_operator import OracleOperator
|
||||
from airflow.operators.postgres_operator import PostgresOperator
|
||||
from airflow.operators.sqlite_operator import SqliteOperator
|
||||
from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||
|
||||
JdbcOperator()
|
||||
MsSqlOperator()
|
||||
MySqlOperator()
|
||||
OracleOperator()
|
||||
PostgresOperator()
|
||||
SqliteOperator()
|
||||
SQLExecuteQueryOperator()
|
||||
SQLExecuteQueryOperator()
|
||||
SQLExecuteQueryOperator()
|
||||
SQLExecuteQueryOperator()
|
||||
SQLExecuteQueryOperator()
|
||||
SQLExecuteQueryOperator()
|
||||
|
||||
@@ -145,3 +145,23 @@ def func():
|
||||
sleep = 10
|
||||
|
||||
anyio.run(main)
|
||||
|
||||
|
||||
async def test_anyio_async115_helpers():
|
||||
import anyio
|
||||
|
||||
await anyio.sleep(delay=1) # OK
|
||||
await anyio.sleep(seconds=1) # OK
|
||||
|
||||
await anyio.sleep(delay=0) # ASYNC115
|
||||
await anyio.sleep(seconds=0) # OK
|
||||
|
||||
|
||||
async def test_trio_async115_helpers():
|
||||
import trio
|
||||
|
||||
await trio.sleep(seconds=1) # OK
|
||||
await trio.sleep(delay=1) # OK
|
||||
|
||||
await trio.sleep(seconds=0) # ASYNC115
|
||||
await trio.sleep(delay=0) # OK
|
||||
|
||||
@@ -108,3 +108,23 @@ async def import_from_anyio():
|
||||
|
||||
# catch from import
|
||||
await sleep(86401) # error: 116, "async"
|
||||
|
||||
|
||||
async def test_anyio_async116_helpers():
|
||||
import anyio
|
||||
|
||||
await anyio.sleep(delay=1) # OK
|
||||
await anyio.sleep(seconds=1) # OK
|
||||
|
||||
await anyio.sleep(delay=86401) # ASYNC116
|
||||
await anyio.sleep(seconds=86401) # OK
|
||||
|
||||
|
||||
async def test_trio_async116_helpers():
|
||||
import trio
|
||||
|
||||
await trio.sleep(seconds=1) # OK
|
||||
await trio.sleep(delay=1) # OK
|
||||
|
||||
await trio.sleep(seconds=86401) # ASYNC116
|
||||
await trio.sleep(delay=86401) # OK
|
||||
|
||||
@@ -12,3 +12,4 @@ if True:
|
||||
if True:
|
||||
from __future__ import generator_stop
|
||||
from __future__ import invalid_module, generators
|
||||
from __future__ import generators # comment
|
||||
|
||||
@@ -65,24 +65,26 @@ impl Violation for Airflow3MovedToProvider {
|
||||
|
||||
fn fix_title(&self) -> Option<String> {
|
||||
let Airflow3MovedToProvider { replacement, .. } = self;
|
||||
match replacement {
|
||||
ProviderReplacement::None => None,
|
||||
if let Some((module, name, provider, version)) = match &replacement {
|
||||
ProviderReplacement::AutoImport {
|
||||
name,
|
||||
module,
|
||||
name,
|
||||
provider,
|
||||
version,
|
||||
} => Some(format!(
|
||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
||||
)),
|
||||
} => Some((module, *name, provider, version)),
|
||||
ProviderReplacement::SourceModuleMovedToProvider {
|
||||
name,
|
||||
module,
|
||||
name,
|
||||
provider,
|
||||
version,
|
||||
} => Some(format!(
|
||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
||||
)),
|
||||
} => Some((module, name.as_str(), provider, version)),
|
||||
ProviderReplacement::None => None,
|
||||
} {
|
||||
Some(format!(
|
||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{name}` from `{module}` instead."
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,10 +73,10 @@ impl Violation for Airflow3Removal {
|
||||
Replacement::AttrName(name) => Some(format!("Use `{name}` instead")),
|
||||
Replacement::Message(message) => Some((*message).to_string()),
|
||||
Replacement::AutoImport { module, name } => {
|
||||
Some(format!("Use `{module}.{name}` instead"))
|
||||
Some(format!("Use `{name}` from `{module}` instead."))
|
||||
}
|
||||
Replacement::SourceModuleMoved { module, name } => {
|
||||
Some(format!("Use `{module}.{name}` instead"))
|
||||
Some(format!("Use `{name}` from `{module}` instead."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ impl Violation for Airflow3SuggestedToMoveToProvider {
|
||||
provider,
|
||||
version,
|
||||
} => Some(format!(
|
||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{name}` from `{module}` instead."
|
||||
)),
|
||||
ProviderReplacement::SourceModuleMovedToProvider {
|
||||
module,
|
||||
@@ -85,7 +85,7 @@ impl Violation for Airflow3SuggestedToMoveToProvider {
|
||||
provider,
|
||||
version,
|
||||
} => Some(format!(
|
||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{module}.{name}` instead."
|
||||
"Install `apache-airflow-providers-{provider}>={version}` and use `{name}` from `{module}` instead."
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,10 +72,10 @@ impl Violation for Airflow3SuggestedUpdate {
|
||||
Replacement::AttrName(name) => Some(format!("Use `{name}` instead")),
|
||||
Replacement::Message(message) => Some((*message).to_string()),
|
||||
Replacement::AutoImport { module, name } => {
|
||||
Some(format!("Use `{module}.{name}` instead"))
|
||||
Some(format!("Use `{name}` from `{module}` instead."))
|
||||
}
|
||||
Replacement::SourceModuleMoved { module, name } => {
|
||||
Some(format!("Use `{module}.{name}` instead"))
|
||||
Some(format!("Use `{name}` from `{module}` instead."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ AIR301_class_attribute.py:42:6: AIR301 [*] `airflow.datasets.manager.DatasetMana
|
||||
43 | dm.register_dataset_change()
|
||||
44 | dm.create_datasets()
|
||||
|
|
||||
= help: Use `airflow.assets.manager.AssetManager` instead
|
||||
= help: Use `AssetManager` from `airflow.assets.manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | from airflow.providers_manager import ProvidersManager
|
||||
@@ -302,7 +302,7 @@ AIR301_class_attribute.py:50:11: AIR301 [*] `airflow.lineage.hook.DatasetLineage
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||
51 | dl_info.dataset
|
||||
|
|
||||
= help: Use `airflow.lineage.hook.AssetLineageInfo` instead
|
||||
= help: Use `AssetLineageInfo` from `airflow.lineage.hook` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
9 9 | DatasetAny,
|
||||
|
||||
@@ -85,7 +85,7 @@ AIR301_names.py:60:1: AIR301 [*] `airflow.configuration.get` is removed in Airfl
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.get` instead
|
||||
= help: Use `conf.get` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -111,7 +111,7 @@ AIR301_names.py:60:6: AIR301 [*] `airflow.configuration.getboolean` is removed i
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.getboolean` instead
|
||||
= help: Use `conf.getboolean` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -137,7 +137,7 @@ AIR301_names.py:60:18: AIR301 [*] `airflow.configuration.getfloat` is removed in
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.getfloat` instead
|
||||
= help: Use `conf.getfloat` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -163,7 +163,7 @@ AIR301_names.py:60:28: AIR301 [*] `airflow.configuration.getint` is removed in A
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.getint` instead
|
||||
= help: Use `conf.getint` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -189,7 +189,7 @@ AIR301_names.py:60:36: AIR301 [*] `airflow.configuration.has_option` is removed
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.has_option` instead
|
||||
= help: Use `conf.has_option` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -215,7 +215,7 @@ AIR301_names.py:60:48: AIR301 [*] `airflow.configuration.remove_option` is remov
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^^^^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.remove_option` instead
|
||||
= help: Use `conf.remove_option` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -241,7 +241,7 @@ AIR301_names.py:60:63: AIR301 [*] `airflow.configuration.as_dict` is removed in
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.as_dict` instead
|
||||
= help: Use `conf.as_dict` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -267,7 +267,7 @@ AIR301_names.py:60:72: AIR301 [*] `airflow.configuration.set` is removed in Airf
|
||||
60 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set
|
||||
| ^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.configuration.conf.set` instead
|
||||
= help: Use `conf.set` from `airflow.configuration` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | has_option,
|
||||
@@ -308,7 +308,7 @@ AIR301_names.py:72:1: AIR301 `airflow.hooks.base_hook.BaseHook` is removed in Ai
|
||||
72 | BaseHook()
|
||||
| ^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.hooks.base.BaseHook` instead
|
||||
= help: Use `BaseHook` from `airflow.hooks.base` instead.
|
||||
|
||||
AIR301_names.py:76:1: AIR301 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -324,7 +324,7 @@ AIR301_names.py:85:1: AIR301 `airflow.sensors.base_sensor_operator.BaseSensorOpe
|
||||
85 | BaseSensorOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.sdk.bases.sensor.BaseSensorOperator` instead
|
||||
= help: Use `BaseSensorOperator` from `airflow.sdk.bases.sensor` instead.
|
||||
|
||||
AIR301_names.py:89:1: AIR301 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -446,7 +446,7 @@ AIR301_names.py:117:1: AIR301 `airflow.utils.file.TemporaryDirectory` is removed
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||
118 | mkdirs
|
||||
|
|
||||
= help: Use `tempfile.TemporaryDirectory` instead
|
||||
= help: Use `TemporaryDirectory` from `tempfile` instead.
|
||||
|
||||
AIR301_names.py:118:1: AIR301 `airflow.utils.file.mkdirs` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -466,7 +466,7 @@ AIR301_names.py:121:1: AIR301 [*] `airflow.utils.helpers.chain` is removed in Ai
|
||||
| ^^^^^^^^^^^^ AIR301
|
||||
122 | helper_cross_downstream
|
||||
|
|
||||
= help: Use `airflow.sdk.chain` instead
|
||||
= help: Use `chain` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
48 48 | from airflow.utils.trigger_rule import TriggerRule
|
||||
@@ -495,7 +495,7 @@ AIR301_names.py:122:1: AIR301 [*] `airflow.utils.helpers.cross_downstream` is re
|
||||
123 |
|
||||
124 | # airflow.utils.log
|
||||
|
|
||||
= help: Use `airflow.sdk.cross_downstream` instead
|
||||
= help: Use `cross_downstream` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
48 48 | from airflow.utils.trigger_rule import TriggerRule
|
||||
@@ -523,7 +523,7 @@ AIR301_names.py:125:1: AIR301 `airflow.utils.log.secrets_masker` is removed in A
|
||||
126 |
|
||||
127 | # airflow.utils.state
|
||||
|
|
||||
= help: Use `airflow.sdk.execution_time.secrets_masker` instead
|
||||
= help: Use `secrets_masker` from `airflow.sdk.execution_time` instead.
|
||||
|
||||
AIR301_names.py:128:1: AIR301 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -595,7 +595,7 @@ AIR301_names.py:146:1: AIR301 `airflow.operators.python.get_current_context` is
|
||||
147 |
|
||||
148 | # airflow.providers.mysql
|
||||
|
|
||||
= help: Use `airflow.sdk.get_current_context` instead
|
||||
= help: Use `get_current_context` from `airflow.sdk` instead.
|
||||
|
||||
AIR301_names.py:151:1: AIR301 `airflow.providers.mysql.datasets.mysql.sanitize_uri` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -606,7 +606,7 @@ AIR301_names.py:151:1: AIR301 `airflow.providers.mysql.datasets.mysql.sanitize_u
|
||||
152 |
|
||||
153 | # airflow.providers.postgres
|
||||
|
|
||||
= help: Use `airflow.providers.mysql.assets.mysql.sanitize_uri` instead
|
||||
= help: Use `sanitize_uri` from `airflow.providers.mysql.assets.mysql` instead.
|
||||
|
||||
AIR301_names.py:156:1: AIR301 `airflow.providers.postgres.datasets.postgres.sanitize_uri` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -617,7 +617,7 @@ AIR301_names.py:156:1: AIR301 `airflow.providers.postgres.datasets.postgres.sani
|
||||
157 |
|
||||
158 | # airflow.providers.trino
|
||||
|
|
||||
= help: Use `airflow.providers.postgres.assets.postgres.sanitize_uri` instead
|
||||
= help: Use `sanitize_uri` from `airflow.providers.postgres.assets.postgres` instead.
|
||||
|
||||
AIR301_names.py:161:1: AIR301 `airflow.providers.trino.datasets.trino.sanitize_uri` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -628,7 +628,7 @@ AIR301_names.py:161:1: AIR301 `airflow.providers.trino.datasets.trino.sanitize_u
|
||||
162 |
|
||||
163 | # airflow.notifications.basenotifier
|
||||
|
|
||||
= help: Use `airflow.providers.trino.assets.trino.sanitize_uri` instead
|
||||
= help: Use `sanitize_uri` from `airflow.providers.trino.assets.trino` instead.
|
||||
|
||||
AIR301_names.py:166:1: AIR301 `airflow.notifications.basenotifier.BaseNotifier` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -639,7 +639,7 @@ AIR301_names.py:166:1: AIR301 `airflow.notifications.basenotifier.BaseNotifier`
|
||||
167 |
|
||||
168 | # airflow.auth.manager
|
||||
|
|
||||
= help: Use `airflow.sdk.bases.notifier.BaseNotifier` instead
|
||||
= help: Use `BaseNotifier` from `airflow.sdk.bases.notifier` instead.
|
||||
|
||||
AIR301_names.py:171:1: AIR301 `airflow.auth.managers.base_auth_manager.BaseAuthManager` is removed in Airflow 3.0
|
||||
|
|
||||
@@ -648,4 +648,4 @@ AIR301_names.py:171:1: AIR301 `airflow.auth.managers.base_auth_manager.BaseAuthM
|
||||
171 | BaseAuthManager()
|
||||
| ^^^^^^^^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.api_fastapi.auth.managers.base_auth_manager.BaseAuthManager` instead
|
||||
= help: Use `BaseAuthManager` from `airflow.api_fastapi.auth.managers.base_auth_manager` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR301_names_fix.py:19:1: AIR301 [*] `airflow.api_connexion.security.requires_ac
|
||||
20 |
|
||||
21 | DatasetDetails()
|
||||
|
|
||||
= help: Use `airflow.api_fastapi.core_api.security.requires_access_asset` instead
|
||||
= help: Use `requires_access_asset` from `airflow.api_fastapi.core_api.security` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
15 15 | from airflow.secrets.local_filesystm import load_connections
|
||||
@@ -31,7 +31,7 @@ AIR301_names_fix.py:21:1: AIR301 [*] `airflow.auth.managers.models.resource_deta
|
||||
21 | DatasetDetails()
|
||||
| ^^^^^^^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.api_fastapi.auth.managers.models.resource_details.AssetDetails` instead
|
||||
= help: Use `AssetDetails` from `airflow.api_fastapi.auth.managers.models.resource_details` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
15 15 | from airflow.secrets.local_filesystm import load_connections
|
||||
@@ -54,7 +54,7 @@ AIR301_names_fix.py:24:1: AIR301 [*] `airflow.datasets.manager.DatasetManager` i
|
||||
25 | dataset_manager()
|
||||
26 | resolve_dataset_manager()
|
||||
|
|
||||
= help: Use `airflow.assets.manager.AssetManager` instead
|
||||
= help: Use `AssetManager` from `airflow.assets.manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
15 15 | from airflow.secrets.local_filesystm import load_connections
|
||||
@@ -80,7 +80,7 @@ AIR301_names_fix.py:25:1: AIR301 [*] `airflow.datasets.manager.dataset_manager`
|
||||
| ^^^^^^^^^^^^^^^ AIR301
|
||||
26 | resolve_dataset_manager()
|
||||
|
|
||||
= help: Use `airflow.assets.manager.asset_manager` instead
|
||||
= help: Use `asset_manager` from `airflow.assets.manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
15 15 | from airflow.secrets.local_filesystm import load_connections
|
||||
@@ -109,7 +109,7 @@ AIR301_names_fix.py:26:1: AIR301 [*] `airflow.datasets.manager.resolve_dataset_m
|
||||
27 |
|
||||
28 | DatasetLineageInfo()
|
||||
|
|
||||
= help: Use `airflow.assets.manager.resolve_asset_manager` instead
|
||||
= help: Use `resolve_asset_manager` from `airflow.assets.manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
15 15 | from airflow.secrets.local_filesystm import load_connections
|
||||
@@ -138,7 +138,7 @@ AIR301_names_fix.py:28:1: AIR301 [*] `airflow.lineage.hook.DatasetLineageInfo` i
|
||||
29 |
|
||||
30 | AllowListValidator()
|
||||
|
|
||||
= help: Use `airflow.lineage.hook.AssetLineageInfo` instead
|
||||
= help: Use `AssetLineageInfo` from `airflow.lineage.hook` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
10 10 | dataset_manager,
|
||||
@@ -167,7 +167,7 @@ AIR301_names_fix.py:30:1: AIR301 [*] `airflow.metrics.validators.AllowListValida
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||
31 | BlockListValidator()
|
||||
|
|
||||
= help: Use `airflow.metrics.validators.PatternAllowListValidator` instead
|
||||
= help: Use `PatternAllowListValidator` from `airflow.metrics.validators` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
11 11 | resolve_dataset_manager,
|
||||
@@ -196,7 +196,7 @@ AIR301_names_fix.py:31:1: AIR301 [*] `airflow.metrics.validators.BlockListValida
|
||||
32 |
|
||||
33 | load_connections()
|
||||
|
|
||||
= help: Use `airflow.metrics.validators.PatternBlockListValidator` instead
|
||||
= help: Use `PatternBlockListValidator` from `airflow.metrics.validators` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
11 11 | resolve_dataset_manager,
|
||||
@@ -226,7 +226,7 @@ AIR301_names_fix.py:35:1: AIR301 [*] `airflow.security.permissions.RESOURCE_DATA
|
||||
36 |
|
||||
37 | has_access_dataset()
|
||||
|
|
||||
= help: Use `airflow.security.permissions.RESOURCE_ASSET` instead
|
||||
= help: Use `RESOURCE_ASSET` from `airflow.security.permissions` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
13 13 | from airflow.lineage.hook import DatasetLineageInfo
|
||||
@@ -265,7 +265,7 @@ AIR301_names_fix.py:44:1: AIR301 [*] `airflow.listeners.spec.dataset.on_dataset_
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||
45 | on_dataset_changed()
|
||||
|
|
||||
= help: Use `airflow.listeners.spec.asset.on_asset_created` instead
|
||||
= help: Use `on_asset_created` from `airflow.listeners.spec.asset` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
40 40 | on_dataset_changed,
|
||||
@@ -283,7 +283,7 @@ AIR301_names_fix.py:45:1: AIR301 [*] `airflow.listeners.spec.dataset.on_dataset_
|
||||
45 | on_dataset_changed()
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR301
|
||||
|
|
||||
= help: Use `airflow.listeners.spec.asset.on_asset_changed` instead
|
||||
= help: Use `on_asset_changed` from `airflow.listeners.spec.asset` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
40 40 | on_dataset_changed,
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR301_provider_names_fix.py:25:1: AIR301 [*] `airflow.providers.amazon.aws.auth
|
||||
26 |
|
||||
27 | s3_create_dataset()
|
||||
|
|
||||
= help: Use `airflow.providers.amazon.aws.auth_manager.avp.entities.AvpEntities.ASSET` instead
|
||||
= help: Use `AvpEntities.ASSET` from `airflow.providers.amazon.aws.auth_manager.avp.entities` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | translate_airflow_dataset,
|
||||
@@ -30,7 +30,7 @@ AIR301_provider_names_fix.py:27:1: AIR301 [*] `airflow.providers.amazon.aws.data
|
||||
| ^^^^^^^^^^^^^^^^^ AIR301
|
||||
28 | s3_convert_dataset_to_openlineage()
|
||||
|
|
||||
= help: Use `airflow.providers.amazon.aws.assets.s3.create_asset` instead
|
||||
= help: Use `create_asset` from `airflow.providers.amazon.aws.assets.s3` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
21 21 | DatasetInfo,
|
||||
@@ -54,7 +54,7 @@ AIR301_provider_names_fix.py:28:1: AIR301 [*] `airflow.providers.amazon.aws.data
|
||||
29 |
|
||||
30 | io_create_dataset()
|
||||
|
|
||||
= help: Use `airflow.providers.amazon.aws.assets.s3.convert_asset_to_openlineage` instead
|
||||
= help: Use `convert_asset_to_openlineage` from `airflow.providers.amazon.aws.assets.s3` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
21 21 | DatasetInfo,
|
||||
@@ -79,7 +79,7 @@ AIR301_provider_names_fix.py:36:1: AIR301 [*] `airflow.providers.google.datasets
|
||||
37 | # airflow.providers.google.datasets.gcs
|
||||
38 | gcs_create_dataset()
|
||||
|
|
||||
= help: Use `airflow.providers.google.assets.bigquery.create_asset` instead
|
||||
= help: Use `create_asset` from `airflow.providers.google.assets.bigquery` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
21 21 | DatasetInfo,
|
||||
@@ -108,7 +108,7 @@ AIR301_provider_names_fix.py:38:1: AIR301 [*] `airflow.providers.google.datasets
|
||||
39 | gcs_convert_dataset_to_openlineage()
|
||||
40 | # airflow.providers.openlineage.utils.utils
|
||||
|
|
||||
= help: Use `airflow.providers.google.assets.gcs.create_asset` instead
|
||||
= help: Use `create_asset` from `airflow.providers.google.assets.gcs` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
21 21 | DatasetInfo,
|
||||
@@ -137,7 +137,7 @@ AIR301_provider_names_fix.py:39:1: AIR301 [*] `airflow.providers.google.datasets
|
||||
40 | # airflow.providers.openlineage.utils.utils
|
||||
41 | DatasetInfo()
|
||||
|
|
||||
= help: Use `airflow.providers.google.assets.gcs.convert_asset_to_openlineage` instead
|
||||
= help: Use `convert_asset_to_openlineage` from `airflow.providers.google.assets.gcs` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
21 21 | DatasetInfo,
|
||||
@@ -166,7 +166,7 @@ AIR301_provider_names_fix.py:41:1: AIR301 [*] `airflow.providers.openlineage.uti
|
||||
42 | translate_airflow_dataset()
|
||||
43 | #
|
||||
|
|
||||
= help: Use `airflow.providers.openlineage.utils.utils.AssetInfo` instead
|
||||
= help: Use `AssetInfo` from `airflow.providers.openlineage.utils.utils` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
20 20 | from airflow.providers.openlineage.utils.utils import (
|
||||
@@ -195,7 +195,7 @@ AIR301_provider_names_fix.py:42:1: AIR301 [*] `airflow.providers.openlineage.uti
|
||||
43 | #
|
||||
44 | # airflow.secrets.local_filesystem
|
||||
|
|
||||
= help: Use `airflow.providers.openlineage.utils.utils.translate_airflow_asset` instead
|
||||
= help: Use `translate_airflow_asset` from `airflow.providers.openlineage.utils.utils` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
20 20 | from airflow.providers.openlineage.utils.utils import (
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_amazon.py:23:1: AIR302 `airflow.hooks.S3_hook.S3Hook` is moved into `amaz
|
||||
| ^^^^^^ AIR302
|
||||
24 | provide_bucket_name()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.hooks.s3.S3Hook` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3Hook` from `airflow.providers.amazon.aws.hooks.s3` instead.
|
||||
|
||||
AIR302_amazon.py:24:1: AIR302 `airflow.hooks.S3_hook.provide_bucket_name` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_amazon.py:24:1: AIR302 `airflow.hooks.S3_hook.provide_bucket_name` is mov
|
||||
25 |
|
||||
26 | GCSToS3Operator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.hooks.s3.provide_bucket_name` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `provide_bucket_name` from `airflow.providers.amazon.aws.hooks.s3` instead.
|
||||
|
||||
AIR302_amazon.py:26:1: AIR302 `airflow.operators.gcs_to_s3.GCSToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -30,7 +30,7 @@ AIR302_amazon.py:26:1: AIR302 `airflow.operators.gcs_to_s3.GCSToS3Operator` is m
|
||||
27 |
|
||||
28 | GoogleApiToS3Operator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.gcs_to_s3.GCSToS3Operator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `GCSToS3Operator` from `airflow.providers.amazon.aws.transfers.gcs_to_s3` instead.
|
||||
|
||||
AIR302_amazon.py:28:1: AIR302 `airflow.operators.google_api_to_s3_transfer.GoogleApiToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -40,7 +40,7 @@ AIR302_amazon.py:28:1: AIR302 `airflow.operators.google_api_to_s3_transfer.Googl
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
29 | GoogleApiToS3Transfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.google_api_to_s3.GoogleApiToS3Operator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `GoogleApiToS3Operator` from `airflow.providers.amazon.aws.transfers.google_api_to_s3` instead.
|
||||
|
||||
AIR302_amazon.py:29:1: AIR302 `airflow.operators.google_api_to_s3_transfer.GoogleApiToS3Transfer` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -50,7 +50,7 @@ AIR302_amazon.py:29:1: AIR302 `airflow.operators.google_api_to_s3_transfer.Googl
|
||||
30 |
|
||||
31 | RedshiftToS3Operator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.google_api_to_s3.GoogleApiToS3Operator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `GoogleApiToS3Operator` from `airflow.providers.amazon.aws.transfers.google_api_to_s3` instead.
|
||||
|
||||
AIR302_amazon.py:31:1: AIR302 `airflow.operators.redshift_to_s3_operator.RedshiftToS3Operator` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -60,7 +60,7 @@ AIR302_amazon.py:31:1: AIR302 `airflow.operators.redshift_to_s3_operator.Redshif
|
||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
32 | RedshiftToS3Transfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.redshift_to_s3.RedshiftToS3Operator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `RedshiftToS3Operator` from `airflow.providers.amazon.aws.transfers.redshift_to_s3` instead.
|
||||
|
||||
AIR302_amazon.py:32:1: AIR302 `airflow.operators.redshift_to_s3_operator.RedshiftToS3Transfer` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -70,7 +70,7 @@ AIR302_amazon.py:32:1: AIR302 `airflow.operators.redshift_to_s3_operator.Redshif
|
||||
33 |
|
||||
34 | S3FileTransformOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.redshift_to_s3.RedshiftToS3Operator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `RedshiftToS3Operator` from `airflow.providers.amazon.aws.transfers.redshift_to_s3` instead.
|
||||
|
||||
AIR302_amazon.py:34:1: AIR302 `airflow.operators.s3_file_transform_operator.S3FileTransformOperator` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -81,7 +81,7 @@ AIR302_amazon.py:34:1: AIR302 `airflow.operators.s3_file_transform_operator.S3Fi
|
||||
35 |
|
||||
36 | S3ToRedshiftOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=3.0.0` and use `airflow.providers.amazon.aws.operators.s3.S3FileTransformOperator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=3.0.0` and use `S3FileTransformOperator` from `airflow.providers.amazon.aws.operators.s3` instead.
|
||||
|
||||
AIR302_amazon.py:36:1: AIR302 `airflow.operators.s3_to_redshift_operator.S3ToRedshiftOperator` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -91,7 +91,7 @@ AIR302_amazon.py:36:1: AIR302 `airflow.operators.s3_to_redshift_operator.S3ToRed
|
||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
37 | S3ToRedshiftTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.s3_to_redshift.S3ToRedshiftOperator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3ToRedshiftOperator` from `airflow.providers.amazon.aws.transfers.s3_to_redshift` instead.
|
||||
|
||||
AIR302_amazon.py:37:1: AIR302 `airflow.operators.s3_to_redshift_operator.S3ToRedshiftTransfer` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -101,7 +101,7 @@ AIR302_amazon.py:37:1: AIR302 `airflow.operators.s3_to_redshift_operator.S3ToRed
|
||||
38 |
|
||||
39 | S3KeySensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.transfers.s3_to_redshift.S3ToRedshiftOperator` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3ToRedshiftOperator` from `airflow.providers.amazon.aws.transfers.s3_to_redshift` instead.
|
||||
|
||||
AIR302_amazon.py:39:1: AIR302 `airflow.sensors.s3_key_sensor.S3KeySensor` is moved into `amazon` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -110,4 +110,4 @@ AIR302_amazon.py:39:1: AIR302 `airflow.sensors.s3_key_sensor.S3KeySensor` is mov
|
||||
39 | S3KeySensor()
|
||||
| ^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `airflow.providers.amazon.aws.sensors.s3.S3KeySensor` instead.
|
||||
= help: Install `apache-airflow-providers-amazon>=1.0.0` and use `S3KeySensor` from `airflow.providers.amazon.aws.sensors.s3` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_celery.py:9:1: AIR302 `airflow.config_templates.default_celery.DEFAULT_CE
|
||||
10 |
|
||||
11 | app
|
||||
|
|
||||
= help: Install `apache-airflow-providers-celery>=3.3.0` and use `airflow.providers.celery.executors.default_celery.DEFAULT_CELERY_CONFIG` instead.
|
||||
= help: Install `apache-airflow-providers-celery>=3.3.0` and use `DEFAULT_CELERY_CONFIG` from `airflow.providers.celery.executors.default_celery` instead.
|
||||
|
||||
AIR302_celery.py:11:1: AIR302 `airflow.executors.celery_executor.app` is moved into `celery` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -20,7 +20,7 @@ AIR302_celery.py:11:1: AIR302 `airflow.executors.celery_executor.app` is moved i
|
||||
| ^^^ AIR302
|
||||
12 | CeleryExecutor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-celery>=3.3.0` and use `airflow.providers.celery.executors.celery_executor_utils.app` instead.
|
||||
= help: Install `apache-airflow-providers-celery>=3.3.0` and use `app` from `airflow.providers.celery.executors.celery_executor_utils` instead.
|
||||
|
||||
AIR302_celery.py:12:1: AIR302 `airflow.executors.celery_executor.CeleryExecutor` is moved into `celery` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -28,4 +28,4 @@ AIR302_celery.py:12:1: AIR302 `airflow.executors.celery_executor.CeleryExecutor`
|
||||
12 | CeleryExecutor()
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-celery>=3.3.0` and use `airflow.providers.celery.executors.celery_executor.CeleryExecutor` instead.
|
||||
= help: Install `apache-airflow-providers-celery>=3.3.0` and use `CeleryExecutor` from `airflow.providers.celery.executors.celery_executor` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_common_sql.py:10:1: AIR302 `airflow.hooks.dbapi.ConnectorProtocol` is mov
|
||||
11 | DbApiHook()
|
||||
12 | SQLCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `airflow.providers.common.sql.hooks.sql.ConnectorProtocol` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `ConnectorProtocol` from `airflow.providers.common.sql.hooks.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:11:1: AIR302 `airflow.hooks.dbapi_hook.DbApiHook` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_common_sql.py:11:1: AIR302 `airflow.hooks.dbapi_hook.DbApiHook` is moved
|
||||
| ^^^^^^^^^ AIR302
|
||||
12 | SQLCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `airflow.providers.common.sql.hooks.sql.DbApiHook` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `DbApiHook` from `airflow.providers.common.sql.hooks.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:12:1: AIR302 `airflow.operators.check_operator.SQLCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -28,7 +28,7 @@ AIR302_common_sql.py:12:1: AIR302 `airflow.operators.check_operator.SQLCheckOper
|
||||
12 | SQLCheckOperator()
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:18:1: AIR302 `airflow.operators.sql.SQLCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -38,7 +38,7 @@ AIR302_common_sql.py:18:1: AIR302 `airflow.operators.sql.SQLCheckOperator` is mo
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
19 | CheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:19:1: AIR302 `airflow.operators.check_operator.CheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -46,7 +46,7 @@ AIR302_common_sql.py:19:1: AIR302 `airflow.operators.check_operator.CheckOperato
|
||||
19 | CheckOperator()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:24:1: AIR302 `airflow.operators.druid_check_operator.CheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -55,7 +55,7 @@ AIR302_common_sql.py:24:1: AIR302 `airflow.operators.druid_check_operator.CheckO
|
||||
24 | CheckOperator()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:29:1: AIR302 `airflow.operators.presto_check_operator.CheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -64,7 +64,7 @@ AIR302_common_sql.py:29:1: AIR302 `airflow.operators.presto_check_operator.Check
|
||||
29 | CheckOperator()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:39:1: AIR302 `airflow.operators.druid_check_operator.DruidCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -75,7 +75,7 @@ AIR302_common_sql.py:39:1: AIR302 `airflow.operators.druid_check_operator.DruidC
|
||||
40 | PrestoCheckOperator()
|
||||
41 | IntervalCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:40:1: AIR302 `airflow.operators.presto_check_operator.PrestoCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -85,7 +85,7 @@ AIR302_common_sql.py:40:1: AIR302 `airflow.operators.presto_check_operator.Prest
|
||||
41 | IntervalCheckOperator()
|
||||
42 | SQLIntervalCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:41:1: AIR302 `airflow.operators.check_operator.IntervalCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -95,7 +95,7 @@ AIR302_common_sql.py:41:1: AIR302 `airflow.operators.check_operator.IntervalChec
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
42 | SQLIntervalCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLIntervalCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLIntervalCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:42:1: AIR302 `airflow.operators.check_operator.SQLIntervalCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -104,7 +104,7 @@ AIR302_common_sql.py:42:1: AIR302 `airflow.operators.check_operator.SQLIntervalC
|
||||
42 | SQLIntervalCheckOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLIntervalCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLIntervalCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:51:1: AIR302 `airflow.operators.presto_check_operator.IntervalCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -115,7 +115,7 @@ AIR302_common_sql.py:51:1: AIR302 `airflow.operators.presto_check_operator.Inter
|
||||
52 | SQLIntervalCheckOperator()
|
||||
53 | PrestoIntervalCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLIntervalCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLIntervalCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:52:1: AIR302 `airflow.operators.sql.SQLIntervalCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -124,7 +124,7 @@ AIR302_common_sql.py:52:1: AIR302 `airflow.operators.sql.SQLIntervalCheckOperato
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
53 | PrestoIntervalCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLIntervalCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLIntervalCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:53:1: AIR302 `airflow.operators.presto_check_operator.PrestoIntervalCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -133,7 +133,7 @@ AIR302_common_sql.py:53:1: AIR302 `airflow.operators.presto_check_operator.Prest
|
||||
53 | PrestoIntervalCheckOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLIntervalCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLIntervalCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:61:1: AIR302 `airflow.operators.check_operator.SQLThresholdCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -143,7 +143,7 @@ AIR302_common_sql.py:61:1: AIR302 `airflow.operators.check_operator.SQLThreshold
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
62 | ThresholdCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLThresholdCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLThresholdCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:62:1: AIR302 `airflow.operators.check_operator.ThresholdCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -151,7 +151,7 @@ AIR302_common_sql.py:62:1: AIR302 `airflow.operators.check_operator.ThresholdChe
|
||||
62 | ThresholdCheckOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLThresholdCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLThresholdCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:67:1: AIR302 `airflow.operators.sql.SQLThresholdCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -160,7 +160,7 @@ AIR302_common_sql.py:67:1: AIR302 `airflow.operators.sql.SQLThresholdCheckOperat
|
||||
67 | SQLThresholdCheckOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLThresholdCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLThresholdCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:75:1: AIR302 `airflow.operators.check_operator.SQLValueCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -170,7 +170,7 @@ AIR302_common_sql.py:75:1: AIR302 `airflow.operators.check_operator.SQLValueChec
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
76 | ValueCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLValueCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLValueCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:76:1: AIR302 `airflow.operators.check_operator.ValueCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -178,7 +178,7 @@ AIR302_common_sql.py:76:1: AIR302 `airflow.operators.check_operator.ValueCheckOp
|
||||
76 | ValueCheckOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLValueCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLValueCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:85:1: AIR302 `airflow.operators.sql.SQLValueCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -189,7 +189,7 @@ AIR302_common_sql.py:85:1: AIR302 `airflow.operators.sql.SQLValueCheckOperator`
|
||||
86 | ValueCheckOperator()
|
||||
87 | PrestoValueCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLValueCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLValueCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:86:1: AIR302 `airflow.operators.presto_check_operator.ValueCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -198,7 +198,7 @@ AIR302_common_sql.py:86:1: AIR302 `airflow.operators.presto_check_operator.Value
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR302
|
||||
87 | PrestoValueCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLValueCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLValueCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:87:1: AIR302 `airflow.operators.presto_check_operator.PrestoValueCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -207,7 +207,7 @@ AIR302_common_sql.py:87:1: AIR302 `airflow.operators.presto_check_operator.Prest
|
||||
87 | PrestoValueCheckOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLValueCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLValueCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:99:1: AIR302 `airflow.operators.sql.BaseSQLOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -218,7 +218,7 @@ AIR302_common_sql.py:99:1: AIR302 `airflow.operators.sql.BaseSQLOperator` is mov
|
||||
100 | BranchSQLOperator()
|
||||
101 | SQLTableCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.BaseSQLOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `BaseSQLOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:100:1: AIR302 `airflow.operators.sql.BranchSQLOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -228,7 +228,7 @@ AIR302_common_sql.py:100:1: AIR302 `airflow.operators.sql.BranchSQLOperator` is
|
||||
101 | SQLTableCheckOperator()
|
||||
102 | SQLColumnCheckOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.BranchSQLOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `BranchSQLOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:101:1: AIR302 `airflow.operators.sql.SQLTableCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -239,7 +239,7 @@ AIR302_common_sql.py:101:1: AIR302 `airflow.operators.sql.SQLTableCheckOperator`
|
||||
102 | SQLColumnCheckOperator()
|
||||
103 | _convert_to_float_if_possible()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `airflow.providers.common.sql.operators.sql.SQLTableCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.1.0` and use `SQLTableCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:102:1: AIR302 `airflow.operators.sql.SQLColumnCheckOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -250,7 +250,7 @@ AIR302_common_sql.py:102:1: AIR302 `airflow.operators.sql.SQLColumnCheckOperator
|
||||
103 | _convert_to_float_if_possible()
|
||||
104 | parse_boolean()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `airflow.providers.common.sql.operators.sql.SQLColumnCheckOperator` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `SQLColumnCheckOperator` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:103:1: AIR302 `airflow.operators.sql._convert_to_float_if_possible` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -260,7 +260,7 @@ AIR302_common_sql.py:103:1: AIR302 `airflow.operators.sql._convert_to_float_if_p
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
104 | parse_boolean()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `airflow.providers.common.sql.operators.sql._convert_to_float_if_possible` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `_convert_to_float_if_possible` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:104:1: AIR302 `airflow.operators.sql.parse_boolean` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -269,7 +269,7 @@ AIR302_common_sql.py:104:1: AIR302 `airflow.operators.sql.parse_boolean` is move
|
||||
104 | parse_boolean()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `airflow.providers.common.sql.operators.sql.parse_boolean` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `parse_boolean` from `airflow.providers.common.sql.operators.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:109:1: AIR302 `airflow.sensors.sql.SqlSensor` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -278,7 +278,7 @@ AIR302_common_sql.py:109:1: AIR302 `airflow.sensors.sql.SqlSensor` is moved into
|
||||
109 | SqlSensor()
|
||||
| ^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `airflow.providers.common.sql.sensors.sql.SqlSensor` instead.
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `SqlSensor` from `airflow.providers.common.sql.sensors.sql` instead.
|
||||
|
||||
AIR302_common_sql.py:114:1: AIR302 `airflow.sensors.sql_sensor.SqlSensor` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -287,147 +287,4 @@ AIR302_common_sql.py:114:1: AIR302 `airflow.sensors.sql_sensor.SqlSensor` is mov
|
||||
114 | SqlSensor()
|
||||
| ^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `airflow.providers.common.sql.sensors.sql.SqlSensor` instead.
|
||||
|
||||
AIR302_common_sql.py:124:1: AIR302 [*] `airflow.operators.jdbc_operator.JdbcOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
122 | from airflow.operators.sqlite_operator import SqliteOperator
|
||||
123 |
|
||||
124 | JdbcOperator()
|
||||
| ^^^^^^^^^^^^ AIR302
|
||||
125 | MsSqlOperator()
|
||||
126 | MySqlOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.3.0` and use `airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
120 120 | from airflow.operators.oracle_operator import OracleOperator
|
||||
121 121 | from airflow.operators.postgres_operator import PostgresOperator
|
||||
122 122 | from airflow.operators.sqlite_operator import SqliteOperator
|
||||
123 |+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||
123 124 |
|
||||
124 |-JdbcOperator()
|
||||
125 |+SQLExecuteQueryOperator()
|
||||
125 126 | MsSqlOperator()
|
||||
126 127 | MySqlOperator()
|
||||
127 128 | OracleOperator()
|
||||
|
||||
AIR302_common_sql.py:125:1: AIR302 [*] `airflow.operators.mssql_operator.MsSqlOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
124 | JdbcOperator()
|
||||
125 | MsSqlOperator()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
126 | MySqlOperator()
|
||||
127 | OracleOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.3.0` and use `airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
120 120 | from airflow.operators.oracle_operator import OracleOperator
|
||||
121 121 | from airflow.operators.postgres_operator import PostgresOperator
|
||||
122 122 | from airflow.operators.sqlite_operator import SqliteOperator
|
||||
123 |+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||
123 124 |
|
||||
124 125 | JdbcOperator()
|
||||
125 |-MsSqlOperator()
|
||||
126 |+SQLExecuteQueryOperator()
|
||||
126 127 | MySqlOperator()
|
||||
127 128 | OracleOperator()
|
||||
128 129 | PostgresOperator()
|
||||
|
||||
AIR302_common_sql.py:126:1: AIR302 [*] `airflow.operators.mysql_operator.MySqlOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
124 | JdbcOperator()
|
||||
125 | MsSqlOperator()
|
||||
126 | MySqlOperator()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
127 | OracleOperator()
|
||||
128 | PostgresOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.3.0` and use `airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
120 120 | from airflow.operators.oracle_operator import OracleOperator
|
||||
121 121 | from airflow.operators.postgres_operator import PostgresOperator
|
||||
122 122 | from airflow.operators.sqlite_operator import SqliteOperator
|
||||
123 |+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||
123 124 |
|
||||
124 125 | JdbcOperator()
|
||||
125 126 | MsSqlOperator()
|
||||
126 |-MySqlOperator()
|
||||
127 |+SQLExecuteQueryOperator()
|
||||
127 128 | OracleOperator()
|
||||
128 129 | PostgresOperator()
|
||||
129 130 | SqliteOperator()
|
||||
|
||||
AIR302_common_sql.py:127:1: AIR302 [*] `airflow.operators.oracle_operator.OracleOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
125 | MsSqlOperator()
|
||||
126 | MySqlOperator()
|
||||
127 | OracleOperator()
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
128 | PostgresOperator()
|
||||
129 | SqliteOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.3.0` and use `airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
120 120 | from airflow.operators.oracle_operator import OracleOperator
|
||||
121 121 | from airflow.operators.postgres_operator import PostgresOperator
|
||||
122 122 | from airflow.operators.sqlite_operator import SqliteOperator
|
||||
123 |+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||
123 124 |
|
||||
124 125 | JdbcOperator()
|
||||
125 126 | MsSqlOperator()
|
||||
126 127 | MySqlOperator()
|
||||
127 |-OracleOperator()
|
||||
128 |+SQLExecuteQueryOperator()
|
||||
128 129 | PostgresOperator()
|
||||
129 130 | SqliteOperator()
|
||||
|
||||
AIR302_common_sql.py:128:1: AIR302 [*] `airflow.operators.postgres_operator.PostgresOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
126 | MySqlOperator()
|
||||
127 | OracleOperator()
|
||||
128 | PostgresOperator()
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
129 | SqliteOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.3.0` and use `airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
120 120 | from airflow.operators.oracle_operator import OracleOperator
|
||||
121 121 | from airflow.operators.postgres_operator import PostgresOperator
|
||||
122 122 | from airflow.operators.sqlite_operator import SqliteOperator
|
||||
123 |+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||
123 124 |
|
||||
124 125 | JdbcOperator()
|
||||
125 126 | MsSqlOperator()
|
||||
126 127 | MySqlOperator()
|
||||
127 128 | OracleOperator()
|
||||
128 |-PostgresOperator()
|
||||
129 |+SQLExecuteQueryOperator()
|
||||
129 130 | SqliteOperator()
|
||||
|
||||
AIR302_common_sql.py:129:1: AIR302 [*] `airflow.operators.sqlite_operator.SqliteOperator` is moved into `common-sql` provider in Airflow 3.0;
|
||||
|
|
||||
127 | OracleOperator()
|
||||
128 | PostgresOperator()
|
||||
129 | SqliteOperator()
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.3.0` and use `airflow.providers.common.sql.operators.sql.SQLExecuteQueryOperator` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
120 120 | from airflow.operators.oracle_operator import OracleOperator
|
||||
121 121 | from airflow.operators.postgres_operator import PostgresOperator
|
||||
122 122 | from airflow.operators.sqlite_operator import SqliteOperator
|
||||
123 |+from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator
|
||||
123 124 |
|
||||
124 125 | JdbcOperator()
|
||||
125 126 | MsSqlOperator()
|
||||
126 127 | MySqlOperator()
|
||||
127 128 | OracleOperator()
|
||||
128 129 | PostgresOperator()
|
||||
129 |-SqliteOperator()
|
||||
130 |+SQLExecuteQueryOperator()
|
||||
= help: Install `apache-airflow-providers-common-sql>=1.0.0` and use `SqlSensor` from `airflow.providers.common.sql.sensors.sql` instead.
|
||||
|
||||
@@ -8,4 +8,4 @@ AIR302_daskexecutor.py:5:1: AIR302 `airflow.executors.dask_executor.DaskExecutor
|
||||
5 | DaskExecutor()
|
||||
| ^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-daskexecutor>=1.0.0` and use `airflow.providers.daskexecutor.executors.dask_executor.DaskExecutor` instead.
|
||||
= help: Install `apache-airflow-providers-daskexecutor>=1.0.0` and use `DaskExecutor` from `airflow.providers.daskexecutor.executors.dask_executor` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_druid.py:12:1: AIR302 `airflow.hooks.druid_hook.DruidDbApiHook` is moved
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
13 | DruidHook()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `airflow.providers.apache.druid.hooks.druid.DruidDbApiHook` instead.
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `DruidDbApiHook` from `airflow.providers.apache.druid.hooks.druid` instead.
|
||||
|
||||
AIR302_druid.py:13:1: AIR302 `airflow.hooks.druid_hook.DruidHook` is moved into `apache-druid` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_druid.py:13:1: AIR302 `airflow.hooks.druid_hook.DruidHook` is moved into
|
||||
14 |
|
||||
15 | HiveToDruidOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `airflow.providers.apache.druid.hooks.druid.DruidHook` instead.
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `DruidHook` from `airflow.providers.apache.druid.hooks.druid` instead.
|
||||
|
||||
AIR302_druid.py:15:1: AIR302 `airflow.operators.hive_to_druid.HiveToDruidOperator` is moved into `apache-druid` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -29,7 +29,7 @@ AIR302_druid.py:15:1: AIR302 `airflow.operators.hive_to_druid.HiveToDruidOperato
|
||||
| ^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
16 | HiveToDruidTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `airflow.providers.apache.druid.transfers.hive_to_druid.HiveToDruidOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `HiveToDruidOperator` from `airflow.providers.apache.druid.transfers.hive_to_druid` instead.
|
||||
|
||||
AIR302_druid.py:16:1: AIR302 `airflow.operators.hive_to_druid.HiveToDruidTransfer` is moved into `apache-druid` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -37,4 +37,4 @@ AIR302_druid.py:16:1: AIR302 `airflow.operators.hive_to_druid.HiveToDruidTransfe
|
||||
16 | HiveToDruidTransfer()
|
||||
| ^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `airflow.providers.apache.druid.transfers.hive_to_druid.HiveToDruidOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-druid>=1.0.0` and use `HiveToDruidOperator` from `airflow.providers.apache.druid.transfers.hive_to_druid` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_fab.py:10:1: AIR302 `airflow.api.auth.backend.basic_auth.CLIENT_AUTH` is
|
||||
11 | init_app()
|
||||
12 | auth_current_user()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth.CLIENT_AUTH` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `CLIENT_AUTH` from `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth` instead.
|
||||
|
||||
AIR302_fab.py:11:1: AIR302 `airflow.api.auth.backend.basic_auth.init_app` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -20,7 +20,7 @@ AIR302_fab.py:11:1: AIR302 `airflow.api.auth.backend.basic_auth.init_app` is mov
|
||||
12 | auth_current_user()
|
||||
13 | requires_authentication()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth.init_app` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `init_app` from `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth` instead.
|
||||
|
||||
AIR302_fab.py:12:1: AIR302 `airflow.api.auth.backend.basic_auth.auth_current_user` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -30,7 +30,7 @@ AIR302_fab.py:12:1: AIR302 `airflow.api.auth.backend.basic_auth.auth_current_use
|
||||
| ^^^^^^^^^^^^^^^^^ AIR302
|
||||
13 | requires_authentication()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth.auth_current_user` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `auth_current_user` from `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth` instead.
|
||||
|
||||
AIR302_fab.py:13:1: AIR302 `airflow.api.auth.backend.basic_auth.requires_authentication` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -41,7 +41,7 @@ AIR302_fab.py:13:1: AIR302 `airflow.api.auth.backend.basic_auth.requires_authent
|
||||
14 |
|
||||
15 | from airflow.api.auth.backend.kerberos_auth import (
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth.requires_authentication` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `requires_authentication` from `airflow.providers.fab.auth_manager.api.auth.backend.basic_auth` instead.
|
||||
|
||||
AIR302_fab.py:23:1: AIR302 `airflow.api.auth.backend.kerberos_auth.log` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -52,7 +52,7 @@ AIR302_fab.py:23:1: AIR302 `airflow.api.auth.backend.kerberos_auth.log` is moved
|
||||
24 | CLIENT_AUTH
|
||||
25 | find_user()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.log` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `log` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:24:1: AIR302 `airflow.api.auth.backend.kerberos_auth.CLIENT_AUTH` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -62,7 +62,7 @@ AIR302_fab.py:24:1: AIR302 `airflow.api.auth.backend.kerberos_auth.CLIENT_AUTH`
|
||||
25 | find_user()
|
||||
26 | init_app()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.CLIENT_AUTH` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `CLIENT_AUTH` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:25:1: AIR302 `airflow.api.auth.backend.kerberos_auth.find_user` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -73,7 +73,7 @@ AIR302_fab.py:25:1: AIR302 `airflow.api.auth.backend.kerberos_auth.find_user` is
|
||||
26 | init_app()
|
||||
27 | requires_authentication()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.find_user` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `find_user` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:26:1: AIR302 `airflow.api.auth.backend.kerberos_auth.init_app` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -83,7 +83,7 @@ AIR302_fab.py:26:1: AIR302 `airflow.api.auth.backend.kerberos_auth.init_app` is
|
||||
| ^^^^^^^^ AIR302
|
||||
27 | requires_authentication()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.init_app` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `init_app` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:27:1: AIR302 `airflow.api.auth.backend.kerberos_auth.requires_authentication` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -94,7 +94,7 @@ AIR302_fab.py:27:1: AIR302 `airflow.api.auth.backend.kerberos_auth.requires_auth
|
||||
28 |
|
||||
29 | from airflow.auth.managers.fab.api.auth.backend.kerberos_auth import (
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.requires_authentication` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `requires_authentication` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:37:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_auth.log` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -105,7 +105,7 @@ AIR302_fab.py:37:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_
|
||||
38 | CLIENT_AUTH
|
||||
39 | find_user()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.log` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `log` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:38:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_auth.CLIENT_AUTH` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -115,7 +115,7 @@ AIR302_fab.py:38:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_
|
||||
39 | find_user()
|
||||
40 | init_app()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.CLIENT_AUTH` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `CLIENT_AUTH` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:39:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_auth.find_user` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -126,7 +126,7 @@ AIR302_fab.py:39:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_
|
||||
40 | init_app()
|
||||
41 | requires_authentication()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.find_user` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `find_user` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:40:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_auth.init_app` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -136,7 +136,7 @@ AIR302_fab.py:40:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_
|
||||
| ^^^^^^^^ AIR302
|
||||
41 | requires_authentication()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.init_app` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `init_app` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:41:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_auth.requires_authentication` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -147,7 +147,7 @@ AIR302_fab.py:41:1: AIR302 `airflow.auth.managers.fab.api.auth.backend.kerberos_
|
||||
42 |
|
||||
43 | from airflow.auth.managers.fab.fab_auth_manager import FabAuthManager
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth.requires_authentication` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `requires_authentication` from `airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.
|
||||
|
||||
AIR302_fab.py:49:1: AIR302 `airflow.auth.managers.fab.fab_auth_manager.FabAuthManager` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -158,7 +158,7 @@ AIR302_fab.py:49:1: AIR302 `airflow.auth.managers.fab.fab_auth_manager.FabAuthMa
|
||||
50 | MAX_NUM_DATABASE_USER_SESSIONS
|
||||
51 | FabAirflowSecurityManagerOverride()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `FabAuthManager` from `airflow.providers.fab.auth_manager.fab_auth_manager` instead.
|
||||
|
||||
AIR302_fab.py:50:1: AIR302 `airflow.auth.managers.fab.security_manager.override.MAX_NUM_DATABASE_USER_SESSIONS` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -167,7 +167,7 @@ AIR302_fab.py:50:1: AIR302 `airflow.auth.managers.fab.security_manager.override.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
51 | FabAirflowSecurityManagerOverride()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.security_manager.override.MAX_NUM_DATABASE_USER_SESSIONS` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `MAX_NUM_DATABASE_USER_SESSIONS` from `airflow.providers.fab.auth_manager.security_manager.override` instead.
|
||||
|
||||
AIR302_fab.py:51:1: AIR302 `airflow.auth.managers.fab.security_manager.override.FabAirflowSecurityManagerOverride` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -178,7 +178,7 @@ AIR302_fab.py:51:1: AIR302 `airflow.auth.managers.fab.security_manager.override.
|
||||
52 |
|
||||
53 | from airflow.www.security import FabAirflowSecurityManagerOverride
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.security_manager.override.FabAirflowSecurityManagerOverride` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `FabAirflowSecurityManagerOverride` from `airflow.providers.fab.auth_manager.security_manager.override` instead.
|
||||
|
||||
AIR302_fab.py:55:1: AIR302 `airflow.www.security.FabAirflowSecurityManagerOverride` is moved into `fab` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -187,4 +187,4 @@ AIR302_fab.py:55:1: AIR302 `airflow.www.security.FabAirflowSecurityManagerOverri
|
||||
55 | FabAirflowSecurityManagerOverride()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `airflow.providers.fab.auth_manager.security_manager.override.FabAirflowSecurityManagerOverride` instead.
|
||||
= help: Install `apache-airflow-providers-fab>=1.0.0` and use `FabAirflowSecurityManagerOverride` from `airflow.providers.fab.auth_manager.security_manager.override` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_hdfs.py:6:1: AIR302 `airflow.hooks.webhdfs_hook.WebHDFSHook` is moved int
|
||||
| ^^^^^^^^^^^ AIR302
|
||||
7 | WebHdfsSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hdfs>=1.0.0` and use `airflow.providers.apache.hdfs.hooks.webhdfs.WebHDFSHook` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hdfs>=1.0.0` and use `WebHDFSHook` from `airflow.providers.apache.hdfs.hooks.webhdfs` instead.
|
||||
|
||||
AIR302_hdfs.py:7:1: AIR302 `airflow.sensors.web_hdfs_sensor.WebHdfsSensor` is moved into `apache-hdfs` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -17,4 +17,4 @@ AIR302_hdfs.py:7:1: AIR302 `airflow.sensors.web_hdfs_sensor.WebHdfsSensor` is mo
|
||||
7 | WebHdfsSensor()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hdfs>=1.0.0` and use `airflow.providers.apache.hdfs.sensors.web_hdfs.WebHdfsSensor` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hdfs>=1.0.0` and use `WebHdfsSensor` from `airflow.providers.apache.hdfs.sensors.web_hdfs` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_hive.py:36:1: AIR302 `airflow.macros.hive.closest_ds_partition` is moved
|
||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
37 | max_partition()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=5.1.0` and use `airflow.providers.apache.hive.macros.hive.closest_ds_partition` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=5.1.0` and use `closest_ds_partition` from `airflow.providers.apache.hive.macros.hive` instead.
|
||||
|
||||
AIR302_hive.py:37:1: AIR302 `airflow.macros.hive.max_partition` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_hive.py:37:1: AIR302 `airflow.macros.hive.max_partition` is moved into `a
|
||||
38 |
|
||||
39 | HiveCliHook()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=5.1.0` and use `airflow.providers.apache.hive.macros.hive.max_partition` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=5.1.0` and use `max_partition` from `airflow.providers.apache.hive.macros.hive` instead.
|
||||
|
||||
AIR302_hive.py:39:1: AIR302 `airflow.hooks.hive_hooks.HiveCliHook` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -30,7 +30,7 @@ AIR302_hive.py:39:1: AIR302 `airflow.hooks.hive_hooks.HiveCliHook` is moved into
|
||||
40 | HiveMetastoreHook()
|
||||
41 | HiveServer2Hook()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.hooks.hive.HiveCliHook` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveCliHook` from `airflow.providers.apache.hive.hooks.hive` instead.
|
||||
|
||||
AIR302_hive.py:40:1: AIR302 `airflow.hooks.hive_hooks.HiveMetastoreHook` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -40,7 +40,7 @@ AIR302_hive.py:40:1: AIR302 `airflow.hooks.hive_hooks.HiveMetastoreHook` is move
|
||||
41 | HiveServer2Hook()
|
||||
42 | HIVE_QUEUE_PRIORITIES
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.hooks.hive.HiveMetastoreHook` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveMetastoreHook` from `airflow.providers.apache.hive.hooks.hive` instead.
|
||||
|
||||
AIR302_hive.py:41:1: AIR302 `airflow.hooks.hive_hooks.HiveServer2Hook` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -50,7 +50,7 @@ AIR302_hive.py:41:1: AIR302 `airflow.hooks.hive_hooks.HiveServer2Hook` is moved
|
||||
| ^^^^^^^^^^^^^^^ AIR302
|
||||
42 | HIVE_QUEUE_PRIORITIES
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.hooks.hive.HiveServer2Hook` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveServer2Hook` from `airflow.providers.apache.hive.hooks.hive` instead.
|
||||
|
||||
AIR302_hive.py:42:1: AIR302 `airflow.hooks.hive_hooks.HIVE_QUEUE_PRIORITIES` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -61,7 +61,7 @@ AIR302_hive.py:42:1: AIR302 `airflow.hooks.hive_hooks.HIVE_QUEUE_PRIORITIES` is
|
||||
43 |
|
||||
44 | HiveOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.hooks.hive.HIVE_QUEUE_PRIORITIES` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HIVE_QUEUE_PRIORITIES` from `airflow.providers.apache.hive.hooks.hive` instead.
|
||||
|
||||
AIR302_hive.py:44:1: AIR302 `airflow.operators.hive_operator.HiveOperator` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -72,7 +72,7 @@ AIR302_hive.py:44:1: AIR302 `airflow.operators.hive_operator.HiveOperator` is mo
|
||||
45 |
|
||||
46 | HiveStatsCollectionOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.operators.hive.HiveOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveOperator` from `airflow.providers.apache.hive.operators.hive` instead.
|
||||
|
||||
AIR302_hive.py:46:1: AIR302 `airflow.operators.hive_stats_operator.HiveStatsCollectionOperator` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -83,7 +83,7 @@ AIR302_hive.py:46:1: AIR302 `airflow.operators.hive_stats_operator.HiveStatsColl
|
||||
47 |
|
||||
48 | HiveToMySqlOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.operators.hive_stats.HiveStatsCollectionOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveStatsCollectionOperator` from `airflow.providers.apache.hive.operators.hive_stats` instead.
|
||||
|
||||
AIR302_hive.py:48:1: AIR302 `airflow.operators.hive_to_mysql.HiveToMySqlOperator` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -93,7 +93,7 @@ AIR302_hive.py:48:1: AIR302 `airflow.operators.hive_to_mysql.HiveToMySqlOperator
|
||||
| ^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
49 | HiveToMySqlTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.hive_to_mysql.HiveToMySqlOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveToMySqlOperator` from `airflow.providers.apache.hive.transfers.hive_to_mysql` instead.
|
||||
|
||||
AIR302_hive.py:49:1: AIR302 `airflow.operators.hive_to_mysql.HiveToMySqlTransfer` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -103,7 +103,7 @@ AIR302_hive.py:49:1: AIR302 `airflow.operators.hive_to_mysql.HiveToMySqlTransfer
|
||||
50 |
|
||||
51 | HiveToSambaOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.hive_to_mysql.HiveToMySqlOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveToMySqlOperator` from `airflow.providers.apache.hive.transfers.hive_to_mysql` instead.
|
||||
|
||||
AIR302_hive.py:51:1: AIR302 `airflow.operators.hive_to_samba_operator.HiveToSambaOperator` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -114,7 +114,7 @@ AIR302_hive.py:51:1: AIR302 `airflow.operators.hive_to_samba_operator.HiveToSamb
|
||||
52 |
|
||||
53 | MsSqlToHiveOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.hive_to_samba.HiveToSambaOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HiveToSambaOperator` from `airflow.providers.apache.hive.transfers.hive_to_samba` instead.
|
||||
|
||||
AIR302_hive.py:53:1: AIR302 `airflow.operators.mssql_to_hive.MsSqlToHiveOperator` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -124,7 +124,7 @@ AIR302_hive.py:53:1: AIR302 `airflow.operators.mssql_to_hive.MsSqlToHiveOperator
|
||||
| ^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
54 | MsSqlToHiveTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.mssql_to_hive.MsSqlToHiveOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `MsSqlToHiveOperator` from `airflow.providers.apache.hive.transfers.mssql_to_hive` instead.
|
||||
|
||||
AIR302_hive.py:54:1: AIR302 `airflow.operators.mssql_to_hive.MsSqlToHiveTransfer` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -134,7 +134,7 @@ AIR302_hive.py:54:1: AIR302 `airflow.operators.mssql_to_hive.MsSqlToHiveTransfer
|
||||
55 |
|
||||
56 | MySqlToHiveOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.mssql_to_hive.MsSqlToHiveOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `MsSqlToHiveOperator` from `airflow.providers.apache.hive.transfers.mssql_to_hive` instead.
|
||||
|
||||
AIR302_hive.py:56:1: AIR302 `airflow.operators.mysql_to_hive.MySqlToHiveOperator` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -144,7 +144,7 @@ AIR302_hive.py:56:1: AIR302 `airflow.operators.mysql_to_hive.MySqlToHiveOperator
|
||||
| ^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
57 | MySqlToHiveTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.mysql_to_hive.MySqlToHiveOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `MySqlToHiveOperator` from `airflow.providers.apache.hive.transfers.mysql_to_hive` instead.
|
||||
|
||||
AIR302_hive.py:57:1: AIR302 `airflow.operators.mysql_to_hive.MySqlToHiveTransfer` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -154,7 +154,7 @@ AIR302_hive.py:57:1: AIR302 `airflow.operators.mysql_to_hive.MySqlToHiveTransfer
|
||||
58 |
|
||||
59 | S3ToHiveOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.mysql_to_hive.MySqlToHiveOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `MySqlToHiveOperator` from `airflow.providers.apache.hive.transfers.mysql_to_hive` instead.
|
||||
|
||||
AIR302_hive.py:59:1: AIR302 `airflow.operators.s3_to_hive_operator.S3ToHiveOperator` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -164,7 +164,7 @@ AIR302_hive.py:59:1: AIR302 `airflow.operators.s3_to_hive_operator.S3ToHiveOpera
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
60 | S3ToHiveTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.s3_to_hive.S3ToHiveOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `S3ToHiveOperator` from `airflow.providers.apache.hive.transfers.s3_to_hive` instead.
|
||||
|
||||
AIR302_hive.py:60:1: AIR302 `airflow.operators.s3_to_hive_operator.S3ToHiveTransfer` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -174,7 +174,7 @@ AIR302_hive.py:60:1: AIR302 `airflow.operators.s3_to_hive_operator.S3ToHiveTrans
|
||||
61 |
|
||||
62 | HivePartitionSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.transfers.s3_to_hive.S3ToHiveOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `S3ToHiveOperator` from `airflow.providers.apache.hive.transfers.s3_to_hive` instead.
|
||||
|
||||
AIR302_hive.py:62:1: AIR302 `airflow.sensors.hive_partition_sensor.HivePartitionSensor` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -185,7 +185,7 @@ AIR302_hive.py:62:1: AIR302 `airflow.sensors.hive_partition_sensor.HivePartition
|
||||
63 |
|
||||
64 | MetastorePartitionSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.sensors.hive_partition.HivePartitionSensor` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `HivePartitionSensor` from `airflow.providers.apache.hive.sensors.hive_partition` instead.
|
||||
|
||||
AIR302_hive.py:64:1: AIR302 `airflow.sensors.metastore_partition_sensor.MetastorePartitionSensor` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -196,7 +196,7 @@ AIR302_hive.py:64:1: AIR302 `airflow.sensors.metastore_partition_sensor.Metastor
|
||||
65 |
|
||||
66 | NamedHivePartitionSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.sensors.metastore_partition.MetastorePartitionSensor` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `MetastorePartitionSensor` from `airflow.providers.apache.hive.sensors.metastore_partition` instead.
|
||||
|
||||
AIR302_hive.py:66:1: AIR302 `airflow.sensors.named_hive_partition_sensor.NamedHivePartitionSensor` is moved into `apache-hive` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -205,4 +205,4 @@ AIR302_hive.py:66:1: AIR302 `airflow.sensors.named_hive_partition_sensor.NamedHi
|
||||
66 | NamedHivePartitionSensor()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `airflow.providers.apache.hive.sensors.named_hive_partition.NamedHivePartitionSensor` instead.
|
||||
= help: Install `apache-airflow-providers-apache-hive>=1.0.0` and use `NamedHivePartitionSensor` from `airflow.providers.apache.hive.sensors.named_hive_partition` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_http.py:7:1: AIR302 `airflow.hooks.http_hook.HttpHook` is moved into `htt
|
||||
8 | SimpleHttpOperator()
|
||||
9 | HttpSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-http>=1.0.0` and use `airflow.providers.http.hooks.http.HttpHook` instead.
|
||||
= help: Install `apache-airflow-providers-http>=1.0.0` and use `HttpHook` from `airflow.providers.http.hooks.http` instead.
|
||||
|
||||
AIR302_http.py:8:1: AIR302 [*] `airflow.operators.http_operator.SimpleHttpOperator` is moved into `http` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_http.py:8:1: AIR302 [*] `airflow.operators.http_operator.SimpleHttpOperat
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR302
|
||||
9 | HttpSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-http>=5.0.0` and use `airflow.providers.http.operators.http.HttpOperator` instead.
|
||||
= help: Install `apache-airflow-providers-http>=5.0.0` and use `HttpOperator` from `airflow.providers.http.operators.http` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
3 3 | from airflow.hooks.http_hook import HttpHook
|
||||
@@ -39,4 +39,4 @@ AIR302_http.py:9:1: AIR302 `airflow.sensors.http_sensor.HttpSensor` is moved int
|
||||
9 | HttpSensor()
|
||||
| ^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-http>=1.0.0` and use `airflow.providers.http.sensors.http.HttpSensor` instead.
|
||||
= help: Install `apache-airflow-providers-http>=1.0.0` and use `HttpSensor` from `airflow.providers.http.sensors.http` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_jdbc.py:8:1: AIR302 `airflow.hooks.jdbc_hook.JdbcHook` is moved into `jdb
|
||||
| ^^^^^^^^ AIR302
|
||||
9 | jaydebeapi()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-jdbc>=1.0.0` and use `airflow.providers.jdbc.hooks.jdbc.JdbcHook` instead.
|
||||
= help: Install `apache-airflow-providers-jdbc>=1.0.0` and use `JdbcHook` from `airflow.providers.jdbc.hooks.jdbc` instead.
|
||||
|
||||
AIR302_jdbc.py:9:1: AIR302 `airflow.hooks.jdbc_hook.jaydebeapi` is moved into `jdbc` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -17,4 +17,4 @@ AIR302_jdbc.py:9:1: AIR302 `airflow.hooks.jdbc_hook.jaydebeapi` is moved into `j
|
||||
9 | jaydebeapi()
|
||||
| ^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-jdbc>=1.0.0` and use `airflow.providers.jdbc.hooks.jdbc.jaydebeapi` instead.
|
||||
= help: Install `apache-airflow-providers-jdbc>=1.0.0` and use `jaydebeapi` from `airflow.providers.jdbc.hooks.jdbc` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_kubernetes.py:29:1: AIR302 `airflow.executors.kubernetes_executor_types.A
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
30 | POD_EXECUTOR_DONE_KEY
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.executors.kubernetes_executor_types.ALL_NAMESPACES` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `ALL_NAMESPACES` from `airflow.providers.cncf.kubernetes.executors.kubernetes_executor_types` instead.
|
||||
|
||||
AIR302_kubernetes.py:30:1: AIR302 `airflow.executors.kubernetes_executor_types.POD_EXECUTOR_DONE_KEY` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_kubernetes.py:30:1: AIR302 `airflow.executors.kubernetes_executor_types.P
|
||||
31 |
|
||||
32 | K8SModel()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.executors.kubernetes_executor_types.POD_EXECUTOR_DONE_KEY` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `POD_EXECUTOR_DONE_KEY` from `airflow.providers.cncf.kubernetes.executors.kubernetes_executor_types` instead.
|
||||
|
||||
AIR302_kubernetes.py:32:1: AIR302 `airflow.kubernetes.k8s_model.K8SModel` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -29,7 +29,7 @@ AIR302_kubernetes.py:32:1: AIR302 `airflow.kubernetes.k8s_model.K8SModel` is mov
|
||||
| ^^^^^^^^ AIR302
|
||||
33 | append_to_pod()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.k8s_model.K8SModel` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `K8SModel` from `airflow.providers.cncf.kubernetes.k8s_model` instead.
|
||||
|
||||
AIR302_kubernetes.py:33:1: AIR302 `airflow.kubernetes.k8s_model.append_to_pod` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -39,7 +39,7 @@ AIR302_kubernetes.py:33:1: AIR302 `airflow.kubernetes.k8s_model.append_to_pod` i
|
||||
34 |
|
||||
35 | _disable_verify_ssl()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.k8s_model.append_to_pod` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `append_to_pod` from `airflow.providers.cncf.kubernetes.k8s_model` instead.
|
||||
|
||||
AIR302_kubernetes.py:35:1: AIR302 `airflow.kubernetes.kube_client._disable_verify_ssl` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -50,7 +50,7 @@ AIR302_kubernetes.py:35:1: AIR302 `airflow.kubernetes.kube_client._disable_verif
|
||||
36 | _enable_tcp_keepalive()
|
||||
37 | get_kube_client()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kube_client._disable_verify_ssl` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `_disable_verify_ssl` from `airflow.providers.cncf.kubernetes.kube_client` instead.
|
||||
|
||||
AIR302_kubernetes.py:36:1: AIR302 `airflow.kubernetes.kube_client._enable_tcp_keepalive` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -59,7 +59,7 @@ AIR302_kubernetes.py:36:1: AIR302 `airflow.kubernetes.kube_client._enable_tcp_ke
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
37 | get_kube_client()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kube_client._enable_tcp_keepalive` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `_enable_tcp_keepalive` from `airflow.providers.cncf.kubernetes.kube_client` instead.
|
||||
|
||||
AIR302_kubernetes.py:37:1: AIR302 `airflow.kubernetes.kube_client.get_kube_client` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -70,7 +70,7 @@ AIR302_kubernetes.py:37:1: AIR302 `airflow.kubernetes.kube_client.get_kube_clien
|
||||
38 |
|
||||
39 | add_pod_suffix()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kube_client.get_kube_client` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `get_kube_client` from `airflow.providers.cncf.kubernetes.kube_client` instead.
|
||||
|
||||
AIR302_kubernetes.py:39:1: AIR302 [*] `airflow.kubernetes.kubernetes_helper_functions.add_pod_suffix` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -80,7 +80,7 @@ AIR302_kubernetes.py:39:1: AIR302 [*] `airflow.kubernetes.kubernetes_helper_func
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
40 | create_pod_id()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=10.0.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.add_unique_suffix` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=10.0.0` and use `add_unique_suffix` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
25 25 | Port,
|
||||
@@ -108,7 +108,7 @@ AIR302_kubernetes.py:40:1: AIR302 [*] `airflow.kubernetes.kubernetes_helper_func
|
||||
41 |
|
||||
42 | annotations_for_logging_task_metadata()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=10.0.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.create_unique_id` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=10.0.0` and use `create_unique_id` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
25 25 | Port,
|
||||
@@ -137,7 +137,7 @@ AIR302_kubernetes.py:42:1: AIR302 `airflow.kubernetes.kubernetes_helper_function
|
||||
43 | annotations_to_key()
|
||||
44 | get_logs_task_metadata()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.annotations_for_logging_task_metadata` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `annotations_for_logging_task_metadata` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
AIR302_kubernetes.py:43:1: AIR302 `airflow.kubernetes.kubernetes_helper_functions.annotations_to_key` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -147,7 +147,7 @@ AIR302_kubernetes.py:43:1: AIR302 `airflow.kubernetes.kubernetes_helper_function
|
||||
44 | get_logs_task_metadata()
|
||||
45 | rand_str()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.annotations_to_key` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `annotations_to_key` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
AIR302_kubernetes.py:44:1: AIR302 `airflow.kubernetes.kubernetes_helper_functions.get_logs_task_metadata` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -157,7 +157,7 @@ AIR302_kubernetes.py:44:1: AIR302 `airflow.kubernetes.kubernetes_helper_function
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
45 | rand_str()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.get_logs_task_metadata` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `get_logs_task_metadata` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
AIR302_kubernetes.py:45:1: AIR302 `airflow.kubernetes.kubernetes_helper_functions.rand_str` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -168,7 +168,7 @@ AIR302_kubernetes.py:45:1: AIR302 `airflow.kubernetes.kubernetes_helper_function
|
||||
46 |
|
||||
47 | Port()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.rand_str` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `rand_str` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
AIR302_kubernetes.py:47:1: AIR302 [*] `airflow.kubernetes.pod.Port` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -178,7 +178,7 @@ AIR302_kubernetes.py:47:1: AIR302 [*] `airflow.kubernetes.pod.Port` is moved int
|
||||
| ^^^^ AIR302
|
||||
48 | Resources()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `kubernetes.client.models.V1ContainerPort` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `V1ContainerPort` from `kubernetes.client.models` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
25 25 | Port,
|
||||
@@ -204,7 +204,7 @@ AIR302_kubernetes.py:48:1: AIR302 [*] `airflow.kubernetes.pod.Resources` is move
|
||||
48 | Resources()
|
||||
| ^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `kubernetes.client.models.V1ResourceRequirements` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `V1ResourceRequirements` from `kubernetes.client.models` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
25 25 | Port,
|
||||
@@ -233,7 +233,7 @@ AIR302_kubernetes.py:64:1: AIR302 `airflow.kubernetes.pod_generator.datetime_to_
|
||||
65 | extend_object_field()
|
||||
66 | label_safe_datestring_to_datetime()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.datetime_to_label_safe_datestring` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `datetime_to_label_safe_datestring` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:65:1: AIR302 `airflow.kubernetes.pod_generator.extend_object_field` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -243,7 +243,7 @@ AIR302_kubernetes.py:65:1: AIR302 `airflow.kubernetes.pod_generator.extend_objec
|
||||
66 | label_safe_datestring_to_datetime()
|
||||
67 | make_safe_label_value()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.extend_object_field` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `extend_object_field` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:66:1: AIR302 `airflow.kubernetes.pod_generator.label_safe_datestring_to_datetime` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -254,7 +254,7 @@ AIR302_kubernetes.py:66:1: AIR302 `airflow.kubernetes.pod_generator.label_safe_d
|
||||
67 | make_safe_label_value()
|
||||
68 | merge_objects()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.label_safe_datestring_to_datetime` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `label_safe_datestring_to_datetime` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:67:1: AIR302 `airflow.kubernetes.pod_generator.make_safe_label_value` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -265,7 +265,7 @@ AIR302_kubernetes.py:67:1: AIR302 `airflow.kubernetes.pod_generator.make_safe_la
|
||||
68 | merge_objects()
|
||||
69 | PodGenerator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.make_safe_label_value` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `make_safe_label_value` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:68:1: AIR302 `airflow.kubernetes.pod_generator.merge_objects` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -276,7 +276,7 @@ AIR302_kubernetes.py:68:1: AIR302 `airflow.kubernetes.pod_generator.merge_object
|
||||
69 | PodGenerator()
|
||||
70 | PodDefaults()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.merge_objects` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `merge_objects` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:69:1: AIR302 `airflow.kubernetes.pod_generator.PodGenerator` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -287,7 +287,7 @@ AIR302_kubernetes.py:69:1: AIR302 `airflow.kubernetes.pod_generator.PodGenerator
|
||||
70 | PodDefaults()
|
||||
71 | PodGeneratorDeprecated()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.PodGenerator` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `PodGenerator` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:70:1: AIR302 `airflow.kubernetes.pod_generator.PodDefaults` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -298,7 +298,7 @@ AIR302_kubernetes.py:70:1: AIR302 `airflow.kubernetes.pod_generator.PodDefaults`
|
||||
71 | PodGeneratorDeprecated()
|
||||
72 | add_pod_suffix()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.utils.xcom_sidecar.PodDefaults` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `PodDefaults` from `airflow.providers.cncf.kubernetes.utils.xcom_sidecar` instead.
|
||||
|
||||
AIR302_kubernetes.py:71:1: AIR302 `airflow.kubernetes.pod_generator.PodGeneratorDeprecated` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -309,7 +309,7 @@ AIR302_kubernetes.py:71:1: AIR302 `airflow.kubernetes.pod_generator.PodGenerator
|
||||
72 | add_pod_suffix()
|
||||
73 | rand_str()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.PodGenerator` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `PodGenerator` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:72:1: AIR302 [*] `airflow.kubernetes.pod_generator.add_pod_suffix` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -319,7 +319,7 @@ AIR302_kubernetes.py:72:1: AIR302 [*] `airflow.kubernetes.pod_generator.add_pod_
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
73 | rand_str()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=10.0.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.add_unique_suffix` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=10.0.0` and use `add_unique_suffix` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
60 60 | merge_objects,
|
||||
@@ -346,7 +346,7 @@ AIR302_kubernetes.py:73:1: AIR302 `airflow.kubernetes.pod_generator.rand_str` is
|
||||
73 | rand_str()
|
||||
| ^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kubernetes_helper_functions.rand_str` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `rand_str` from `airflow.providers.cncf.kubernetes.kubernetes_helper_functions` instead.
|
||||
|
||||
AIR302_kubernetes.py:86:1: AIR302 `airflow.kubernetes.pod_generator_deprecated.PodDefaults` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -357,7 +357,7 @@ AIR302_kubernetes.py:86:1: AIR302 `airflow.kubernetes.pod_generator_deprecated.P
|
||||
87 | PodGenerator()
|
||||
88 | make_safe_label_value()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.utils.xcom_sidecar.PodDefaults` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `PodDefaults` from `airflow.providers.cncf.kubernetes.utils.xcom_sidecar` instead.
|
||||
|
||||
AIR302_kubernetes.py:87:1: AIR302 `airflow.kubernetes.pod_generator_deprecated.PodGenerator` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -366,7 +366,7 @@ AIR302_kubernetes.py:87:1: AIR302 `airflow.kubernetes.pod_generator_deprecated.P
|
||||
| ^^^^^^^^^^^^ AIR302
|
||||
88 | make_safe_label_value()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.PodGenerator` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `PodGenerator` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:88:1: AIR302 `airflow.kubernetes.pod_generator_deprecated.make_safe_label_value` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -377,7 +377,7 @@ AIR302_kubernetes.py:88:1: AIR302 `airflow.kubernetes.pod_generator_deprecated.m
|
||||
89 |
|
||||
90 | PodLauncher()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.pod_generator.make_safe_label_value` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `make_safe_label_value` from `airflow.providers.cncf.kubernetes.pod_generator` instead.
|
||||
|
||||
AIR302_kubernetes.py:90:1: AIR302 [*] `airflow.kubernetes.pod_launcher.PodLauncher` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -387,7 +387,7 @@ AIR302_kubernetes.py:90:1: AIR302 [*] `airflow.kubernetes.pod_launcher.PodLaunch
|
||||
| ^^^^^^^^^^^ AIR302
|
||||
91 | PodStatus()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use `airflow.providers.cncf.kubernetes.utils.pod_manager.PodManager` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use `PodManager` from `airflow.providers.cncf.kubernetes.utils.pod_manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
82 82 | PodLauncher,
|
||||
@@ -411,7 +411,7 @@ AIR302_kubernetes.py:91:1: AIR302 [*] `airflow.kubernetes.pod_launcher.PodStatus
|
||||
91 | PodStatus()
|
||||
| ^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use ` airflow.providers.cncf.kubernetes.utils.pod_manager.PodPhase` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use `PodPhase` from ` airflow.providers.cncf.kubernetes.utils.pod_manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
82 82 | PodLauncher,
|
||||
@@ -439,7 +439,7 @@ AIR302_kubernetes.py:108:1: AIR302 `airflow.kubernetes.pod_launcher_deprecated.P
|
||||
109 | PodLauncher()
|
||||
110 | PodStatus()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.utils.xcom_sidecar.PodDefaults` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `PodDefaults` from `airflow.providers.cncf.kubernetes.utils.xcom_sidecar` instead.
|
||||
|
||||
AIR302_kubernetes.py:109:1: AIR302 [*] `airflow.kubernetes.pod_launcher_deprecated.PodLauncher` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -449,7 +449,7 @@ AIR302_kubernetes.py:109:1: AIR302 [*] `airflow.kubernetes.pod_launcher_deprecat
|
||||
110 | PodStatus()
|
||||
111 | get_kube_client()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use `airflow.providers.cncf.kubernetes.utils.pod_manager.PodManager` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use `PodManager` from `airflow.providers.cncf.kubernetes.utils.pod_manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
104 104 | )
|
||||
@@ -472,7 +472,7 @@ AIR302_kubernetes.py:110:1: AIR302 [*] `airflow.kubernetes.pod_launcher_deprecat
|
||||
| ^^^^^^^^^ AIR302
|
||||
111 | get_kube_client()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use ` airflow.providers.cncf.kubernetes.utils.pod_manager.PodPhase` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=3.0.0` and use `PodPhase` from ` airflow.providers.cncf.kubernetes.utils.pod_manager` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
104 104 | )
|
||||
@@ -497,7 +497,7 @@ AIR302_kubernetes.py:111:1: AIR302 `airflow.kubernetes.pod_launcher_deprecated.g
|
||||
112 |
|
||||
113 | PodRuntimeInfoEnv()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.kube_client.get_kube_client` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `get_kube_client` from `airflow.providers.cncf.kubernetes.kube_client` instead.
|
||||
|
||||
AIR302_kubernetes.py:113:1: AIR302 [*] `airflow.kubernetes.pod_runtime_info_env.PodRuntimeInfoEnv` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -508,7 +508,7 @@ AIR302_kubernetes.py:113:1: AIR302 [*] `airflow.kubernetes.pod_runtime_info_env.
|
||||
114 | K8SModel()
|
||||
115 | Secret()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `kubernetes.client.models.V1EnvVar` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `V1EnvVar` from `kubernetes.client.models` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
104 104 | )
|
||||
@@ -535,7 +535,7 @@ AIR302_kubernetes.py:114:1: AIR302 `airflow.kubernetes.secret.K8SModel` is moved
|
||||
115 | Secret()
|
||||
116 | Volume()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.k8s_model.K8SModel` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `K8SModel` from `airflow.providers.cncf.kubernetes.k8s_model` instead.
|
||||
|
||||
AIR302_kubernetes.py:115:1: AIR302 `airflow.kubernetes.secret.Secret` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -546,7 +546,7 @@ AIR302_kubernetes.py:115:1: AIR302 `airflow.kubernetes.secret.Secret` is moved i
|
||||
116 | Volume()
|
||||
117 | VolumeMount()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `airflow.providers.cncf.kubernetes.secret.Secret` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `Secret` from `airflow.providers.cncf.kubernetes.secret` instead.
|
||||
|
||||
AIR302_kubernetes.py:116:1: AIR302 [*] `airflow.kubernetes.volume.Volume` is moved into `cncf-kubernetes` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -556,7 +556,7 @@ AIR302_kubernetes.py:116:1: AIR302 [*] `airflow.kubernetes.volume.Volume` is mov
|
||||
| ^^^^^^ AIR302
|
||||
117 | VolumeMount()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `kubernetes.client.models.V1Volume` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `V1Volume` from `kubernetes.client.models` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
104 104 | )
|
||||
@@ -581,7 +581,7 @@ AIR302_kubernetes.py:117:1: AIR302 [*] `airflow.kubernetes.volume_mount.VolumeMo
|
||||
117 | VolumeMount()
|
||||
| ^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `kubernetes.client.models.V1VolumeMount` instead.
|
||||
= help: Install `apache-airflow-providers-cncf-kubernetes>=7.4.0` and use `V1VolumeMount` from `kubernetes.client.models` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
104 104 | )
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_mysql.py:9:1: AIR302 `airflow.hooks.mysql_hook.MySqlHook` is moved into `
|
||||
10 | PrestoToMySqlOperator()
|
||||
11 | PrestoToMySqlTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-mysql>=1.0.0` and use `airflow.providers.mysql.hooks.mysql.MySqlHook` instead.
|
||||
= help: Install `apache-airflow-providers-mysql>=1.0.0` and use `MySqlHook` from `airflow.providers.mysql.hooks.mysql` instead.
|
||||
|
||||
AIR302_mysql.py:10:1: AIR302 `airflow.operators.presto_to_mysql.PrestoToMySqlOperator` is moved into `mysql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_mysql.py:10:1: AIR302 `airflow.operators.presto_to_mysql.PrestoToMySqlOpe
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
11 | PrestoToMySqlTransfer()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-mysql>=1.0.0` and use `airflow.providers.mysql.transfers.presto_to_mysql.PrestoToMySqlOperator` instead.
|
||||
= help: Install `apache-airflow-providers-mysql>=1.0.0` and use `PrestoToMySqlOperator` from `airflow.providers.mysql.transfers.presto_to_mysql` instead.
|
||||
|
||||
AIR302_mysql.py:11:1: AIR302 `airflow.operators.presto_to_mysql.PrestoToMySqlTransfer` is moved into `mysql` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -28,4 +28,4 @@ AIR302_mysql.py:11:1: AIR302 `airflow.operators.presto_to_mysql.PrestoToMySqlTra
|
||||
11 | PrestoToMySqlTransfer()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-mysql>=1.0.0` and use `airflow.providers.mysql.transfers.presto_to_mysql.PrestoToMySqlOperator` instead.
|
||||
= help: Install `apache-airflow-providers-mysql>=1.0.0` and use `PrestoToMySqlOperator` from `airflow.providers.mysql.transfers.presto_to_mysql` instead.
|
||||
|
||||
@@ -8,4 +8,4 @@ AIR302_oracle.py:5:1: AIR302 `airflow.hooks.oracle_hook.OracleHook` is moved int
|
||||
5 | OracleHook()
|
||||
| ^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-oracle>=1.0.0` and use `airflow.providers.oracle.hooks.oracle.OracleHook` instead.
|
||||
= help: Install `apache-airflow-providers-oracle>=1.0.0` and use `OracleHook` from `airflow.providers.oracle.hooks.oracle` instead.
|
||||
|
||||
@@ -8,4 +8,4 @@ AIR302_papermill.py:5:1: AIR302 `airflow.operators.papermill_operator.PapermillO
|
||||
5 | PapermillOperator()
|
||||
| ^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-papermill>=1.0.0` and use `airflow.providers.papermill.operators.papermill.PapermillOperator` instead.
|
||||
= help: Install `apache-airflow-providers-papermill>=1.0.0` and use `PapermillOperator` from `airflow.providers.papermill.operators.papermill` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_pig.py:6:1: AIR302 `airflow.hooks.pig_hook.PigCliHook` is moved into `apa
|
||||
| ^^^^^^^^^^ AIR302
|
||||
7 | PigOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-pig>=1.0.0` and use `airflow.providers.apache.pig.hooks.pig.PigCliHook` instead.
|
||||
= help: Install `apache-airflow-providers-apache-pig>=1.0.0` and use `PigCliHook` from `airflow.providers.apache.pig.hooks.pig` instead.
|
||||
|
||||
AIR302_pig.py:7:1: AIR302 `airflow.operators.pig_operator.PigOperator` is moved into `apache-pig` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -17,4 +17,4 @@ AIR302_pig.py:7:1: AIR302 `airflow.operators.pig_operator.PigOperator` is moved
|
||||
7 | PigOperator()
|
||||
| ^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-apache-pig>=1.0.0` and use `airflow.providers.apache.pig.operators.pig.PigOperator` instead.
|
||||
= help: Install `apache-airflow-providers-apache-pig>=1.0.0` and use `PigOperator` from `airflow.providers.apache.pig.operators.pig` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR302_postgres.py:6:1: AIR302 `airflow.hooks.postgres_hook.PostgresHook` is mov
|
||||
| ^^^^^^^^^^^^ AIR302
|
||||
7 | Mapping()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-postgres>=1.0.0` and use `airflow.providers.postgres.hooks.postgres.PostgresHook` instead.
|
||||
= help: Install `apache-airflow-providers-postgres>=1.0.0` and use `PostgresHook` from `airflow.providers.postgres.hooks.postgres` instead.
|
||||
|
||||
AIR302_postgres.py:7:1: AIR302 `airflow.operators.postgres_operator.Mapping` is removed in Airflow 3.0
|
||||
|
|
||||
|
||||
@@ -8,4 +8,4 @@ AIR302_presto.py:5:1: AIR302 `airflow.hooks.presto_hook.PrestoHook` is moved int
|
||||
5 | PrestoHook()
|
||||
| ^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-presto>=1.0.0` and use `airflow.providers.presto.hooks.presto.PrestoHook` instead.
|
||||
= help: Install `apache-airflow-providers-presto>=1.0.0` and use `PrestoHook` from `airflow.providers.presto.hooks.presto` instead.
|
||||
|
||||
@@ -8,4 +8,4 @@ AIR302_samba.py:5:1: AIR302 `airflow.hooks.samba_hook.SambaHook` is moved into `
|
||||
5 | SambaHook()
|
||||
| ^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-samba>=1.0.0` and use `airflow.providers.samba.hooks.samba.SambaHook` instead.
|
||||
= help: Install `apache-airflow-providers-samba>=1.0.0` and use `SambaHook` from `airflow.providers.samba.hooks.samba` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_slack.py:6:1: AIR302 `airflow.hooks.slack_hook.SlackHook` is moved into `
|
||||
7 | SlackAPIOperator()
|
||||
8 | SlackAPIPostOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-slack>=1.0.0` and use `airflow.providers.slack.hooks.slack.SlackHook` instead.
|
||||
= help: Install `apache-airflow-providers-slack>=1.0.0` and use `SlackHook` from `airflow.providers.slack.hooks.slack` instead.
|
||||
|
||||
AIR302_slack.py:7:1: AIR302 `airflow.operators.slack_operator.SlackAPIOperator` is moved into `slack` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,7 +19,7 @@ AIR302_slack.py:7:1: AIR302 `airflow.operators.slack_operator.SlackAPIOperator`
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
8 | SlackAPIPostOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-slack>=1.0.0` and use `airflow.providers.slack.operators.slack.SlackAPIOperator` instead.
|
||||
= help: Install `apache-airflow-providers-slack>=1.0.0` and use `SlackAPIOperator` from `airflow.providers.slack.operators.slack` instead.
|
||||
|
||||
AIR302_slack.py:8:1: AIR302 `airflow.operators.slack_operator.SlackAPIPostOperator` is moved into `slack` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -28,4 +28,4 @@ AIR302_slack.py:8:1: AIR302 `airflow.operators.slack_operator.SlackAPIPostOperat
|
||||
8 | SlackAPIPostOperator()
|
||||
| ^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-slack>=1.0.0` and use `airflow.providers.slack.operators.slack.SlackAPIPostOperator` instead.
|
||||
= help: Install `apache-airflow-providers-slack>=1.0.0` and use `SlackAPIPostOperator` from `airflow.providers.slack.operators.slack` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_smtp.py:5:1: AIR302 `airflow.operators.email_operator.EmailOperator` is m
|
||||
6 |
|
||||
7 | from airflow.operators.email import EmailOperator
|
||||
|
|
||||
= help: Install `apache-airflow-providers-smtp>=1.0.0` and use `airflow.providers.smtp.operators.smtp.EmailOperator` instead.
|
||||
= help: Install `apache-airflow-providers-smtp>=1.0.0` and use `EmailOperator` from `airflow.providers.smtp.operators.smtp` instead.
|
||||
|
||||
AIR302_smtp.py:9:1: AIR302 `airflow.operators.email.EmailOperator` is moved into `smtp` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -19,4 +19,4 @@ AIR302_smtp.py:9:1: AIR302 `airflow.operators.email.EmailOperator` is moved into
|
||||
9 | EmailOperator()
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-smtp>=1.0.0` and use `airflow.providers.smtp.operators.smtp.EmailOperator` instead.
|
||||
= help: Install `apache-airflow-providers-smtp>=1.0.0` and use `EmailOperator` from `airflow.providers.smtp.operators.smtp` instead.
|
||||
|
||||
@@ -8,4 +8,4 @@ AIR302_sqlite.py:5:1: AIR302 `airflow.hooks.sqlite_hook.SqliteHook` is moved int
|
||||
5 | SqliteHook()
|
||||
| ^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-sqlite>=1.0.0` and use `airflow.providers.sqlite.hooks.sqlite.SqliteHook` instead.
|
||||
= help: Install `apache-airflow-providers-sqlite>=1.0.0` and use `SqliteHook` from `airflow.providers.sqlite.hooks.sqlite` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR302_standard.py:25:1: AIR302 `airflow.operators.bash_operator.BashOperator` i
|
||||
26 |
|
||||
27 | TriggerDagRunLink()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.bash.BashOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `BashOperator` from `airflow.providers.standard.operators.bash` instead.
|
||||
|
||||
AIR302_standard.py:27:1: AIR302 `airflow.operators.dagrun_operator.TriggerDagRunLink` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -21,7 +21,7 @@ AIR302_standard.py:27:1: AIR302 `airflow.operators.dagrun_operator.TriggerDagRun
|
||||
28 | TriggerDagRunOperator()
|
||||
29 | DummyOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunLink` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `TriggerDagRunLink` from `airflow.providers.standard.operators.trigger_dagrun` instead.
|
||||
|
||||
AIR302_standard.py:28:1: AIR302 `airflow.operators.dagrun_operator.TriggerDagRunOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -31,7 +31,7 @@ AIR302_standard.py:28:1: AIR302 `airflow.operators.dagrun_operator.TriggerDagRun
|
||||
29 | DummyOperator()
|
||||
30 | EmptyOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `TriggerDagRunOperator` from `airflow.providers.standard.operators.trigger_dagrun` instead.
|
||||
|
||||
AIR302_standard.py:29:1: AIR302 `airflow.operators.dummy.DummyOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -41,7 +41,7 @@ AIR302_standard.py:29:1: AIR302 `airflow.operators.dummy.DummyOperator` is moved
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
30 | EmptyOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.empty.EmptyOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `EmptyOperator` from `airflow.providers.standard.operators.empty` instead.
|
||||
|
||||
AIR302_standard.py:30:1: AIR302 `airflow.operators.dummy.EmptyOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -52,7 +52,7 @@ AIR302_standard.py:30:1: AIR302 `airflow.operators.dummy.EmptyOperator` is moved
|
||||
31 |
|
||||
32 | LatestOnlyOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.empty.EmptyOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `EmptyOperator` from `airflow.providers.standard.operators.empty` instead.
|
||||
|
||||
AIR302_standard.py:32:1: AIR302 `airflow.operators.latest_only_operator.LatestOnlyOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -63,7 +63,7 @@ AIR302_standard.py:32:1: AIR302 `airflow.operators.latest_only_operator.LatestOn
|
||||
33 |
|
||||
34 | BranchPythonOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.operators.latest_only.LatestOnlyOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `LatestOnlyOperator` from `airflow.providers.standard.operators.latest_only` instead.
|
||||
|
||||
AIR302_standard.py:34:1: AIR302 `airflow.operators.python_operator.BranchPythonOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -74,7 +74,7 @@ AIR302_standard.py:34:1: AIR302 `airflow.operators.python_operator.BranchPythonO
|
||||
35 | PythonOperator()
|
||||
36 | PythonVirtualenvOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.BranchPythonOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `BranchPythonOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR302_standard.py:35:1: AIR302 `airflow.operators.python_operator.PythonOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -84,7 +84,7 @@ AIR302_standard.py:35:1: AIR302 `airflow.operators.python_operator.PythonOperato
|
||||
36 | PythonVirtualenvOperator()
|
||||
37 | ShortCircuitOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.PythonOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `PythonOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR302_standard.py:36:1: AIR302 `airflow.operators.python_operator.PythonVirtualenvOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -94,7 +94,7 @@ AIR302_standard.py:36:1: AIR302 `airflow.operators.python_operator.PythonVirtual
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
37 | ShortCircuitOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.PythonVirtualenvOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `PythonVirtualenvOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR302_standard.py:37:1: AIR302 `airflow.operators.python_operator.ShortCircuitOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -105,7 +105,7 @@ AIR302_standard.py:37:1: AIR302 `airflow.operators.python_operator.ShortCircuitO
|
||||
38 |
|
||||
39 | ExternalTaskMarker()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.ShortCircuitOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `ShortCircuitOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR302_standard.py:39:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskMarker` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -116,7 +116,7 @@ AIR302_standard.py:39:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTa
|
||||
40 | ExternalTaskSensor()
|
||||
41 | ExternalTaskSensorLink()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.sensors.external_task.ExternalTaskMarker` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `ExternalTaskMarker` from `airflow.providers.standard.sensors.external_task` instead.
|
||||
|
||||
AIR302_standard.py:40:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensor` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -125,7 +125,7 @@ AIR302_standard.py:40:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTa
|
||||
| ^^^^^^^^^^^^^^^^^^ AIR302
|
||||
41 | ExternalTaskSensorLink()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.sensors.external_task.ExternalTaskSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `ExternalTaskSensor` from `airflow.providers.standard.sensors.external_task` instead.
|
||||
|
||||
AIR302_standard.py:41:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensorLink` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -136,7 +136,7 @@ AIR302_standard.py:41:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTa
|
||||
42 |
|
||||
43 | from airflow.operators.dummy_operator import (
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.sensors.external_task.ExternalTaskSensorLink` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `ExternalTaskSensorLink` from `airflow.providers.standard.sensors.external_task` instead.
|
||||
|
||||
AIR302_standard.py:48:1: AIR302 `airflow.operators.dummy_operator.DummyOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -146,7 +146,7 @@ AIR302_standard.py:48:1: AIR302 `airflow.operators.dummy_operator.DummyOperator`
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
49 | EmptyOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.empty.EmptyOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `EmptyOperator` from `airflow.providers.standard.operators.empty` instead.
|
||||
|
||||
AIR302_standard.py:49:1: AIR302 `airflow.operators.dummy_operator.EmptyOperator` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -156,7 +156,7 @@ AIR302_standard.py:49:1: AIR302 `airflow.operators.dummy_operator.EmptyOperator`
|
||||
50 |
|
||||
51 | from airflow.hooks.subprocess import SubprocessResult
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.empty.EmptyOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `EmptyOperator` from `airflow.providers.standard.operators.empty` instead.
|
||||
|
||||
AIR302_standard.py:52:1: AIR302 `airflow.hooks.subprocess.SubprocessResult` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -166,7 +166,7 @@ AIR302_standard.py:52:1: AIR302 `airflow.hooks.subprocess.SubprocessResult` is m
|
||||
53 | from airflow.hooks.subprocess import working_directory
|
||||
54 | working_directory()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.hooks.subprocess.SubprocessResult` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `SubprocessResult` from `airflow.providers.standard.hooks.subprocess` instead.
|
||||
|
||||
AIR302_standard.py:54:1: AIR302 `airflow.hooks.subprocess.working_directory` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -177,7 +177,7 @@ AIR302_standard.py:54:1: AIR302 `airflow.hooks.subprocess.working_directory` is
|
||||
55 | from airflow.operators.datetime import target_times_as_dates
|
||||
56 | target_times_as_dates()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.hooks.subprocess.working_directory` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `working_directory` from `airflow.providers.standard.hooks.subprocess` instead.
|
||||
|
||||
AIR302_standard.py:56:1: AIR302 `airflow.operators.datetime.target_times_as_dates` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -188,7 +188,7 @@ AIR302_standard.py:56:1: AIR302 `airflow.operators.datetime.target_times_as_date
|
||||
57 | from airflow.operators.trigger_dagrun import TriggerDagRunLink
|
||||
58 | TriggerDagRunLink()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.datetime.target_times_as_dates` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `target_times_as_dates` from `airflow.providers.standard.operators.datetime` instead.
|
||||
|
||||
AIR302_standard.py:58:1: AIR302 `airflow.operators.trigger_dagrun.TriggerDagRunLink` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -199,7 +199,7 @@ AIR302_standard.py:58:1: AIR302 `airflow.operators.trigger_dagrun.TriggerDagRunL
|
||||
59 | from airflow.sensors.external_task import ExternalTaskSensorLink
|
||||
60 | ExternalTaskSensorLink()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunLink` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `TriggerDagRunLink` from `airflow.providers.standard.operators.trigger_dagrun` instead.
|
||||
|
||||
AIR302_standard.py:60:1: AIR302 [*] `airflow.sensors.external_task.ExternalTaskSensorLink` is moved into `standard` provider in Airflow 3.0;
|
||||
|
|
||||
@@ -210,7 +210,7 @@ AIR302_standard.py:60:1: AIR302 [*] `airflow.sensors.external_task.ExternalTaskS
|
||||
61 | from airflow.sensors.time_delta import WaitSensor
|
||||
62 | WaitSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.sensors.external_task.ExternalDagLink` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `ExternalDagLink` from `airflow.providers.standard.sensors.external_task` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
57 57 | from airflow.operators.trigger_dagrun import TriggerDagRunLink
|
||||
@@ -229,4 +229,4 @@ AIR302_standard.py:62:1: AIR302 `airflow.sensors.time_delta.WaitSensor` is moved
|
||||
62 | WaitSensor()
|
||||
| ^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.time_delta.WaitSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `WaitSensor` from `airflow.providers.standard.sensors.time_delta` instead.
|
||||
|
||||
@@ -8,4 +8,4 @@ AIR302_zendesk.py:5:1: AIR302 `airflow.hooks.zendesk_hook.ZendeskHook` is moved
|
||||
5 | ZendeskHook()
|
||||
| ^^^^^^^^^^^ AIR302
|
||||
|
|
||||
= help: Install `apache-airflow-providers-zendesk>=1.0.0` and use `airflow.providers.zendesk.hooks.zendesk.ZendeskHook` instead.
|
||||
= help: Install `apache-airflow-providers-zendesk>=1.0.0` and use `ZendeskHook` from `airflow.providers.zendesk.hooks.zendesk` instead.
|
||||
|
||||
@@ -9,7 +9,7 @@ AIR311_names.py:27:1: AIR311 [*] `airflow.Dataset` is removed in Airflow 3.0; It
|
||||
28 |
|
||||
29 | # airflow.datasets
|
||||
|
|
||||
= help: Use `airflow.sdk.Asset` instead
|
||||
= help: Use `Asset` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -32,7 +32,7 @@ AIR311_names.py:30:1: AIR311 [*] `airflow.datasets.Dataset` is removed in Airflo
|
||||
31 | DatasetAlias()
|
||||
32 | DatasetAll()
|
||||
|
|
||||
= help: Use `airflow.sdk.Asset` instead
|
||||
= help: Use `Asset` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -59,7 +59,7 @@ AIR311_names.py:31:1: AIR311 [*] `airflow.datasets.DatasetAlias` is removed in A
|
||||
32 | DatasetAll()
|
||||
33 | DatasetAny()
|
||||
|
|
||||
= help: Use `airflow.sdk.AssetAlias` instead
|
||||
= help: Use `AssetAlias` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -87,7 +87,7 @@ AIR311_names.py:32:1: AIR311 [*] `airflow.datasets.DatasetAll` is removed in Air
|
||||
33 | DatasetAny()
|
||||
34 | Metadata()
|
||||
|
|
||||
= help: Use `airflow.sdk.AssetAll` instead
|
||||
= help: Use `AssetAll` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -116,7 +116,7 @@ AIR311_names.py:33:1: AIR311 [*] `airflow.datasets.DatasetAny` is removed in Air
|
||||
34 | Metadata()
|
||||
35 | expand_alias_to_datasets()
|
||||
|
|
||||
= help: Use `airflow.sdk.AssetAny` instead
|
||||
= help: Use `AssetAny` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -144,7 +144,7 @@ AIR311_names.py:34:1: AIR311 `airflow.datasets.metadata.Metadata` is removed in
|
||||
| ^^^^^^^^ AIR311
|
||||
35 | expand_alias_to_datasets()
|
||||
|
|
||||
= help: Use `airflow.sdk.Metadata` instead
|
||||
= help: Use `Metadata` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:35:1: AIR311 [*] `airflow.datasets.expand_alias_to_datasets` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -155,7 +155,7 @@ AIR311_names.py:35:1: AIR311 [*] `airflow.datasets.expand_alias_to_datasets` is
|
||||
36 |
|
||||
37 | # airflow.decorators
|
||||
|
|
||||
= help: Use `airflow.sdk.expand_alias_to_assets` instead
|
||||
= help: Use `expand_alias_to_assets` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -183,7 +183,7 @@ AIR311_names.py:38:1: AIR311 `airflow.decorators.dag` is removed in Airflow 3.0;
|
||||
39 | task()
|
||||
40 | task_group()
|
||||
|
|
||||
= help: Use `airflow.sdk.dag` instead
|
||||
= help: Use `dag` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:39:1: AIR311 `airflow.decorators.task` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -194,7 +194,7 @@ AIR311_names.py:39:1: AIR311 `airflow.decorators.task` is removed in Airflow 3.0
|
||||
40 | task_group()
|
||||
41 | setup()
|
||||
|
|
||||
= help: Use `airflow.sdk.task` instead
|
||||
= help: Use `task` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:40:1: AIR311 `airflow.decorators.task_group` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -205,7 +205,7 @@ AIR311_names.py:40:1: AIR311 `airflow.decorators.task_group` is removed in Airfl
|
||||
41 | setup()
|
||||
42 | teardown()
|
||||
|
|
||||
= help: Use `airflow.sdk.task_group` instead
|
||||
= help: Use `task_group` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:41:1: AIR311 `airflow.decorators.setup` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -215,7 +215,7 @@ AIR311_names.py:41:1: AIR311 `airflow.decorators.setup` is removed in Airflow 3.
|
||||
| ^^^^^ AIR311
|
||||
42 | teardown()
|
||||
|
|
||||
= help: Use `airflow.sdk.setup` instead
|
||||
= help: Use `setup` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:42:1: AIR311 `airflow.decorators.teardown` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -226,7 +226,7 @@ AIR311_names.py:42:1: AIR311 `airflow.decorators.teardown` is removed in Airflow
|
||||
43 |
|
||||
44 | # airflow.io
|
||||
|
|
||||
= help: Use `airflow.sdk.teardown` instead
|
||||
= help: Use `teardown` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:45:1: AIR311 `airflow.io.path.ObjectStoragePath` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -235,7 +235,7 @@ AIR311_names.py:45:1: AIR311 `airflow.io.path.ObjectStoragePath` is removed in A
|
||||
| ^^^^^^^^^^^^^^^^^ AIR311
|
||||
46 | attach()
|
||||
|
|
||||
= help: Use `airflow.sdk.ObjectStoragePath` instead
|
||||
= help: Use `ObjectStoragePath` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:46:1: AIR311 `airflow.io.storage.attach` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -246,7 +246,7 @@ AIR311_names.py:46:1: AIR311 `airflow.io.storage.attach` is removed in Airflow 3
|
||||
47 |
|
||||
48 | # airflow.models
|
||||
|
|
||||
= help: Use `airflow.sdk.io.attach` instead
|
||||
= help: Use `attach` from `airflow.sdk.io` instead.
|
||||
|
||||
AIR311_names.py:49:1: AIR311 `airflow.models.Connection` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -256,7 +256,7 @@ AIR311_names.py:49:1: AIR311 `airflow.models.Connection` is removed in Airflow 3
|
||||
50 | DAGFromModel()
|
||||
51 | Variable()
|
||||
|
|
||||
= help: Use `airflow.sdk.Connection` instead
|
||||
= help: Use `Connection` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:50:1: AIR311 [*] `airflow.models.DAG` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -266,7 +266,7 @@ AIR311_names.py:50:1: AIR311 [*] `airflow.models.DAG` is removed in Airflow 3.0;
|
||||
| ^^^^^^^^^^^^ AIR311
|
||||
51 | Variable()
|
||||
|
|
||||
= help: Use `airflow.sdk.DAG` instead
|
||||
= help: Use `DAG` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -295,7 +295,7 @@ AIR311_names.py:51:1: AIR311 `airflow.models.Variable` is removed in Airflow 3.0
|
||||
52 |
|
||||
53 | # airflow.models.baseoperator
|
||||
|
|
||||
= help: Use `airflow.sdk.Variable` instead
|
||||
= help: Use `Variable` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:54:1: AIR311 `airflow.models.baseoperator.chain` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -305,7 +305,7 @@ AIR311_names.py:54:1: AIR311 `airflow.models.baseoperator.chain` is removed in A
|
||||
55 | chain_linear()
|
||||
56 | cross_downstream()
|
||||
|
|
||||
= help: Use `airflow.sdk.chain` instead
|
||||
= help: Use `chain` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:55:1: AIR311 `airflow.models.baseoperator.chain_linear` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -315,7 +315,7 @@ AIR311_names.py:55:1: AIR311 `airflow.models.baseoperator.chain_linear` is remov
|
||||
| ^^^^^^^^^^^^ AIR311
|
||||
56 | cross_downstream()
|
||||
|
|
||||
= help: Use `airflow.sdk.chain_linear` instead
|
||||
= help: Use `chain_linear` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:56:1: AIR311 `airflow.models.baseoperator.cross_downstream` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -326,7 +326,7 @@ AIR311_names.py:56:1: AIR311 `airflow.models.baseoperator.cross_downstream` is r
|
||||
57 |
|
||||
58 | # airflow.models.baseoperatolinker
|
||||
|
|
||||
= help: Use `airflow.sdk.cross_downstream` instead
|
||||
= help: Use `cross_downstream` from `airflow.sdk` instead.
|
||||
|
||||
AIR311_names.py:59:1: AIR311 `airflow.models.baseoperatorlink.BaseOperatorLink` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -336,7 +336,7 @@ AIR311_names.py:59:1: AIR311 `airflow.models.baseoperatorlink.BaseOperatorLink`
|
||||
60 |
|
||||
61 | # airflow.models.dag
|
||||
|
|
||||
= help: Use `airflow.sdk.definitions.baseoperatorlink.BaseOperatorLink` instead
|
||||
= help: Use `BaseOperatorLink` from `airflow.sdk.definitions.baseoperatorlink` instead.
|
||||
|
||||
AIR311_names.py:62:1: AIR311 [*] `airflow.models.dag.DAG` is removed in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -346,7 +346,7 @@ AIR311_names.py:62:1: AIR311 [*] `airflow.models.dag.DAG` is removed in Airflow
|
||||
63 | # airflow.timetables.datasets
|
||||
64 | DatasetOrTimeSchedule()
|
||||
|
|
||||
= help: Use `airflow.sdk.DAG` instead
|
||||
= help: Use `DAG` from `airflow.sdk` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -375,7 +375,7 @@ AIR311_names.py:64:1: AIR311 [*] `airflow.timetables.datasets.DatasetOrTimeSched
|
||||
65 |
|
||||
66 | # airflow.utils.dag_parsing_context
|
||||
|
|
||||
= help: Use `airflow.timetables.assets.AssetOrTimeSchedule` instead
|
||||
= help: Use `AssetOrTimeSchedule` from `airflow.timetables.assets` instead.
|
||||
|
||||
ℹ Safe fix
|
||||
22 22 | from airflow.models.dag import DAG as DAGFromDag
|
||||
@@ -401,4 +401,4 @@ AIR311_names.py:67:1: AIR311 `airflow.utils.dag_parsing_context.get_parsing_cont
|
||||
67 | get_parsing_context()
|
||||
| ^^^^^^^^^^^^^^^^^^^ AIR311
|
||||
|
|
||||
= help: Use `airflow.sdk.get_parsing_context` instead
|
||||
= help: Use `get_parsing_context` from `airflow.sdk` instead.
|
||||
|
||||
@@ -10,7 +10,7 @@ AIR312.py:32:1: AIR312 `airflow.hooks.filesystem.FSHook` is deprecated and moved
|
||||
33 | PackageIndexHook()
|
||||
34 | SubprocessHook()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.hooks.filesystem.FSHook` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `FSHook` from `airflow.providers.standard.hooks.filesystem` instead.
|
||||
|
||||
AIR312.py:33:1: AIR312 `airflow.hooks.package_index.PackageIndexHook` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -20,7 +20,7 @@ AIR312.py:33:1: AIR312 `airflow.hooks.package_index.PackageIndexHook` is depreca
|
||||
34 | SubprocessHook()
|
||||
35 | BashOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.hooks.package_index.PackageIndexHook` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `PackageIndexHook` from `airflow.providers.standard.hooks.package_index` instead.
|
||||
|
||||
AIR312.py:34:1: AIR312 `airflow.hooks.subprocess.SubprocessHook` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -31,7 +31,7 @@ AIR312.py:34:1: AIR312 `airflow.hooks.subprocess.SubprocessHook` is deprecated a
|
||||
35 | BashOperator()
|
||||
36 | BranchDateTimeOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.hooks.subprocess.SubprocessHook` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `SubprocessHook` from `airflow.providers.standard.hooks.subprocess` instead.
|
||||
|
||||
AIR312.py:35:1: AIR312 `airflow.operators.bash.BashOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -42,7 +42,7 @@ AIR312.py:35:1: AIR312 `airflow.operators.bash.BashOperator` is deprecated and m
|
||||
36 | BranchDateTimeOperator()
|
||||
37 | TriggerDagRunOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.bash.BashOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `BashOperator` from `airflow.providers.standard.operators.bash` instead.
|
||||
|
||||
AIR312.py:36:1: AIR312 `airflow.operators.datetime.BranchDateTimeOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -53,7 +53,7 @@ AIR312.py:36:1: AIR312 `airflow.operators.datetime.BranchDateTimeOperator` is de
|
||||
37 | TriggerDagRunOperator()
|
||||
38 | EmptyOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.datetime.BranchDateTimeOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `BranchDateTimeOperator` from `airflow.providers.standard.operators.datetime` instead.
|
||||
|
||||
AIR312.py:37:1: AIR312 `airflow.operators.trigger_dagrun.TriggerDagRunOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -64,7 +64,7 @@ AIR312.py:37:1: AIR312 `airflow.operators.trigger_dagrun.TriggerDagRunOperator`
|
||||
38 | EmptyOperator()
|
||||
39 | LatestOnlyOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `TriggerDagRunOperator` from `airflow.providers.standard.operators.trigger_dagrun` instead.
|
||||
|
||||
AIR312.py:38:1: AIR312 `airflow.operators.empty.EmptyOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -75,7 +75,7 @@ AIR312.py:38:1: AIR312 `airflow.operators.empty.EmptyOperator` is deprecated and
|
||||
39 | LatestOnlyOperator()
|
||||
40 | (
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.operators.empty.EmptyOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `EmptyOperator` from `airflow.providers.standard.operators.empty` instead.
|
||||
|
||||
AIR312.py:39:1: AIR312 `airflow.operators.latest_only.LatestOnlyOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -86,7 +86,7 @@ AIR312.py:39:1: AIR312 `airflow.operators.latest_only.LatestOnlyOperator` is dep
|
||||
40 | (
|
||||
41 | BranchPythonOperator(),
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.operators.latest_only.LatestOnlyOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `LatestOnlyOperator` from `airflow.providers.standard.operators.latest_only` instead.
|
||||
|
||||
AIR312.py:41:5: AIR312 `airflow.operators.python.BranchPythonOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -97,7 +97,7 @@ AIR312.py:41:5: AIR312 `airflow.operators.python.BranchPythonOperator` is deprec
|
||||
42 | PythonOperator(),
|
||||
43 | PythonVirtualenvOperator(),
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.BranchPythonOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `BranchPythonOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR312.py:42:5: AIR312 `airflow.operators.python.PythonOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -108,7 +108,7 @@ AIR312.py:42:5: AIR312 `airflow.operators.python.PythonOperator` is deprecated a
|
||||
43 | PythonVirtualenvOperator(),
|
||||
44 | ShortCircuitOperator(),
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.PythonOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `PythonOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR312.py:43:5: AIR312 `airflow.operators.python.PythonVirtualenvOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -119,7 +119,7 @@ AIR312.py:43:5: AIR312 `airflow.operators.python.PythonVirtualenvOperator` is de
|
||||
44 | ShortCircuitOperator(),
|
||||
45 | )
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.PythonVirtualenvOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `PythonVirtualenvOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR312.py:44:5: AIR312 `airflow.operators.python.ShortCircuitOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -130,7 +130,7 @@ AIR312.py:44:5: AIR312 `airflow.operators.python.ShortCircuitOperator` is deprec
|
||||
45 | )
|
||||
46 | BranchDayOfWeekOperator()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.python.ShortCircuitOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `ShortCircuitOperator` from `airflow.providers.standard.operators.python` instead.
|
||||
|
||||
AIR312.py:46:1: AIR312 `airflow.operators.weekday.BranchDayOfWeekOperator` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -141,7 +141,7 @@ AIR312.py:46:1: AIR312 `airflow.operators.weekday.BranchDayOfWeekOperator` is de
|
||||
47 | DateTimeSensor(), DateTimeSensorAsync()
|
||||
48 | ExternalTaskMarker(), ExternalTaskSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.operators.weekday.BranchDayOfWeekOperator` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `BranchDayOfWeekOperator` from `airflow.providers.standard.operators.weekday` instead.
|
||||
|
||||
AIR312.py:47:1: AIR312 `airflow.sensors.date_time.DateTimeSensor` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -152,7 +152,7 @@ AIR312.py:47:1: AIR312 `airflow.sensors.date_time.DateTimeSensor` is deprecated
|
||||
48 | ExternalTaskMarker(), ExternalTaskSensor()
|
||||
49 | FileSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.date_time.DateTimeSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `DateTimeSensor` from `airflow.providers.standard.sensors.date_time` instead.
|
||||
|
||||
AIR312.py:47:19: AIR312 `airflow.sensors.date_time.DateTimeSensorAsync` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -163,7 +163,7 @@ AIR312.py:47:19: AIR312 `airflow.sensors.date_time.DateTimeSensorAsync` is depre
|
||||
48 | ExternalTaskMarker(), ExternalTaskSensor()
|
||||
49 | FileSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.date_time.DateTimeSensorAsync` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `DateTimeSensorAsync` from `airflow.providers.standard.sensors.date_time` instead.
|
||||
|
||||
AIR312.py:48:1: AIR312 `airflow.sensors.external_task.ExternalTaskMarker` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -174,7 +174,7 @@ AIR312.py:48:1: AIR312 `airflow.sensors.external_task.ExternalTaskMarker` is dep
|
||||
49 | FileSensor()
|
||||
50 | TimeSensor(), TimeSensorAsync()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.sensors.external_task.ExternalTaskMarker` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `ExternalTaskMarker` from `airflow.providers.standard.sensors.external_task` instead.
|
||||
|
||||
AIR312.py:48:23: AIR312 `airflow.sensors.external_task.ExternalTaskSensor` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -185,7 +185,7 @@ AIR312.py:48:23: AIR312 `airflow.sensors.external_task.ExternalTaskSensor` is de
|
||||
49 | FileSensor()
|
||||
50 | TimeSensor(), TimeSensorAsync()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.sensors.external_task.ExternalTaskSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `ExternalTaskSensor` from `airflow.providers.standard.sensors.external_task` instead.
|
||||
|
||||
AIR312.py:49:1: AIR312 `airflow.sensors.filesystem.FileSensor` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -196,7 +196,7 @@ AIR312.py:49:1: AIR312 `airflow.sensors.filesystem.FileSensor` is deprecated and
|
||||
50 | TimeSensor(), TimeSensorAsync()
|
||||
51 | TimeDeltaSensor(), TimeDeltaSensorAsync()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `airflow.providers.standard.sensors.filesystem.FileSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.2` and use `FileSensor` from `airflow.providers.standard.sensors.filesystem` instead.
|
||||
|
||||
AIR312.py:50:1: AIR312 `airflow.sensors.time_sensor.TimeSensor` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -207,7 +207,7 @@ AIR312.py:50:1: AIR312 `airflow.sensors.time_sensor.TimeSensor` is deprecated an
|
||||
51 | TimeDeltaSensor(), TimeDeltaSensorAsync()
|
||||
52 | DayOfWeekSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.time.TimeSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `TimeSensor` from `airflow.providers.standard.sensors.time` instead.
|
||||
|
||||
AIR312.py:50:15: AIR312 `airflow.sensors.time_sensor.TimeSensorAsync` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -218,7 +218,7 @@ AIR312.py:50:15: AIR312 `airflow.sensors.time_sensor.TimeSensorAsync` is depreca
|
||||
51 | TimeDeltaSensor(), TimeDeltaSensorAsync()
|
||||
52 | DayOfWeekSensor()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.time.TimeSensorAsync` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `TimeSensorAsync` from `airflow.providers.standard.sensors.time` instead.
|
||||
|
||||
AIR312.py:51:1: AIR312 `airflow.sensors.time_delta.TimeDeltaSensor` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -229,7 +229,7 @@ AIR312.py:51:1: AIR312 `airflow.sensors.time_delta.TimeDeltaSensor` is deprecate
|
||||
52 | DayOfWeekSensor()
|
||||
53 | DagStateTrigger(), WorkflowTrigger()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.time_delta.TimeDeltaSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `TimeDeltaSensor` from `airflow.providers.standard.sensors.time_delta` instead.
|
||||
|
||||
AIR312.py:51:20: AIR312 `airflow.sensors.time_delta.TimeDeltaSensorAsync` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -240,7 +240,7 @@ AIR312.py:51:20: AIR312 `airflow.sensors.time_delta.TimeDeltaSensorAsync` is dep
|
||||
52 | DayOfWeekSensor()
|
||||
53 | DagStateTrigger(), WorkflowTrigger()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.time_delta.TimeDeltaSensorAsync` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `TimeDeltaSensorAsync` from `airflow.providers.standard.sensors.time_delta` instead.
|
||||
|
||||
AIR312.py:52:1: AIR312 `airflow.sensors.weekday.DayOfWeekSensor` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -251,7 +251,7 @@ AIR312.py:52:1: AIR312 `airflow.sensors.weekday.DayOfWeekSensor` is deprecated a
|
||||
53 | DagStateTrigger(), WorkflowTrigger()
|
||||
54 | FileTrigger()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `airflow.providers.standard.sensors.weekday.DayOfWeekSensor` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.1` and use `DayOfWeekSensor` from `airflow.providers.standard.sensors.weekday` instead.
|
||||
|
||||
AIR312.py:53:1: AIR312 `airflow.triggers.external_task.DagStateTrigger` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -262,7 +262,7 @@ AIR312.py:53:1: AIR312 `airflow.triggers.external_task.DagStateTrigger` is depre
|
||||
54 | FileTrigger()
|
||||
55 | DateTimeTrigger(), TimeDeltaTrigger()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.triggers.external_task.DagStateTrigger` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `DagStateTrigger` from `airflow.providers.standard.triggers.external_task` instead.
|
||||
|
||||
AIR312.py:53:20: AIR312 `airflow.triggers.external_task.WorkflowTrigger` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -273,7 +273,7 @@ AIR312.py:53:20: AIR312 `airflow.triggers.external_task.WorkflowTrigger` is depr
|
||||
54 | FileTrigger()
|
||||
55 | DateTimeTrigger(), TimeDeltaTrigger()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.triggers.external_task.WorkflowTrigger` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `WorkflowTrigger` from `airflow.providers.standard.triggers.external_task` instead.
|
||||
|
||||
AIR312.py:54:1: AIR312 `airflow.triggers.file.FileTrigger` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -283,7 +283,7 @@ AIR312.py:54:1: AIR312 `airflow.triggers.file.FileTrigger` is deprecated and mov
|
||||
| ^^^^^^^^^^^ AIR312
|
||||
55 | DateTimeTrigger(), TimeDeltaTrigger()
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.triggers.file.FileTrigger` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `FileTrigger` from `airflow.providers.standard.triggers.file` instead.
|
||||
|
||||
AIR312.py:55:1: AIR312 `airflow.triggers.temporal.DateTimeTrigger` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -292,7 +292,7 @@ AIR312.py:55:1: AIR312 `airflow.triggers.temporal.DateTimeTrigger` is deprecated
|
||||
55 | DateTimeTrigger(), TimeDeltaTrigger()
|
||||
| ^^^^^^^^^^^^^^^ AIR312
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.triggers.temporal.DateTimeTrigger` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `DateTimeTrigger` from `airflow.providers.standard.triggers.temporal` instead.
|
||||
|
||||
AIR312.py:55:20: AIR312 `airflow.triggers.temporal.TimeDeltaTrigger` is deprecated and moved into `standard` provider in Airflow 3.0; It still works in Airflow 3.0 but is expected to be removed in a future version.
|
||||
|
|
||||
@@ -301,4 +301,4 @@ AIR312.py:55:20: AIR312 `airflow.triggers.temporal.TimeDeltaTrigger` is deprecat
|
||||
55 | DateTimeTrigger(), TimeDeltaTrigger()
|
||||
| ^^^^^^^^^^^^^^^^ AIR312
|
||||
|
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `airflow.providers.standard.triggers.temporal.TimeDeltaTrigger` instead.
|
||||
= help: Install `apache-airflow-providers-standard>=0.0.3` and use `TimeDeltaTrigger` from `airflow.providers.standard.triggers.temporal` instead.
|
||||
|
||||
@@ -52,17 +52,20 @@ impl Violation for SysVersionCmpStr3 {
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for equality comparisons against the major version returned by
|
||||
/// `sys.version_info` (e.g., `sys.version_info[0] == 3`).
|
||||
/// `sys.version_info` (e.g., `sys.version_info[0] == 3` or `sys.version_info[0] != 3`).
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Using `sys.version_info[0] == 3` to verify that the major version is
|
||||
/// Python 3 or greater will fail if the major version number is ever
|
||||
/// incremented (e.g., to Python 4). This is likely unintended, as code
|
||||
/// that uses this comparison is likely intended to be run on Python 2,
|
||||
/// but would now run on Python 4 too.
|
||||
/// but would now run on Python 4 too. Similarly, using `sys.version_info[0] != 3`
|
||||
/// to check for Python 2 will also fail if the major version number is
|
||||
/// incremented.
|
||||
///
|
||||
/// Instead, use `>=` to check if the major version number is 3 or greater,
|
||||
/// to future-proof the code.
|
||||
/// or `<` to check if the major version number is less than 3, to future-proof
|
||||
/// the code.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
@@ -88,12 +91,18 @@ impl Violation for SysVersionCmpStr3 {
|
||||
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
|
||||
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct SysVersionInfo0Eq3;
|
||||
pub(crate) struct SysVersionInfo0Eq3 {
|
||||
eq: bool,
|
||||
}
|
||||
|
||||
impl Violation for SysVersionInfo0Eq3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
"`sys.version_info[0] == 3` referenced (python4), use `>=`".to_string()
|
||||
if self.eq {
|
||||
"`sys.version_info[0] == 3` referenced (python4), use `>=`".to_string()
|
||||
} else {
|
||||
"`sys.version_info[0] != 3` referenced (python4), use `<`".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +244,7 @@ pub(crate) fn compare(checker: &Checker, left: &Expr, ops: &[CmpOp], comparators
|
||||
{
|
||||
if *i == 0 {
|
||||
if let (
|
||||
[CmpOp::Eq | CmpOp::NotEq],
|
||||
[operator @ (CmpOp::Eq | CmpOp::NotEq)],
|
||||
[
|
||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(n),
|
||||
@@ -246,7 +255,9 @@ pub(crate) fn compare(checker: &Checker, left: &Expr, ops: &[CmpOp], comparators
|
||||
{
|
||||
if *n == 3 && checker.enabled(Rule::SysVersionInfo0Eq3) {
|
||||
checker.report_diagnostic(Diagnostic::new(
|
||||
SysVersionInfo0Eq3,
|
||||
SysVersionInfo0Eq3 {
|
||||
eq: matches!(*operator, CmpOp::Eq),
|
||||
},
|
||||
left.range(),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ YTT201.py:8:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
||||
10 | PY2 = version_info[0] != 3
|
||||
|
|
||||
|
||||
YTT201.py:9:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
||||
YTT201.py:9:7: YTT201 `sys.version_info[0] != 3` referenced (python4), use `<`
|
||||
|
|
||||
7 | PY3 = sys.version_info[0] == 3
|
||||
8 | PY3 = version_info[0] == 3
|
||||
@@ -29,7 +29,7 @@ YTT201.py:9:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
||||
10 | PY2 = version_info[0] != 3
|
||||
|
|
||||
|
||||
YTT201.py:10:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
||||
YTT201.py:10:7: YTT201 `sys.version_info[0] != 3` referenced (python4), use `<`
|
||||
|
|
||||
8 | PY3 = version_info[0] == 3
|
||||
9 | PY2 = sys.version_info[0] != 3
|
||||
|
||||
@@ -62,7 +62,25 @@ pub(crate) fn async_zero_sleep(checker: &Checker, call: &ExprCall) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(arg) = call.arguments.find_argument_value("seconds", 0) else {
|
||||
let Some(qualified_name) = checker
|
||||
.semantic()
|
||||
.resolve_qualified_name(call.func.as_ref())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(module) = AsyncModule::try_from(&qualified_name) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Determine the correct argument name
|
||||
let arg_name = match module {
|
||||
AsyncModule::Trio => "seconds",
|
||||
AsyncModule::AnyIo => "delay",
|
||||
AsyncModule::AsyncIo => return,
|
||||
};
|
||||
|
||||
let Some(arg) = call.arguments.find_argument_value(arg_name, 0) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -71,7 +71,25 @@ pub(crate) fn long_sleep_not_forever(checker: &Checker, call: &ExprCall) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(arg) = call.arguments.find_argument_value("seconds", 0) else {
|
||||
let Some(qualified_name) = checker
|
||||
.semantic()
|
||||
.resolve_qualified_name(call.func.as_ref())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(module) = AsyncModule::try_from(&qualified_name) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Determine the correct argument name
|
||||
let arg_name = match module {
|
||||
AsyncModule::Trio => "seconds",
|
||||
AsyncModule::AnyIo => "delay",
|
||||
AsyncModule::AsyncIo => return,
|
||||
};
|
||||
|
||||
let Some(arg) = call.arguments.find_argument_value(arg_name, 0) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -214,3 +214,41 @@ ASYNC115.py:128:15: ASYNC115 [*] Use `anyio.lowlevel.checkpoint()` instead of `a
|
||||
129 129 |
|
||||
130 130 |
|
||||
131 131 | def func():
|
||||
|
||||
ASYNC115.py:156:11: ASYNC115 [*] Use `anyio.lowlevel.checkpoint()` instead of `anyio.sleep(0)`
|
||||
|
|
||||
154 | await anyio.sleep(seconds=1) # OK
|
||||
155 |
|
||||
156 | await anyio.sleep(delay=0) # ASYNC115
|
||||
| ^^^^^^^^^^^^^^^^^^^^ ASYNC115
|
||||
157 | await anyio.sleep(seconds=0) # OK
|
||||
|
|
||||
= help: Replace with `anyio.lowlevel.checkpoint()`
|
||||
|
||||
ℹ Safe fix
|
||||
153 153 | await anyio.sleep(delay=1) # OK
|
||||
154 154 | await anyio.sleep(seconds=1) # OK
|
||||
155 155 |
|
||||
156 |- await anyio.sleep(delay=0) # ASYNC115
|
||||
156 |+ await anyio.lowlevel.checkpoint() # ASYNC115
|
||||
157 157 | await anyio.sleep(seconds=0) # OK
|
||||
158 158 |
|
||||
159 159 |
|
||||
|
||||
ASYNC115.py:166:11: ASYNC115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)`
|
||||
|
|
||||
164 | await trio.sleep(delay=1) # OK
|
||||
165 |
|
||||
166 | await trio.sleep(seconds=0) # ASYNC115
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ ASYNC115
|
||||
167 | await trio.sleep(delay=0) # OK
|
||||
|
|
||||
= help: Replace with `trio.lowlevel.checkpoint()`
|
||||
|
||||
ℹ Safe fix
|
||||
163 163 | await trio.sleep(seconds=1) # OK
|
||||
164 164 | await trio.sleep(delay=1) # OK
|
||||
165 165 |
|
||||
166 |- await trio.sleep(seconds=0) # ASYNC115
|
||||
166 |+ await trio.lowlevel.checkpoint() # ASYNC115
|
||||
167 167 | await trio.sleep(delay=0) # OK
|
||||
|
||||
@@ -289,3 +289,44 @@ ASYNC116.py:110:11: ASYNC116 [*] `anyio.sleep()` with >24 hour interval should u
|
||||
109 110 | # catch from import
|
||||
110 |- await sleep(86401) # error: 116, "async"
|
||||
111 |+ await sleep_forever() # error: 116, "async"
|
||||
111 112 |
|
||||
112 113 |
|
||||
113 114 | async def test_anyio_async116_helpers():
|
||||
|
||||
ASYNC116.py:119:11: ASYNC116 [*] `anyio.sleep()` with >24 hour interval should usually be `anyio.sleep_forever()`
|
||||
|
|
||||
117 | await anyio.sleep(seconds=1) # OK
|
||||
118 |
|
||||
119 | await anyio.sleep(delay=86401) # ASYNC116
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC116
|
||||
120 | await anyio.sleep(seconds=86401) # OK
|
||||
|
|
||||
= help: Replace with `anyio.sleep_forever()`
|
||||
|
||||
ℹ Unsafe fix
|
||||
116 116 | await anyio.sleep(delay=1) # OK
|
||||
117 117 | await anyio.sleep(seconds=1) # OK
|
||||
118 118 |
|
||||
119 |- await anyio.sleep(delay=86401) # ASYNC116
|
||||
119 |+ await anyio.sleep_forever() # ASYNC116
|
||||
120 120 | await anyio.sleep(seconds=86401) # OK
|
||||
121 121 |
|
||||
122 122 |
|
||||
|
||||
ASYNC116.py:129:11: ASYNC116 [*] `trio.sleep()` with >24 hour interval should usually be `trio.sleep_forever()`
|
||||
|
|
||||
127 | await trio.sleep(delay=1) # OK
|
||||
128 |
|
||||
129 | await trio.sleep(seconds=86401) # ASYNC116
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ASYNC116
|
||||
130 | await trio.sleep(delay=86401) # OK
|
||||
|
|
||||
= help: Replace with `trio.sleep_forever()`
|
||||
|
||||
ℹ Unsafe fix
|
||||
126 126 | await trio.sleep(seconds=1) # OK
|
||||
127 127 | await trio.sleep(delay=1) # OK
|
||||
128 128 |
|
||||
129 |- await trio.sleep(seconds=86401) # ASYNC116
|
||||
129 |+ await trio.sleep_forever() # ASYNC116
|
||||
130 130 | await trio.sleep(delay=86401) # OK
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use itertools::Itertools;
|
||||
use ruff_python_ast::{Alias, Stmt};
|
||||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Fix};
|
||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
@@ -123,9 +123,19 @@ pub(crate) fn unnecessary_future_import(checker: &Checker, stmt: &Stmt, names: &
|
||||
checker.stylist(),
|
||||
checker.indexer(),
|
||||
)?;
|
||||
Ok(Fix::safe_edit(edit).isolate(Checker::isolation(
|
||||
checker.semantic().current_statement_parent_id(),
|
||||
)))
|
||||
|
||||
let range = edit.range();
|
||||
let applicability = if checker.comment_ranges().intersects(range) {
|
||||
Applicability::Unsafe
|
||||
} else {
|
||||
Applicability::Safe
|
||||
};
|
||||
|
||||
Ok(
|
||||
Fix::applicable_edit(edit, applicability).isolate(Checker::isolation(
|
||||
checker.semantic().current_statement_parent_id(),
|
||||
)),
|
||||
)
|
||||
});
|
||||
checker.report_diagnostic(diagnostic);
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ UP010.py:13:5: UP010 [*] Unnecessary `__future__` import `generator_stop` for ta
|
||||
13 | from __future__ import generator_stop
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP010
|
||||
14 | from __future__ import invalid_module, generators
|
||||
15 | from __future__ import generators # comment
|
||||
|
|
||||
= help: Remove unnecessary `__future__` import
|
||||
|
||||
@@ -165,6 +166,7 @@ UP010.py:13:5: UP010 [*] Unnecessary `__future__` import `generator_stop` for ta
|
||||
12 12 | if True:
|
||||
13 |- from __future__ import generator_stop
|
||||
14 13 | from __future__ import invalid_module, generators
|
||||
15 14 | from __future__ import generators # comment
|
||||
|
||||
UP010.py:14:5: UP010 [*] Unnecessary `__future__` import `generators` for target Python version
|
||||
|
|
||||
@@ -172,6 +174,7 @@ UP010.py:14:5: UP010 [*] Unnecessary `__future__` import `generators` for target
|
||||
13 | from __future__ import generator_stop
|
||||
14 | from __future__ import invalid_module, generators
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP010
|
||||
15 | from __future__ import generators # comment
|
||||
|
|
||||
= help: Remove unnecessary `__future__` import
|
||||
|
||||
@@ -181,3 +184,19 @@ UP010.py:14:5: UP010 [*] Unnecessary `__future__` import `generators` for target
|
||||
13 13 | from __future__ import generator_stop
|
||||
14 |- from __future__ import invalid_module, generators
|
||||
14 |+ from __future__ import invalid_module
|
||||
15 15 | from __future__ import generators # comment
|
||||
|
||||
UP010.py:15:5: UP010 [*] Unnecessary `__future__` import `generators` for target Python version
|
||||
|
|
||||
13 | from __future__ import generator_stop
|
||||
14 | from __future__ import invalid_module, generators
|
||||
15 | from __future__ import generators # comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP010
|
||||
|
|
||||
= help: Remove unnecessary `__future__` import
|
||||
|
||||
ℹ Unsafe fix
|
||||
12 12 | if True:
|
||||
13 13 | from __future__ import generator_stop
|
||||
14 14 | from __future__ import invalid_module, generators
|
||||
15 |- from __future__ import generators # comment
|
||||
|
||||
@@ -41,6 +41,8 @@ getrandom = { workspace = true, features = ["wasm_js"] }
|
||||
serde = { workspace = true }
|
||||
serde-wasm-bindgen = { workspace = true }
|
||||
wasm-bindgen = { workspace = true }
|
||||
# Not a direct dependency but required to compile for Wasm.
|
||||
uuid = { workspace = true, features = ["js"] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = { workspace = true }
|
||||
|
||||
7
crates/ty/docs/cli.md
generated
7
crates/ty/docs/cli.md
generated
@@ -1,3 +1,5 @@
|
||||
<!-- WARNING: This file is auto-generated (cargo dev generate-all). Edit the doc comments in 'crates/ty/src/args.rs' if you want to change anything here. -->
|
||||
|
||||
# CLI Reference
|
||||
|
||||
## ty
|
||||
@@ -41,7 +43,10 @@ ty check [OPTIONS] [PATH]...
|
||||
<li><code>auto</code>: Display colors if the output goes to an interactive terminal</li>
|
||||
<li><code>always</code>: Always display colors</li>
|
||||
<li><code>never</code>: Never display colors</li>
|
||||
</ul></dd><dt id="ty-check--config"><a href="#ty-check--config"><code>--config</code></a>, <code>-c</code> <i>config-option</i></dt><dd><p>A TOML <code><KEY> = <VALUE></code> pair</p>
|
||||
</ul></dd><dt id="ty-check--config"><a href="#ty-check--config"><code>--config</code></a>, <code>-c</code> <i>config-option</i></dt><dd><p>A TOML <code><KEY> = <VALUE></code> pair (such as you might find in a <code>ty.toml</code> configuration file)
|
||||
overriding a specific configuration option.</p>
|
||||
<p>Overrides of individual settings using this option always take precedence
|
||||
over all configuration files.</p>
|
||||
</dd><dt id="ty-check--error"><a href="#ty-check--error"><code>--error</code></a> <i>rule</i></dt><dd><p>Treat the given rule as having severity 'error'. Can be specified multiple times.</p>
|
||||
</dd><dt id="ty-check--error-on-warning"><a href="#ty-check--error-on-warning"><code>--error-on-warning</code></a></dt><dd><p>Use exit code 1 if there are any warning-level diagnostics</p>
|
||||
</dd><dt id="ty-check--exit-zero"><a href="#ty-check--exit-zero"><code>--exit-zero</code></a></dt><dd><p>Always use exit code 0, even when there are error-level diagnostics</p>
|
||||
|
||||
5
crates/ty/docs/configuration.md
generated
5
crates/ty/docs/configuration.md
generated
@@ -1,3 +1,5 @@
|
||||
<!-- WARNING: This file is auto-generated (cargo dev generate-all). Update the doc comments on the 'Options' struct in 'crates/ty_project/src/metadata/options.rs' if you want to change anything here. -->
|
||||
|
||||
# Configuration
|
||||
#### `respect-ignore-files`
|
||||
|
||||
@@ -170,6 +172,9 @@ If left unspecified, ty will try to detect common project layouts and initialize
|
||||
* if a `./<project-name>/<project-name>` directory exists, include `.` and `./<project-name>` in the first party search path
|
||||
* otherwise, default to `.` (flat layout)
|
||||
|
||||
Besides, if a `./tests` directory exists and is not a package (i.e. it does not contain an `__init__.py` file),
|
||||
it will also be included in the first party search path.
|
||||
|
||||
**Default value**: `null`
|
||||
|
||||
**Type**: `str`
|
||||
|
||||
110
crates/ty/docs/rules.md
generated
110
crates/ty/docs/rules.md
generated
@@ -1,3 +1,5 @@
|
||||
<!-- WARNING: This file is auto-generated (cargo dev generate-all). Edit the lint-declarations in 'crates/ty_python_semantic/src/types/diagnostic.rs' if you want to change anything here. -->
|
||||
|
||||
# Rules
|
||||
|
||||
## `byte-string-type-annotation`
|
||||
@@ -50,7 +52,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L90)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L91)
|
||||
</details>
|
||||
|
||||
## `conflicting-argument-forms`
|
||||
@@ -81,7 +83,7 @@ f(int) # error
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L134)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L135)
|
||||
</details>
|
||||
|
||||
## `conflicting-declarations`
|
||||
@@ -111,7 +113,7 @@ a = 1
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L160)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L161)
|
||||
</details>
|
||||
|
||||
## `conflicting-metaclass`
|
||||
@@ -142,7 +144,7 @@ class C(A, B): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L185)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L186)
|
||||
</details>
|
||||
|
||||
## `cyclic-class-definition`
|
||||
@@ -173,7 +175,7 @@ class B(A): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L211)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L212)
|
||||
</details>
|
||||
|
||||
## `duplicate-base`
|
||||
@@ -199,7 +201,7 @@ class B(A, A): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L255)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L256)
|
||||
</details>
|
||||
|
||||
## `escape-character-in-forward-annotation`
|
||||
@@ -336,7 +338,7 @@ TypeError: multiple bases have instance lay-out conflict
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L276)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L277)
|
||||
</details>
|
||||
|
||||
## `inconsistent-mro`
|
||||
@@ -365,7 +367,7 @@ class C(A, B): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L362)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L363)
|
||||
</details>
|
||||
|
||||
## `index-out-of-bounds`
|
||||
@@ -390,7 +392,7 @@ t[3] # IndexError: tuple index out of range
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L386)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L387)
|
||||
</details>
|
||||
|
||||
## `invalid-argument-type`
|
||||
@@ -416,7 +418,7 @@ func("foo") # error: [invalid-argument-type]
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L406)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L407)
|
||||
</details>
|
||||
|
||||
## `invalid-assignment`
|
||||
@@ -443,7 +445,7 @@ a: int = ''
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L446)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L447)
|
||||
</details>
|
||||
|
||||
## `invalid-attribute-access`
|
||||
@@ -476,7 +478,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1394)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1395)
|
||||
</details>
|
||||
|
||||
## `invalid-base`
|
||||
@@ -499,7 +501,7 @@ class A(42): ... # error: [invalid-base]
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L468)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L469)
|
||||
</details>
|
||||
|
||||
## `invalid-context-manager`
|
||||
@@ -525,7 +527,7 @@ with 1:
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L519)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L520)
|
||||
</details>
|
||||
|
||||
## `invalid-declaration`
|
||||
@@ -553,7 +555,7 @@ a: str
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L540)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L541)
|
||||
</details>
|
||||
|
||||
## `invalid-exception-caught`
|
||||
@@ -594,7 +596,7 @@ except ZeroDivisionError:
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L563)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L564)
|
||||
</details>
|
||||
|
||||
## `invalid-generic-class`
|
||||
@@ -625,7 +627,7 @@ class C[U](Generic[T]): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L599)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L600)
|
||||
</details>
|
||||
|
||||
## `invalid-legacy-type-variable`
|
||||
@@ -658,7 +660,7 @@ def f(t: TypeVar("U")): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L625)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L626)
|
||||
</details>
|
||||
|
||||
## `invalid-metaclass`
|
||||
@@ -690,7 +692,7 @@ class B(metaclass=f): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L674)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L675)
|
||||
</details>
|
||||
|
||||
## `invalid-overload`
|
||||
@@ -738,7 +740,7 @@ def foo(x: int) -> int: ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L701)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L702)
|
||||
</details>
|
||||
|
||||
## `invalid-parameter-default`
|
||||
@@ -763,7 +765,7 @@ def f(a: int = ''): ...
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L744)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L745)
|
||||
</details>
|
||||
|
||||
## `invalid-protocol`
|
||||
@@ -796,7 +798,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L334)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L335)
|
||||
</details>
|
||||
|
||||
## `invalid-raise`
|
||||
@@ -844,7 +846,7 @@ def g():
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L764)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L765)
|
||||
</details>
|
||||
|
||||
## `invalid-return-type`
|
||||
@@ -868,7 +870,7 @@ def func() -> int:
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L427)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L428)
|
||||
</details>
|
||||
|
||||
## `invalid-super-argument`
|
||||
@@ -912,7 +914,7 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)`
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L807)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L808)
|
||||
</details>
|
||||
|
||||
## `invalid-syntax-in-forward-annotation`
|
||||
@@ -952,7 +954,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L653)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L654)
|
||||
</details>
|
||||
|
||||
## `invalid-type-checking-constant`
|
||||
@@ -981,7 +983,7 @@ TYPE_CHECKING = ''
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L846)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L847)
|
||||
</details>
|
||||
|
||||
## `invalid-type-form`
|
||||
@@ -1010,7 +1012,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L870)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L871)
|
||||
</details>
|
||||
|
||||
## `invalid-type-variable-constraints`
|
||||
@@ -1044,7 +1046,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L894)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L895)
|
||||
</details>
|
||||
|
||||
## `missing-argument`
|
||||
@@ -1068,7 +1070,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L923)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L924)
|
||||
</details>
|
||||
|
||||
## `no-matching-overload`
|
||||
@@ -1096,7 +1098,7 @@ func("string") # error: [no-matching-overload]
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L942)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L943)
|
||||
</details>
|
||||
|
||||
## `non-subscriptable`
|
||||
@@ -1119,7 +1121,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L965)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L966)
|
||||
</details>
|
||||
|
||||
## `not-iterable`
|
||||
@@ -1144,7 +1146,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L983)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L984)
|
||||
</details>
|
||||
|
||||
## `parameter-already-assigned`
|
||||
@@ -1170,7 +1172,7 @@ f(1, x=2) # Error raised here
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1034)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1035)
|
||||
</details>
|
||||
|
||||
## `raw-string-type-annotation`
|
||||
@@ -1229,7 +1231,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1370)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1371)
|
||||
</details>
|
||||
|
||||
## `subclass-of-final-class`
|
||||
@@ -1257,7 +1259,7 @@ class B(A): ... # Error raised here
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1125)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1126)
|
||||
</details>
|
||||
|
||||
## `too-many-positional-arguments`
|
||||
@@ -1283,7 +1285,7 @@ f("foo") # Error raised here
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1170)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1171)
|
||||
</details>
|
||||
|
||||
## `type-assertion-failure`
|
||||
@@ -1310,7 +1312,7 @@ def _(x: int):
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1148)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1149)
|
||||
</details>
|
||||
|
||||
## `unavailable-implicit-super-arguments`
|
||||
@@ -1354,7 +1356,7 @@ class A:
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1191)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1192)
|
||||
</details>
|
||||
|
||||
## `unknown-argument`
|
||||
@@ -1380,7 +1382,7 @@ f(x=1, y=2) # Error raised here
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1248)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1249)
|
||||
</details>
|
||||
|
||||
## `unresolved-attribute`
|
||||
@@ -1407,7 +1409,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1269)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1270)
|
||||
</details>
|
||||
|
||||
## `unresolved-import`
|
||||
@@ -1431,7 +1433,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1291)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1292)
|
||||
</details>
|
||||
|
||||
## `unresolved-reference`
|
||||
@@ -1455,7 +1457,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1310)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1311)
|
||||
</details>
|
||||
|
||||
## `unsupported-bool-conversion`
|
||||
@@ -1491,7 +1493,7 @@ b1 < b2 < b1 # exception raised here
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1003)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1004)
|
||||
</details>
|
||||
|
||||
## `unsupported-operator`
|
||||
@@ -1518,7 +1520,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1329)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1330)
|
||||
</details>
|
||||
|
||||
## `zero-stepsize-in-slice`
|
||||
@@ -1542,7 +1544,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1351)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1352)
|
||||
</details>
|
||||
|
||||
## `invalid-ignore-comment`
|
||||
@@ -1598,7 +1600,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1055)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1056)
|
||||
</details>
|
||||
|
||||
## `possibly-unbound-implicit-call`
|
||||
@@ -1629,7 +1631,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-implicit-call)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L108)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L109)
|
||||
</details>
|
||||
|
||||
## `possibly-unbound-import`
|
||||
@@ -1660,7 +1662,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1077)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1078)
|
||||
</details>
|
||||
|
||||
## `redundant-cast`
|
||||
@@ -1686,7 +1688,7 @@ cast(int, f()) # Redundant
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1422)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1423)
|
||||
</details>
|
||||
|
||||
## `undefined-reveal`
|
||||
@@ -1709,7 +1711,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1230)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1231)
|
||||
</details>
|
||||
|
||||
## `unknown-rule`
|
||||
@@ -1777,7 +1779,7 @@ class D(C): ... # error: [unsupported-base]
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L486)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L487)
|
||||
</details>
|
||||
|
||||
## `division-by-zero`
|
||||
@@ -1800,7 +1802,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L237)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L238)
|
||||
</details>
|
||||
|
||||
## `possibly-unresolved-reference`
|
||||
@@ -1827,7 +1829,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
|
||||
### Links
|
||||
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1103)
|
||||
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1104)
|
||||
</details>
|
||||
|
||||
## `unused-ignore-comment`
|
||||
|
||||
@@ -322,9 +322,11 @@ pub(crate) enum TerminalColor {
|
||||
/// Never display colors.
|
||||
Never,
|
||||
}
|
||||
|
||||
/// A TOML `<KEY> = <VALUE>` pair
|
||||
/// (such as you might find in a `ty.toml` configuration file)
|
||||
/// overriding a specific configuration option.
|
||||
///
|
||||
/// Overrides of individual settings using this option always take precedence
|
||||
/// over all configuration files.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -359,7 +361,15 @@ impl clap::Args for ConfigsArg {
|
||||
.short('c')
|
||||
.long("config")
|
||||
.value_name("CONFIG_OPTION")
|
||||
.help("A TOML `<KEY> = <VALUE>` pair")
|
||||
.help("A TOML `<KEY> = <VALUE>` pair overriding a specific configuration option.")
|
||||
.long_help(
|
||||
"
|
||||
A TOML `<KEY> = <VALUE>` pair (such as you might find in a `ty.toml` configuration file)
|
||||
overriding a specific configuration option.
|
||||
|
||||
Overrides of individual settings using this option always take precedence
|
||||
over all configuration files.",
|
||||
)
|
||||
.action(ArgAction::Append),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -243,12 +243,14 @@ impl MainLoop {
|
||||
MainLoopMessage::CheckWorkspace => {
|
||||
let db = db.clone();
|
||||
let sender = self.sender.clone();
|
||||
let mut reporter = R::default();
|
||||
|
||||
// Spawn a new task that checks the project. This needs to be done in a separate thread
|
||||
// to prevent blocking the main loop here.
|
||||
rayon::spawn(move || {
|
||||
match db.check_with_reporter(&mut reporter) {
|
||||
match salsa::Cancelled::catch(|| {
|
||||
let mut reporter = R::default();
|
||||
db.check_with_reporter(&mut reporter)
|
||||
}) {
|
||||
Ok(result) => {
|
||||
// Send the result back to the main loop for printing.
|
||||
sender
|
||||
|
||||
@@ -1454,10 +1454,10 @@ fn cli_config_args_toml_string_basic() -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_config_args_overrides_knot_toml() -> anyhow::Result<()> {
|
||||
fn cli_config_args_overrides_ty_toml() -> anyhow::Result<()> {
|
||||
let case = TestCase::with_files(vec![
|
||||
(
|
||||
"knot.toml",
|
||||
"ty.toml",
|
||||
r#"
|
||||
[terminal]
|
||||
error-on-warning = true
|
||||
@@ -1465,6 +1465,27 @@ fn cli_config_args_overrides_knot_toml() -> anyhow::Result<()> {
|
||||
),
|
||||
("test.py", r"print(x) # [unresolved-reference]"),
|
||||
])?;
|
||||
|
||||
// Exit code of 1 due to the setting in `ty.toml`
|
||||
assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
warning[unresolved-reference]: Name `x` used when not defined
|
||||
--> test.py:1:7
|
||||
|
|
||||
1 | print(x) # [unresolved-reference]
|
||||
| ^
|
||||
|
|
||||
info: rule `unresolved-reference` was selected on the command line
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
||||
");
|
||||
|
||||
// Exit code of 0 because the `ty.toml` setting is overwritten by `--config`
|
||||
assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference").arg("--config").arg("terminal.error-on-warning=false"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
@@ -1534,6 +1555,83 @@ fn cli_config_args_invalid_option() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The `site-packages` directory is used by ty for external import.
|
||||
/// Ty does the following checks to discover the `site-packages` directory in the order:
|
||||
/// 1) If `VIRTUAL_ENV` environment variable is set
|
||||
/// 2) If `CONDA_PREFIX` environment variable is set
|
||||
/// 3) If a `.venv` directory exists at the project root
|
||||
///
|
||||
/// This test is aiming at validating the logic around `CONDA_PREFIX`.
|
||||
///
|
||||
/// A conda-like environment file structure is used
|
||||
/// We test by first not setting the `CONDA_PREFIX` and expect a fail.
|
||||
/// Then we test by setting `CONDA_PREFIX` to `conda-env` and expect a pass.
|
||||
///
|
||||
/// ├── project
|
||||
/// │ └── test.py
|
||||
/// └── conda-env
|
||||
/// └── lib
|
||||
/// └── python3.13
|
||||
/// └── site-packages
|
||||
/// └── package1
|
||||
/// └── __init__.py
|
||||
///
|
||||
/// test.py imports package1
|
||||
/// And the command is run in the `project` directory.
|
||||
#[test]
|
||||
fn check_conda_prefix_var_to_resolve_path() -> anyhow::Result<()> {
|
||||
let conda_package1_path = if cfg!(windows) {
|
||||
"conda-env/Lib/site-packages/package1/__init__.py"
|
||||
} else {
|
||||
"conda-env/lib/python3.13/site-packages/package1/__init__.py"
|
||||
};
|
||||
|
||||
let case = TestCase::with_files([
|
||||
(
|
||||
"project/test.py",
|
||||
r#"
|
||||
import package1
|
||||
"#,
|
||||
),
|
||||
(
|
||||
conda_package1_path,
|
||||
r#"
|
||||
"#,
|
||||
),
|
||||
])?;
|
||||
|
||||
assert_cmd_snapshot!(case.command().current_dir(case.root().join("project")), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
error[unresolved-import]: Cannot resolve imported module `package1`
|
||||
--> test.py:2:8
|
||||
|
|
||||
2 | import package1
|
||||
| ^^^^^^^^
|
||||
|
|
||||
info: make sure your Python environment is properly configured: https://github.com/astral-sh/ty/blob/main/docs/README.md#python-environment
|
||||
info: rule `unresolved-import` is enabled by default
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
||||
");
|
||||
|
||||
// do command : CONDA_PREFIX=<temp_dir>/conda_env
|
||||
assert_cmd_snapshot!(case.command().current_dir(case.root().join("project")).env("CONDA_PREFIX", case.root().join("conda-env")), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
All checks passed!
|
||||
|
||||
----- stderr -----
|
||||
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
||||
");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct TestCase {
|
||||
_temp_dir: TempDir,
|
||||
_settings_scope: SettingsBindDropGuard,
|
||||
|
||||
@@ -1135,7 +1135,7 @@ print(sys.last_exc, os.getegid())
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let diagnostics = case.db.check().context("Failed to check project.")?;
|
||||
let diagnostics = case.db.check();
|
||||
|
||||
assert_eq!(diagnostics.len(), 2);
|
||||
assert_eq!(
|
||||
@@ -1160,7 +1160,7 @@ print(sys.last_exc, os.getegid())
|
||||
})
|
||||
.expect("Search path settings to be valid");
|
||||
|
||||
let diagnostics = case.db.check().context("Failed to check project.")?;
|
||||
let diagnostics = case.db.check();
|
||||
assert!(diagnostics.is_empty());
|
||||
|
||||
Ok(())
|
||||
@@ -1763,10 +1763,7 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
|
||||
let foo = case
|
||||
.system_file(case.project_path("foo.py"))
|
||||
.expect("foo.py to exist");
|
||||
let diagnostics = case
|
||||
.db()
|
||||
.check_file(foo)
|
||||
.context("Failed to check project.")?;
|
||||
let diagnostics = case.db().check_file(foo);
|
||||
|
||||
assert!(
|
||||
diagnostics.is_empty(),
|
||||
@@ -1786,10 +1783,7 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
|
||||
|
||||
case.apply_changes(changes);
|
||||
|
||||
let diagnostics = case
|
||||
.db()
|
||||
.check_file(foo)
|
||||
.context("Failed to check project.")?;
|
||||
let diagnostics = case.db().check_file(foo);
|
||||
|
||||
assert!(
|
||||
diagnostics.len() == 1,
|
||||
|
||||
30
crates/ty_project/resources/test/corpus/ty_extensions.py
Normal file
30
crates/ty_project/resources/test/corpus/ty_extensions.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Make sure that types are inferred for all subexpressions of the following
|
||||
annotations involving ty_extension `_SpecialForm`s.
|
||||
|
||||
This is a regression test for https://github.com/astral-sh/ty/issues/366
|
||||
"""
|
||||
|
||||
from ty_extensions import CallableTypeOf, Intersection, Not, TypeOf
|
||||
|
||||
|
||||
class A: ...
|
||||
|
||||
|
||||
class B: ...
|
||||
|
||||
|
||||
def _(x: Not[A]):
|
||||
pass
|
||||
|
||||
|
||||
def _(x: Intersection[A], y: Intersection[A, B]):
|
||||
pass
|
||||
|
||||
|
||||
def _(x: TypeOf[1j]):
|
||||
pass
|
||||
|
||||
|
||||
def _(x: CallableTypeOf[str]):
|
||||
pass
|
||||
@@ -8,8 +8,8 @@ use ruff_db::files::{File, Files};
|
||||
use ruff_db::system::System;
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
use ruff_db::{Db as SourceDb, Upcast};
|
||||
use salsa::Event;
|
||||
use salsa::plumbing::ZalsaDatabase;
|
||||
use salsa::{Cancelled, Event};
|
||||
use ty_ide::Db as IdeDb;
|
||||
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||
use ty_python_semantic::{Db as SemanticDb, Program};
|
||||
@@ -76,24 +76,21 @@ impl ProjectDatabase {
|
||||
}
|
||||
|
||||
/// Checks all open files in the project and its dependencies.
|
||||
pub fn check(&self) -> Result<Vec<Diagnostic>, Cancelled> {
|
||||
pub fn check(&self) -> Vec<Diagnostic> {
|
||||
let mut reporter = DummyReporter;
|
||||
let reporter = AssertUnwindSafe(&mut reporter as &mut dyn Reporter);
|
||||
self.with_db(|db| db.project().check(db, reporter))
|
||||
self.project().check(self, reporter)
|
||||
}
|
||||
|
||||
/// Checks all open files in the project and its dependencies, using the given reporter.
|
||||
pub fn check_with_reporter(
|
||||
&self,
|
||||
reporter: &mut dyn Reporter,
|
||||
) -> Result<Vec<Diagnostic>, Cancelled> {
|
||||
pub fn check_with_reporter(&self, reporter: &mut dyn Reporter) -> Vec<Diagnostic> {
|
||||
let reporter = AssertUnwindSafe(reporter);
|
||||
self.with_db(|db| db.project().check(db, reporter))
|
||||
self.project().check(self, reporter)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
pub fn check_file(&self, file: File) -> Result<Vec<Diagnostic>, Cancelled> {
|
||||
self.with_db(|db| self.project().check_file(db, file))
|
||||
pub fn check_file(&self, file: File) -> Vec<Diagnostic> {
|
||||
self.project().check_file(self, file)
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the system.
|
||||
@@ -107,13 +104,6 @@ impl ProjectDatabase {
|
||||
Arc::get_mut(&mut self.system)
|
||||
.expect("ref count should be 1 because `zalsa_mut` drops all other DB references.")
|
||||
}
|
||||
|
||||
pub(crate) fn with_db<F, T>(&self, f: F) -> Result<T, Cancelled>
|
||||
where
|
||||
F: FnOnce(&ProjectDatabase) -> T + std::panic::UnwindSafe,
|
||||
{
|
||||
Cancelled::catch(|| f(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Upcast<dyn SemanticDb> for ProjectDatabase {
|
||||
|
||||
@@ -1029,6 +1029,52 @@ expected `.`, `]`
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn src_root_with_tests() -> anyhow::Result<()> {
|
||||
let system = TestSystem::default();
|
||||
let root = SystemPathBuf::from("/app");
|
||||
|
||||
// pytest will find `tests/test_foo.py` and realize it is NOT part of a package
|
||||
// given that there's no `__init__.py` file in the same folder.
|
||||
// It will then add `tests` to `sys.path`
|
||||
// in order to import `test_foo.py` as the module `test_foo`.
|
||||
system
|
||||
.memory_file_system()
|
||||
.write_files_all([
|
||||
(root.join("src/main.py"), ""),
|
||||
(root.join("tests/conftest.py"), ""),
|
||||
(root.join("tests/test_foo.py"), ""),
|
||||
])
|
||||
.context("Failed to write files")?;
|
||||
|
||||
let metadata = ProjectMetadata::discover(&root, &system)?;
|
||||
let settings = metadata
|
||||
.options
|
||||
.to_program_settings(&root, "my_package", &system);
|
||||
|
||||
assert_eq!(
|
||||
settings.search_paths.src_roots,
|
||||
vec![root.clone(), root.join("src"), root.join("tests")]
|
||||
);
|
||||
|
||||
// If `tests/__init__.py` is present, it is considered a package and `tests` is not added to `sys.path`.
|
||||
system
|
||||
.memory_file_system()
|
||||
.write_file(root.join("tests/__init__.py"), "")
|
||||
.context("Failed to write tests/__init__.py")?;
|
||||
let metadata = ProjectMetadata::discover(&root, &system)?;
|
||||
let settings = metadata
|
||||
.options
|
||||
.to_program_settings(&root, "my_package", &system);
|
||||
|
||||
assert_eq!(
|
||||
settings.search_paths.src_roots,
|
||||
vec![root.clone(), root.join("src")]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_error_eq(error: &ProjectDiscoveryError, message: &str) {
|
||||
assert_eq!(error.to_string().replace('\\', "/"), message);
|
||||
|
||||
@@ -135,7 +135,7 @@ impl Options {
|
||||
} else {
|
||||
let src = project_root.join("src");
|
||||
|
||||
if system.is_directory(&src) {
|
||||
let mut roots = if system.is_directory(&src) {
|
||||
// Default to `src` and the project root if `src` exists and the root hasn't been specified.
|
||||
// This corresponds to the `src-layout`
|
||||
tracing::debug!(
|
||||
@@ -154,7 +154,24 @@ impl Options {
|
||||
// Default to a [flat project structure](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/).
|
||||
tracing::debug!("Defaulting `src.root` to `.`");
|
||||
vec![project_root.to_path_buf()]
|
||||
};
|
||||
|
||||
// Considering pytest test discovery conventions,
|
||||
// we also include the `tests` directory if it exists and is not a package.
|
||||
let tests_dir = project_root.join("tests");
|
||||
if system.is_directory(&tests_dir)
|
||||
&& !system.is_file(&tests_dir.join("__init__.py"))
|
||||
&& !roots.contains(&tests_dir)
|
||||
{
|
||||
// If the `tests` directory exists and is not a package, include it as a source root.
|
||||
tracing::debug!(
|
||||
"Including `./tests` in `src.root` because a `./tests` directory exists"
|
||||
);
|
||||
|
||||
roots.push(tests_dir);
|
||||
}
|
||||
|
||||
roots
|
||||
};
|
||||
|
||||
let (extra_paths, python, typeshed) = self
|
||||
@@ -186,6 +203,11 @@ impl Options {
|
||||
.ok()
|
||||
.map(PythonPath::from_virtual_env_var)
|
||||
})
|
||||
.or_else(|| {
|
||||
std::env::var("CONDA_PREFIX")
|
||||
.ok()
|
||||
.map(PythonPath::from_conda_prefix_var)
|
||||
})
|
||||
.unwrap_or_else(|| PythonPath::Discover(project_root.to_path_buf())),
|
||||
}
|
||||
}
|
||||
@@ -387,6 +409,9 @@ pub struct SrcOptions {
|
||||
/// * if a `./src` directory exists, include `.` and `./src` in the first party search path (src layout or flat)
|
||||
/// * if a `./<project-name>/<project-name>` directory exists, include `.` and `./<project-name>` in the first party search path
|
||||
/// * otherwise, default to `.` (flat layout)
|
||||
///
|
||||
/// Besides, if a `./tests` directory exists and is not a package (i.e. it does not contain an `__init__.py` file),
|
||||
/// it will also be included in the first party search path.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[option(
|
||||
default = r#"null"#,
|
||||
|
||||
@@ -305,4 +305,37 @@ def _(c: Callable[[int], int]):
|
||||
reveal_type(c.__call__) # revealed: (int, /) -> int
|
||||
```
|
||||
|
||||
Unlike other type checkers, we do _not_ allow attributes to be accessed that would only be available
|
||||
on function-like callables:
|
||||
|
||||
```py
|
||||
def f_wrong(c: Callable[[], None]):
|
||||
# error: [unresolved-attribute] "Type `() -> None` has no attribute `__qualname__`"
|
||||
c.__qualname__
|
||||
|
||||
# error: [unresolved-attribute] "Unresolved attribute `__qualname__` on type `() -> None`."
|
||||
c.__qualname__ = "my_callable"
|
||||
```
|
||||
|
||||
We do this, because at runtime, calls to `f_wrong` with a non-function callable would raise an
|
||||
`AttributeError`:
|
||||
|
||||
```py
|
||||
class MyCallable:
|
||||
def __call__(self) -> None:
|
||||
pass
|
||||
|
||||
f_wrong(MyCallable()) # raises `AttributeError` at runtime
|
||||
```
|
||||
|
||||
If users want to write to attributes such as `__qualname__`, they need to check the existence of the
|
||||
attribute first:
|
||||
|
||||
```py
|
||||
def f_okay(c: Callable[[], None]):
|
||||
if hasattr(c, "__qualname__"):
|
||||
c.__qualname__ # okay
|
||||
c.__qualname__ = "my_callable" # also okay
|
||||
```
|
||||
|
||||
[gradual form]: https://typing.python.org/en/latest/spec/glossary.html#term-gradual-form
|
||||
|
||||
@@ -81,23 +81,22 @@ import typing
|
||||
|
||||
class ListSubclass(typing.List): ...
|
||||
|
||||
# revealed: tuple[<class 'ListSubclass'>, <class 'list[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'ListSubclass'>, <class 'list[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(ListSubclass.__mro__)
|
||||
|
||||
class DictSubclass(typing.Dict): ...
|
||||
|
||||
# TODO: should not have multiple `Generic[]` elements
|
||||
# revealed: tuple[<class 'DictSubclass'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'DictSubclass'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(DictSubclass.__mro__)
|
||||
|
||||
class SetSubclass(typing.Set): ...
|
||||
|
||||
# revealed: tuple[<class 'SetSubclass'>, <class 'set[Unknown]'>, <class 'MutableSet[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'SetSubclass'>, <class 'set[Unknown]'>, <class 'MutableSet[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(SetSubclass.__mro__)
|
||||
|
||||
class FrozenSetSubclass(typing.FrozenSet): ...
|
||||
|
||||
# revealed: tuple[<class 'FrozenSetSubclass'>, <class 'frozenset[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'FrozenSetSubclass'>, <class 'frozenset[Unknown]'>, <class 'AbstractSet[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(FrozenSetSubclass.__mro__)
|
||||
|
||||
####################
|
||||
@@ -106,30 +105,26 @@ reveal_type(FrozenSetSubclass.__mro__)
|
||||
|
||||
class ChainMapSubclass(typing.ChainMap): ...
|
||||
|
||||
# TODO: should not have multiple `Generic[]` elements
|
||||
# revealed: tuple[<class 'ChainMapSubclass'>, <class 'ChainMap[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'ChainMapSubclass'>, <class 'ChainMap[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(ChainMapSubclass.__mro__)
|
||||
|
||||
class CounterSubclass(typing.Counter): ...
|
||||
|
||||
# TODO: Should have one `Generic[]` element, not three(!)
|
||||
# revealed: tuple[<class 'CounterSubclass'>, <class 'Counter[Unknown]'>, <class 'dict[Unknown, int]'>, <class 'MutableMapping[Unknown, int]'>, <class 'Mapping[Unknown, int]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], typing.Generic[_T], <class 'object'>]
|
||||
# revealed: tuple[<class 'CounterSubclass'>, <class 'Counter[Unknown]'>, <class 'dict[Unknown, int]'>, <class 'MutableMapping[Unknown, int]'>, <class 'Mapping[Unknown, int]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(CounterSubclass.__mro__)
|
||||
|
||||
class DefaultDictSubclass(typing.DefaultDict): ...
|
||||
|
||||
# TODO: Should not have multiple `Generic[]` elements
|
||||
# revealed: tuple[<class 'DefaultDictSubclass'>, <class 'defaultdict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'DefaultDictSubclass'>, <class 'defaultdict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(DefaultDictSubclass.__mro__)
|
||||
|
||||
class DequeSubclass(typing.Deque): ...
|
||||
|
||||
# revealed: tuple[<class 'DequeSubclass'>, <class 'deque[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'DequeSubclass'>, <class 'deque[Unknown]'>, <class 'MutableSequence[Unknown]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(DequeSubclass.__mro__)
|
||||
|
||||
class OrderedDictSubclass(typing.OrderedDict): ...
|
||||
|
||||
# TODO: Should not have multiple `Generic[]` elements
|
||||
# revealed: tuple[<class 'OrderedDictSubclass'>, <class 'OrderedDict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], typing.Generic[_KT, _VT_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'OrderedDictSubclass'>, <class 'OrderedDict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(OrderedDictSubclass.__mro__)
|
||||
```
|
||||
|
||||
@@ -1527,6 +1527,65 @@ def _(ns: argparse.Namespace):
|
||||
reveal_type(ns.whatever) # revealed: Any
|
||||
```
|
||||
|
||||
## Classes with custom `__getattribute__` methods
|
||||
|
||||
If a type provides a custom `__getattribute__`, we use its return type as the type for unknown
|
||||
attributes. Note that this behavior differs from runtime, where `__getattribute__` is called
|
||||
unconditionally, even for known attributes. The rationale for doing this is that it allows users to
|
||||
specify more precise types for specific attributes, such as `x: str` in the example below. This
|
||||
behavior matches other type checkers such as mypy and pyright.
|
||||
|
||||
```py
|
||||
from typing import Any
|
||||
|
||||
class Foo:
|
||||
x: str
|
||||
def __getattribute__(self, attr: str) -> Any:
|
||||
return 42
|
||||
|
||||
reveal_type(Foo().x) # revealed: str
|
||||
reveal_type(Foo().y) # revealed: Any
|
||||
```
|
||||
|
||||
A standard library example for a class with a custom `__getattribute__` method is `SimpleNamespace`:
|
||||
|
||||
```py
|
||||
from types import SimpleNamespace
|
||||
|
||||
sn = SimpleNamespace(a="a")
|
||||
|
||||
reveal_type(sn.a) # revealed: Any
|
||||
```
|
||||
|
||||
`__getattribute__` takes precedence over `__getattr__`:
|
||||
|
||||
```py
|
||||
class C:
|
||||
def __getattribute__(self, name: str) -> int:
|
||||
return 1
|
||||
|
||||
def __getattr__(self, name: str) -> str:
|
||||
return "a"
|
||||
|
||||
c = C()
|
||||
|
||||
reveal_type(c.x) # revealed: int
|
||||
```
|
||||
|
||||
Like all dunder methods, `__getattribute__` is not looked up on instances:
|
||||
|
||||
```py
|
||||
def external_getattribute(name) -> int:
|
||||
return 1
|
||||
|
||||
class ThisFails:
|
||||
def __init__(self):
|
||||
self.__getattribute__ = external_getattribute
|
||||
|
||||
# error: [unresolved-attribute]
|
||||
ThisFails().x
|
||||
```
|
||||
|
||||
## Classes with custom `__setattr__` methods
|
||||
|
||||
### Basic
|
||||
@@ -1698,6 +1757,36 @@ reveal_type(outer.nested.inner.Outer.Nested.Inner.attr) # revealed: int
|
||||
outer.nested.inner.Outer.Nested.Inner.attr = "a"
|
||||
```
|
||||
|
||||
### Unions of module attributes
|
||||
|
||||
`mod1.py`:
|
||||
|
||||
```py
|
||||
global_symbol: str = "a"
|
||||
```
|
||||
|
||||
`mod2.py`:
|
||||
|
||||
```py
|
||||
global_symbol: str = "a"
|
||||
```
|
||||
|
||||
```py
|
||||
import mod1
|
||||
import mod2
|
||||
|
||||
def _(flag: bool):
|
||||
if flag:
|
||||
mod = mod1
|
||||
else:
|
||||
mod = mod2
|
||||
|
||||
mod.global_symbol = "b"
|
||||
|
||||
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `global_symbol` on type `<module 'mod1'> | <module 'mod2'>`"
|
||||
mod.global_symbol = 1
|
||||
```
|
||||
|
||||
## Literal types
|
||||
|
||||
### Function-literal attributes
|
||||
@@ -2020,6 +2109,52 @@ reveal_type(Foo.BAR.value) # revealed: @Todo(Attribute access on enum classes)
|
||||
reveal_type(Foo.__members__) # revealed: @Todo(Attribute access on enum classes)
|
||||
```
|
||||
|
||||
## Errors for unresolved and invalid attribute assignments
|
||||
|
||||
```py
|
||||
class C:
|
||||
class_attr: int = 1
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.instance_attr: int = 1
|
||||
|
||||
c = C()
|
||||
|
||||
C.class_attr = 2
|
||||
c.class_attr = 2
|
||||
c.instance_attr = 2
|
||||
|
||||
C.class_attr = "invalid" # error: [invalid-assignment]
|
||||
c.class_attr = "invalid" # error: [invalid-assignment]
|
||||
c.instance_attr = "invalid" # error: [invalid-assignment]
|
||||
|
||||
# TODO: The following attribute assignments are flagged by mypy/pyright (Type can
|
||||
# not be declared in assignment to non-self attribute). We currently do not emit
|
||||
# any errors and also don't validate the type of the annotation in any form. This
|
||||
# should probably be changed.
|
||||
C.class_attr: None = 2
|
||||
c.class_attr: None = 2
|
||||
c.instance_attr: None = 2
|
||||
|
||||
# TODO: Similar here. We do report `invalid-assignment` errors, but only because
|
||||
# the value type does not match.
|
||||
C.class_attr: str = "invalid" # error: [invalid-assignment]
|
||||
c.class_attr: str = "invalid" # error: [invalid-assignment]
|
||||
c.instance_attr: str = "invalid" # error: [invalid-assignment]
|
||||
|
||||
# For non-existent attributes, we emit `unresolved-attribute` errors:
|
||||
C.non_existent = 2 # error: [unresolved-attribute]
|
||||
c.non_existent = 2 # error: [unresolved-attribute]
|
||||
|
||||
# TODO: Similar to above, these should either be forbidden or validated.
|
||||
#
|
||||
# Make sure that we emit `unresolved-attribute` errors, at least:
|
||||
C.non_existent: int = 2 # error: [unresolved-attribute]
|
||||
c.non_existent: int = 2 # error: [unresolved-attribute]
|
||||
C.non_existent: None = 2 # error: [unresolved-attribute]
|
||||
c.non_existent: None = 2 # error: [unresolved-attribute]
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
Some of the tests in the *Class and instance variables* section draw inspiration from
|
||||
|
||||
@@ -239,3 +239,37 @@ def _(flag: bool):
|
||||
# error: [possibly-unbound-implicit-call]
|
||||
reveal_type(c[0]) # revealed: str
|
||||
```
|
||||
|
||||
## Dunder methods cannot be looked up on instances
|
||||
|
||||
Class-level annotations with no value assigned are considered instance-only, and aren't available as
|
||||
dunder methods:
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
|
||||
class C:
|
||||
__call__: Callable[..., None]
|
||||
|
||||
# error: [call-non-callable]
|
||||
C()()
|
||||
|
||||
# error: [invalid-assignment]
|
||||
_: Callable[..., None] = C()
|
||||
```
|
||||
|
||||
And of course the same is true if we have only an implicit assignment inside a method:
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
|
||||
class C:
|
||||
def __init__(self):
|
||||
self.__call__ = lambda *a, **kw: None
|
||||
|
||||
# error: [call-non-callable]
|
||||
C()()
|
||||
|
||||
# error: [invalid-assignment]
|
||||
_: Callable[..., None] = C()
|
||||
```
|
||||
|
||||
@@ -109,23 +109,50 @@ def _(o: object):
|
||||
|
||||
### Unsupported operators for positive contributions
|
||||
|
||||
Raise an error if any of the positive contributions to the intersection type are unsupported for the
|
||||
given operator:
|
||||
Raise an error if the given operator is unsupported for all positive contributions to the
|
||||
intersection type:
|
||||
|
||||
```py
|
||||
class NonContainer1: ...
|
||||
class NonContainer2: ...
|
||||
|
||||
def _(x: object):
|
||||
if isinstance(x, NonContainer1):
|
||||
if isinstance(x, NonContainer2):
|
||||
reveal_type(x) # revealed: NonContainer1 & NonContainer2
|
||||
|
||||
# error: [unsupported-operator] "Operator `in` is not supported for types `int` and `NonContainer1`"
|
||||
reveal_type(2 in x) # revealed: bool
|
||||
```
|
||||
|
||||
Do not raise an error if at least one of the positive contributions to the intersection type support
|
||||
the operator:
|
||||
|
||||
```py
|
||||
class Container:
|
||||
def __contains__(self, x) -> bool:
|
||||
return False
|
||||
|
||||
class NonContainer: ...
|
||||
|
||||
def _(x: object):
|
||||
if isinstance(x, Container):
|
||||
if isinstance(x, NonContainer):
|
||||
reveal_type(x) # revealed: Container & NonContainer
|
||||
if isinstance(x, NonContainer1):
|
||||
if isinstance(x, Container):
|
||||
if isinstance(x, NonContainer2):
|
||||
reveal_type(x) # revealed: NonContainer1 & Container & NonContainer2
|
||||
reveal_type(2 in x) # revealed: bool
|
||||
```
|
||||
|
||||
# error: [unsupported-operator] "Operator `in` is not supported for types `int` and `NonContainer`"
|
||||
reveal_type(2 in x) # revealed: bool
|
||||
Do also raise an error if the intersection has no positive contributions at all, unless the operator
|
||||
is supported on `object`:
|
||||
|
||||
```py
|
||||
def _(x: object):
|
||||
if not isinstance(x, NonContainer1):
|
||||
reveal_type(x) # revealed: ~NonContainer1
|
||||
|
||||
# error: [unsupported-operator] "Operator `in` is not supported for types `int` and `object`, in comparing `Literal[2]` with `~NonContainer1`"
|
||||
reveal_type(2 in x) # revealed: bool
|
||||
|
||||
reveal_type(2 is x) # revealed: bool
|
||||
```
|
||||
|
||||
### Unsupported operators for negative contributions
|
||||
|
||||
@@ -24,9 +24,7 @@ class:
|
||||
|
||||
```py
|
||||
class Bad(Generic[T], Generic[T]): ... # error: [duplicate-base]
|
||||
|
||||
# TODO: should emit an error (fails at runtime)
|
||||
class AlsoBad(Generic[T], Generic[S]): ...
|
||||
class AlsoBad(Generic[T], Generic[S]): ... # error: [duplicate-base]
|
||||
```
|
||||
|
||||
You cannot use the same typevar more than once.
|
||||
|
||||
@@ -527,6 +527,45 @@ reveal_type(unknown_object) # revealed: Unknown
|
||||
reveal_type(unknown_object.__mro__) # revealed: Unknown
|
||||
```
|
||||
|
||||
## MROs of classes that use multiple inheritance with generic aliases and subscripted `Generic`
|
||||
|
||||
```py
|
||||
from typing import Generic, TypeVar, Iterator
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class peekable(Generic[T], Iterator[T]): ...
|
||||
|
||||
# revealed: tuple[<class 'peekable[Unknown]'>, <class 'Iterator[T]'>, <class 'Iterable[T]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(peekable.__mro__)
|
||||
|
||||
class peekable2(Iterator[T], Generic[T]): ...
|
||||
|
||||
# revealed: tuple[<class 'peekable2[Unknown]'>, <class 'Iterator[T]'>, <class 'Iterable[T]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(peekable2.__mro__)
|
||||
|
||||
class Base: ...
|
||||
class Intermediate(Base, Generic[T]): ...
|
||||
class Sub(Intermediate[T], Base): ...
|
||||
|
||||
# revealed: tuple[<class 'Sub[Unknown]'>, <class 'Intermediate[T]'>, <class 'Base'>, typing.Generic, <class 'object'>]
|
||||
reveal_type(Sub.__mro__)
|
||||
```
|
||||
|
||||
## Unresolvable MROs involving generics have the original bases reported in the error message, not the resolved bases
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
from typing_extensions import Protocol, TypeVar, Generic
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class Foo(Protocol): ...
|
||||
class Bar(Protocol[T]): ...
|
||||
class Baz(Protocol[T], Foo, Bar[T]): ... # error: [inconsistent-mro]
|
||||
```
|
||||
|
||||
## Classes that inherit from themselves
|
||||
|
||||
These are invalid, but we need to be able to handle them gracefully without panicking.
|
||||
|
||||
@@ -67,12 +67,10 @@ It's an error to include both bare `Protocol` and subscripted `Protocol[]` in th
|
||||
simultaneously:
|
||||
|
||||
```py
|
||||
# TODO: should emit a `[duplicate-bases]` error here:
|
||||
class DuplicateBases(Protocol, Protocol[T]):
|
||||
class DuplicateBases(Protocol, Protocol[T]): # error: [duplicate-base]
|
||||
x: T
|
||||
|
||||
# TODO: should not have `Protocol` or `Generic` multiple times
|
||||
# revealed: tuple[<class 'DuplicateBases[Unknown]'>, typing.Protocol, typing.Generic, typing.Protocol[T], typing.Generic[T], <class 'object'>]
|
||||
# revealed: tuple[<class 'DuplicateBases[Unknown]'>, Unknown, <class 'object'>]
|
||||
reveal_type(DuplicateBases.__mro__)
|
||||
```
|
||||
|
||||
@@ -377,8 +375,7 @@ class Foo(Protocol):
|
||||
def method_member(self) -> bytes:
|
||||
return b"foo"
|
||||
|
||||
# TODO: actually a frozenset (requires support for legacy generics)
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["method_member"], Literal["x"], Literal["y"], Literal["z"]]
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["method_member", "x", "y", "z"]]
|
||||
```
|
||||
|
||||
Certain special attributes and methods are not considered protocol members at runtime, and should
|
||||
@@ -396,8 +393,7 @@ class Lumberjack(Protocol):
|
||||
def __init__(self, x: int) -> None:
|
||||
self.x = x
|
||||
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Lumberjack)) # revealed: tuple[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Lumberjack)) # revealed: frozenset[Literal["x"]]
|
||||
```
|
||||
|
||||
A sub-protocol inherits and extends the members of its superclass protocol(s):
|
||||
@@ -409,13 +405,11 @@ class Bar(Protocol):
|
||||
class Baz(Bar, Protocol):
|
||||
ham: memoryview
|
||||
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Baz)) # revealed: tuple[Literal["ham"], Literal["spam"]]
|
||||
reveal_type(get_protocol_members(Baz)) # revealed: frozenset[Literal["ham", "spam"]]
|
||||
|
||||
class Baz2(Bar, Foo, Protocol): ...
|
||||
|
||||
# TODO: actually a frozenset
|
||||
# revealed: tuple[Literal["method_member"], Literal["spam"], Literal["x"], Literal["y"], Literal["z"]]
|
||||
# revealed: frozenset[Literal["method_member", "spam", "x", "y", "z"]]
|
||||
reveal_type(get_protocol_members(Baz2))
|
||||
```
|
||||
|
||||
@@ -443,8 +437,7 @@ class Foo(Protocol):
|
||||
e = 56
|
||||
def f(self) -> None: ...
|
||||
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["d"], Literal["e"], Literal["f"]]
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["d", "e", "f"]]
|
||||
```
|
||||
|
||||
## Invalid calls to `get_protocol_members()`
|
||||
@@ -675,8 +668,7 @@ class LotsOfBindings(Protocol):
|
||||
case l: # TODO: this should error with `[invalid-protocol]` (`l` is not declared)
|
||||
...
|
||||
|
||||
# TODO: actually a frozenset
|
||||
# revealed: tuple[Literal["Nested"], Literal["NestedProtocol"], Literal["a"], Literal["b"], Literal["c"], Literal["d"], Literal["e"], Literal["f"], Literal["g"], Literal["h"], Literal["i"], Literal["j"], Literal["k"], Literal["l"]]
|
||||
# revealed: frozenset[Literal["Nested", "NestedProtocol", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]]
|
||||
reveal_type(get_protocol_members(LotsOfBindings))
|
||||
```
|
||||
|
||||
@@ -704,9 +696,7 @@ class Foo(Protocol):
|
||||
|
||||
# Note: the list of members does not include `a`, `b` or `c`,
|
||||
# as none of these attributes is declared in the class body.
|
||||
#
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["non_init_method"], Literal["x"], Literal["y"]]
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["non_init_method", "x", "y"]]
|
||||
```
|
||||
|
||||
If a member is declared in a superclass of a protocol class, it is fine for it to be assigned to in
|
||||
@@ -719,9 +709,8 @@ class Super(Protocol):
|
||||
class Sub(Super, Protocol):
|
||||
x = 42 # no error here, since it's declared in the superclass
|
||||
|
||||
# TODO: actually frozensets
|
||||
reveal_type(get_protocol_members(Super)) # revealed: tuple[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Sub)) # revealed: tuple[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Super)) # revealed: frozenset[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Sub)) # revealed: frozenset[Literal["x"]]
|
||||
```
|
||||
|
||||
If a protocol has 0 members, then all other types are assignable to it, and all fully static types
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: mro.md - Method Resolution Order tests - Unresolvable MROs involving generics have the original bases reported in the error message, not the resolved bases
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/mro.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | from typing_extensions import Protocol, TypeVar, Generic
|
||||
2 |
|
||||
3 | T = TypeVar("T")
|
||||
4 |
|
||||
5 | class Foo(Protocol): ...
|
||||
6 | class Bar(Protocol[T]): ...
|
||||
7 | class Baz(Protocol[T], Foo, Bar[T]): ... # error: [inconsistent-mro]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[inconsistent-mro]: Cannot create a consistent method resolution order (MRO) for class `Baz` with bases list `[typing.Protocol[T], <class 'Foo'>, <class 'Bar[T]'>]`
|
||||
--> src/mdtest_snippet.py:7:1
|
||||
|
|
||||
5 | class Foo(Protocol): ...
|
||||
6 | class Bar(Protocol[T]): ...
|
||||
7 | class Baz(Protocol[T], Foo, Bar[T]): ... # error: [inconsistent-mro]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
info: rule `inconsistent-mro` is enabled by default
|
||||
|
||||
```
|
||||
@@ -16,7 +16,7 @@ class Foo[T]: ...
|
||||
class Bar(Foo[Bar]): ...
|
||||
|
||||
reveal_type(Bar) # revealed: <class 'Bar'>
|
||||
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, <class 'Foo[Bar]'>, <class 'object'>]
|
||||
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, <class 'Foo[Bar]'>, typing.Generic, <class 'object'>]
|
||||
```
|
||||
|
||||
## Access to attributes declared in stubs
|
||||
|
||||
@@ -83,7 +83,7 @@ python-version = "3.9"
|
||||
```py
|
||||
class A(tuple[int, str]): ...
|
||||
|
||||
# revealed: tuple[<class 'A'>, <class 'tuple[@Todo(Generic tuple specializations), ...]'>, <class 'Sequence[@Todo(Generic tuple specializations)]'>, <class 'Reversible[@Todo(Generic tuple specializations)]'>, <class 'Collection[@Todo(Generic tuple specializations)]'>, <class 'Iterable[@Todo(Generic tuple specializations)]'>, <class 'Container[@Todo(Generic tuple specializations)]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'A'>, <class 'tuple[@Todo(Generic tuple specializations), ...]'>, <class 'Sequence[@Todo(Generic tuple specializations)]'>, <class 'Reversible[@Todo(Generic tuple specializations)]'>, <class 'Collection[@Todo(Generic tuple specializations)]'>, <class 'Iterable[@Todo(Generic tuple specializations)]'>, <class 'Container[@Todo(Generic tuple specializations)]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(A.__mro__)
|
||||
```
|
||||
|
||||
@@ -114,6 +114,6 @@ from typing import Tuple
|
||||
|
||||
class C(Tuple): ...
|
||||
|
||||
# revealed: tuple[<class 'C'>, <class 'tuple[Unknown, ...]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol[_T_co], typing.Generic[_T_co], <class 'object'>]
|
||||
# revealed: tuple[<class 'C'>, <class 'tuple[Unknown, ...]'>, <class 'Sequence[Unknown]'>, <class 'Reversible[Unknown]'>, <class 'Collection[Unknown]'>, <class 'Iterable[Unknown]'>, <class 'Container[Unknown]'>, typing.Protocol, typing.Generic, <class 'object'>]
|
||||
reveal_type(C.__mro__)
|
||||
```
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Type compendium
|
||||
|
||||
The type compendium contains "fact sheets" about important, interesting, and peculiar types in (ty's
|
||||
interpretation of) Python's type system. It is meant to be an educational reference for developers
|
||||
and users of ty. It is also a living document that ensures that our implementation of these types
|
||||
and their properties is consistent with the specification.
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [`Never`](never.md)
|
||||
- [`Object`](object.md)
|
||||
- [`None`](none.md)
|
||||
- [Integer `Literal`s](integer_literals.md)
|
||||
- String `Literal`s, `LiteralString`
|
||||
- [`tuple` types](tuple.md)
|
||||
- Class instance types
|
||||
- [`Any`](any.md)
|
||||
- Class literal types, `type[C]`, `type[object]`, `type[Any]`
|
||||
- [`AlwaysTruthy`, `AlwaysFalsy`](always_truthy_falsy.md)
|
||||
- [`Not[T]`](not_t.md)
|
||||
@@ -0,0 +1,175 @@
|
||||
# `AlwaysTruthy` and `AlwaysFalsy`
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
The types `AlwaysTruthy` and `AlwaysFalsy` describe the set of values that are always truthy or
|
||||
always falsy, respectively. More concretely, a value `at` is of type `AlwaysTruthy` if we can
|
||||
statically infer that `bool(at)` is always `True`, i.e. that the expression `bool(at)` has type
|
||||
`Literal[True]`. Conversely, a value `af` is of type `AlwaysFalsy` if we can statically infer that
|
||||
`bool(af)` is always `False`, i.e. that `bool(af)` has type `Literal[False]`.
|
||||
|
||||
## Examples
|
||||
|
||||
Here, we give a few examples of values that belong to these types:
|
||||
|
||||
```py
|
||||
from ty_extensions import AlwaysTruthy, AlwaysFalsy
|
||||
from typing_extensions import Literal
|
||||
|
||||
class CustomAlwaysTruthyType:
|
||||
def __bool__(self) -> Literal[True]:
|
||||
return True
|
||||
|
||||
class CustomAlwaysFalsyType:
|
||||
def __bool__(self) -> Literal[False]:
|
||||
return False
|
||||
|
||||
at: AlwaysTruthy
|
||||
at = True
|
||||
at = 1
|
||||
at = 123
|
||||
at = -1
|
||||
at = "non empty"
|
||||
at = b"non empty"
|
||||
at = CustomAlwaysTruthyType()
|
||||
|
||||
af: AlwaysFalsy
|
||||
af = False
|
||||
af = None
|
||||
af = 0
|
||||
af = ""
|
||||
af = b""
|
||||
af = CustomAlwaysFalsyType()
|
||||
```
|
||||
|
||||
## `AlwaysTruthy` and `AlwaysFalsy` are disjoint
|
||||
|
||||
It follows directly from the definition that `AlwaysTruthy` and `AlwaysFalsy` are disjoint types:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_disjoint_from, AlwaysTruthy, AlwaysFalsy
|
||||
|
||||
static_assert(is_disjoint_from(AlwaysTruthy, AlwaysFalsy))
|
||||
```
|
||||
|
||||
## `Truthy` and `Falsy`
|
||||
|
||||
It is useful to also define the types `Truthy = ~AlwaysFalsy` and `Falsy = ~AlwaysTruthy`. These
|
||||
types describe the set of values that *can* be truthy (`bool(t)` can return `True`) or falsy
|
||||
(`bool(f)` can return `False`), respectively.
|
||||
|
||||
Finally, we can also define the type `AmbiguousTruthiness = Truthy & Falsy`, which describes the set
|
||||
of values that can be truthy *and* falsy. This intersection is not empty. In the following, we give
|
||||
examples for values that belong to these three types:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to, is_disjoint_from, Not, Intersection, AlwaysTruthy, AlwaysFalsy
|
||||
from typing_extensions import Never
|
||||
from random import choice
|
||||
|
||||
type Truthy = Not[AlwaysFalsy]
|
||||
type Falsy = Not[AlwaysTruthy]
|
||||
|
||||
type AmbiguousTruthiness = Intersection[Truthy, Falsy]
|
||||
|
||||
static_assert(is_disjoint_from(AlwaysTruthy, AmbiguousTruthiness))
|
||||
static_assert(is_disjoint_from(AlwaysFalsy, AmbiguousTruthiness))
|
||||
static_assert(not is_disjoint_from(Truthy, Falsy))
|
||||
|
||||
class CustomAmbiguousTruthinessType:
|
||||
def __bool__(self) -> bool:
|
||||
return choice((True, False))
|
||||
|
||||
def maybe_empty_list() -> list[int]:
|
||||
return choice(([], [1, 2, 3]))
|
||||
|
||||
reveal_type(bool(maybe_empty_list())) # revealed: bool
|
||||
reveal_type(bool(CustomAmbiguousTruthinessType())) # revealed: bool
|
||||
|
||||
t: Truthy
|
||||
t = True
|
||||
t = 1
|
||||
# TODO: This assignment should be okay
|
||||
t = maybe_empty_list() # error: [invalid-assignment]
|
||||
# TODO: This assignment should be okay
|
||||
t = CustomAmbiguousTruthinessType() # error: [invalid-assignment]
|
||||
|
||||
a: AmbiguousTruthiness
|
||||
# TODO: This assignment should be okay
|
||||
a = maybe_empty_list() # error: [invalid-assignment]
|
||||
# TODO: This assignment should be okay
|
||||
a = CustomAmbiguousTruthinessType() # error: [invalid-assignment]
|
||||
|
||||
f: Falsy
|
||||
f = False
|
||||
f = None
|
||||
# TODO: This assignment should be okay
|
||||
f = maybe_empty_list() # error: [invalid-assignment]
|
||||
# TODO: This assignment should be okay
|
||||
f = CustomAmbiguousTruthinessType() # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
## Subtypes of `AlwaysTruthy`, `AlwaysFalsy`
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of, is_disjoint_from, AlwaysTruthy, AlwaysFalsy
|
||||
from typing_extensions import Literal
|
||||
```
|
||||
|
||||
These two types are disjoint, so types (that are not equivalent to Never) can only be a subtype of
|
||||
either one of them.
|
||||
|
||||
```py
|
||||
static_assert(is_disjoint_from(AlwaysTruthy, AlwaysFalsy))
|
||||
```
|
||||
|
||||
Types that only contain always-truthy values
|
||||
|
||||
```py
|
||||
static_assert(is_subtype_of(Literal[True], AlwaysTruthy))
|
||||
static_assert(is_subtype_of(Literal[1], AlwaysTruthy))
|
||||
static_assert(is_subtype_of(Literal[-1], AlwaysTruthy))
|
||||
static_assert(is_subtype_of(Literal["non empty"], AlwaysTruthy))
|
||||
static_assert(is_subtype_of(Literal[b"non empty"], AlwaysTruthy))
|
||||
```
|
||||
|
||||
Types that only contain always-falsy values
|
||||
|
||||
```py
|
||||
static_assert(is_subtype_of(None, AlwaysFalsy))
|
||||
static_assert(is_subtype_of(Literal[False], AlwaysFalsy))
|
||||
static_assert(is_subtype_of(Literal[0], AlwaysFalsy))
|
||||
static_assert(is_subtype_of(Literal[""], AlwaysFalsy))
|
||||
static_assert(is_subtype_of(Literal[b""], AlwaysFalsy))
|
||||
static_assert(is_subtype_of(Literal[False] | Literal[0], AlwaysFalsy))
|
||||
```
|
||||
|
||||
Ambiguous truthiness types
|
||||
|
||||
```py
|
||||
static_assert(not is_subtype_of(bool, AlwaysTruthy))
|
||||
static_assert(not is_subtype_of(bool, AlwaysFalsy))
|
||||
|
||||
static_assert(not is_subtype_of(list[int], AlwaysTruthy))
|
||||
static_assert(not is_subtype_of(list[int], AlwaysFalsy))
|
||||
```
|
||||
|
||||
## Open questions
|
||||
|
||||
Is `tuple[()]` always falsy? We currently model it this way, but this is
|
||||
[under discussion](https://github.com/astral-sh/ruff/issues/15528).
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of, AlwaysFalsy
|
||||
|
||||
static_assert(is_subtype_of(tuple[()], AlwaysFalsy))
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
See also:
|
||||
|
||||
- Our test suite on [narrowing for `if x` and `if not x`](../narrow/truthiness.md).
|
||||
@@ -0,0 +1,141 @@
|
||||
# `Any`
|
||||
|
||||
## Introduction
|
||||
|
||||
The type `Any` is the dynamic type in Python's gradual type system. It represents an unknown
|
||||
fully-static type, which means that it represents an *unknown* set of runtime values.
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_fully_static
|
||||
from typing import Any
|
||||
```
|
||||
|
||||
`Any` is a dynamic type:
|
||||
|
||||
```py
|
||||
static_assert(not is_fully_static(Any))
|
||||
```
|
||||
|
||||
## Every type is assignable to `Any`, and `Any` is assignable to every type
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_fully_static, is_assignable_to
|
||||
from typing_extensions import Never, Any
|
||||
|
||||
class C: ...
|
||||
|
||||
static_assert(is_assignable_to(C, Any))
|
||||
static_assert(is_assignable_to(Any, C))
|
||||
|
||||
static_assert(is_assignable_to(object, Any))
|
||||
static_assert(is_assignable_to(Any, object))
|
||||
|
||||
static_assert(is_assignable_to(Never, Any))
|
||||
static_assert(is_assignable_to(Any, Never))
|
||||
|
||||
static_assert(is_assignable_to(type, Any))
|
||||
static_assert(is_assignable_to(Any, type))
|
||||
|
||||
static_assert(is_assignable_to(type[Any], Any))
|
||||
static_assert(is_assignable_to(Any, type[Any]))
|
||||
```
|
||||
|
||||
`Any` is also assignable to itself (like every type):
|
||||
|
||||
```py
|
||||
static_assert(is_assignable_to(Any, Any))
|
||||
```
|
||||
|
||||
## Unions with `Any`: `Any | T`
|
||||
|
||||
The union `Any | T` of `Any` with a fully static type `T` describes an unknown set of values that is
|
||||
*at least as large* as the set of values described by `T`. It represents an unknown fully-static
|
||||
type with *lower bound* `T`. Again, this can be demonstrated using the assignable-to relation:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_assignable_to, is_equivalent_to
|
||||
from typing_extensions import Any
|
||||
|
||||
# A class hierarchy Small <: Medium <: Big
|
||||
|
||||
class Big: ...
|
||||
class Medium(Big): ...
|
||||
class Small(Medium): ...
|
||||
|
||||
static_assert(is_assignable_to(Any | Medium, Big))
|
||||
static_assert(is_assignable_to(Any | Medium, Medium))
|
||||
|
||||
# `Any | Medium` is at least as large as `Medium`, so we can not assign it to `Small`:
|
||||
static_assert(not is_assignable_to(Any | Medium, Small))
|
||||
```
|
||||
|
||||
The union `Any | object` is equivalent to `object`. This is true for every union with `object`, but
|
||||
it is worth demonstrating:
|
||||
|
||||
```py
|
||||
static_assert(is_equivalent_to(Any | object, object))
|
||||
static_assert(is_equivalent_to(object | Any, object))
|
||||
```
|
||||
|
||||
## Intersections with `Any`: `Any & T`
|
||||
|
||||
The intersection `Any & T` of `Any` with a fully static type `T` describes an unknown set of values
|
||||
that is *no larger than* the set of values described by `T`. It represents an unknown fully-static
|
||||
type with *upper bound* `T`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_assignable_to, Intersection, is_equivalent_to
|
||||
from typing import Any
|
||||
|
||||
class Big: ...
|
||||
class Medium(Big): ...
|
||||
class Small(Medium): ...
|
||||
|
||||
static_assert(is_assignable_to(Small, Intersection[Any, Medium]))
|
||||
static_assert(is_assignable_to(Medium, Intersection[Any, Medium]))
|
||||
```
|
||||
|
||||
`Any & Medium` is no larger than `Medium`, so we can not assign `Big` to it. There is no possible
|
||||
materialization of `Any & Medium` that would make it as big as `Big`:
|
||||
|
||||
```py
|
||||
static_assert(not is_assignable_to(Big, Intersection[Any, Medium]))
|
||||
```
|
||||
|
||||
`Any & Never` represents an "unknown" fully-static type which is no larger than `Never`. There is no
|
||||
such fully-static type, except for `Never` itself. So `Any & Never` is equivalent to `Never`:
|
||||
|
||||
```py
|
||||
from typing_extensions import Never
|
||||
|
||||
static_assert(is_equivalent_to(Intersection[Any, Never], Never))
|
||||
static_assert(is_equivalent_to(Intersection[Never, Any], Never))
|
||||
```
|
||||
|
||||
## Tuples with `Any`
|
||||
|
||||
This section demonstrates the following passage from the [type system concepts] documentation on
|
||||
gradual types:
|
||||
|
||||
> A type such as `tuple[int, Any]` […] does not represent a single set of Python objects; rather, it
|
||||
> represents a (bounded) range of possible sets of values. […] In the same way that `Any` does not
|
||||
> represent "the set of all Python objects" but rather "an unknown set of objects",
|
||||
> `tuple[int, Any]` does not represent "the set of all length-two tuples whose first element is an
|
||||
> integer". That is a fully static type, spelled `tuple[int, object]`. By contrast,
|
||||
> `tuple[int, Any]` represents some unknown set of tuple values; it might be the set of all tuples
|
||||
> of two integers, or the set of all tuples of an integer and a string, or some other set of tuple
|
||||
> values.
|
||||
>
|
||||
> In practice, this difference is seen (for example) in the fact that we can assign an expression of
|
||||
> type `tuple[int, Any]` to a target typed as `tuple[int, int]`, whereas assigning
|
||||
> `tuple[int, object]` to `tuple[int, int]` is a static type error.
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_assignable_to
|
||||
from typing import Any
|
||||
|
||||
static_assert(is_assignable_to(tuple[int, Any], tuple[int, int]))
|
||||
static_assert(not is_assignable_to(tuple[int, object], tuple[int, int]))
|
||||
```
|
||||
|
||||
[type system concepts]: https://typing.readthedocs.io/en/latest/spec/concepts.html#gradual-types
|
||||
@@ -0,0 +1,234 @@
|
||||
# Integer `Literal`s
|
||||
|
||||
An integer literal type represents the set of all integer objects with one specific value. For
|
||||
example, the type `Literal[54165]` represents the set of all integer objects with the value `54165`.
|
||||
|
||||
## Integer `Literal`s are not singleton types
|
||||
|
||||
This does not necessarily mean that the type is a singleton type, i.e., a type with only one
|
||||
inhabitant. The reason for this is that there might be multiple Python runtime objects (at different
|
||||
memory locations) that all represent the same integer value. For example, the following code snippet
|
||||
may print `False`.
|
||||
|
||||
```py
|
||||
x = 54165
|
||||
y = 54165
|
||||
|
||||
print(x is y)
|
||||
```
|
||||
|
||||
In practice, on CPython 3.13.0, this program prints `True` when executed as a script, but `False`
|
||||
when executed in the REPL.
|
||||
|
||||
Since this is an implementation detail of the Python runtime, we model all integer literals as
|
||||
non-singleton types:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_singleton
|
||||
from typing import Literal
|
||||
|
||||
static_assert(not is_singleton(Literal[0]))
|
||||
static_assert(not is_singleton(Literal[1]))
|
||||
static_assert(not is_singleton(Literal[54165]))
|
||||
```
|
||||
|
||||
This has implications for type-narrowing. For example, you can not use the `is not` operator to
|
||||
check whether a variable has a specific integer literal type, but this is not a recommended practice
|
||||
anyway.
|
||||
|
||||
```py
|
||||
def f(x: int):
|
||||
if x is 54165:
|
||||
# This works, because if `x` is the same object as that left-hand-side literal, then it
|
||||
# must have the same value.
|
||||
reveal_type(x) # revealed: Literal[54165]
|
||||
|
||||
if x is not 54165:
|
||||
# But here, we can not narrow the type (to `int & ~Literal[54165]`), because `x` might also
|
||||
# have the value `54165`, but a different object identity.
|
||||
reveal_type(x) # revealed: int
|
||||
```
|
||||
|
||||
## Integer `Literal`s are single-valued types
|
||||
|
||||
There is a slightly weaker property that integer literals have. They are single-valued types, which
|
||||
means that all objects of the type have the same value, i.e. they compare equal to each other:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_single_valued
|
||||
from typing import Literal
|
||||
|
||||
static_assert(is_single_valued(Literal[0]))
|
||||
static_assert(is_single_valued(Literal[1]))
|
||||
static_assert(is_single_valued(Literal[54165]))
|
||||
```
|
||||
|
||||
And this can be used for type-narrowing using not-equal comparisons:
|
||||
|
||||
```py
|
||||
def f(x: int):
|
||||
if x == 54165:
|
||||
# The reason that no narrowing occurs here is that there might be subclasses of `int`
|
||||
# that override `__eq__`. This is not specific to integer literals though, and generally
|
||||
# applies to `==` comparisons.
|
||||
reveal_type(x) # revealed: int
|
||||
|
||||
if x != 54165:
|
||||
reveal_type(x) # revealed: int & ~Literal[54165]
|
||||
```
|
||||
|
||||
## Subtyping relationships
|
||||
|
||||
### Subtypes of `int`
|
||||
|
||||
All integer literals are subtypes of `int`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of
|
||||
from typing import Literal
|
||||
|
||||
static_assert(is_subtype_of(Literal[0], int))
|
||||
static_assert(is_subtype_of(Literal[1], int))
|
||||
static_assert(is_subtype_of(Literal[54165], int))
|
||||
```
|
||||
|
||||
It is tempting to think that `int` is equivalent to the union of all integer literals,
|
||||
`… | Literal[-1] | Literal[0] | Literal[1] | …`, but this is not the case. `True` and `False` are
|
||||
also inhabitants of the `int` type, but they are not inhabitants of any integer literal type:
|
||||
|
||||
```py
|
||||
static_assert(is_subtype_of(Literal[True], int))
|
||||
static_assert(is_subtype_of(Literal[False], int))
|
||||
|
||||
static_assert(not is_subtype_of(Literal[True], Literal[1]))
|
||||
static_assert(not is_subtype_of(Literal[False], Literal[0]))
|
||||
```
|
||||
|
||||
Also, `int` can be subclassed, and instances of that subclass are also subtypes of `int`:
|
||||
|
||||
```py
|
||||
class CustomInt(int):
|
||||
pass
|
||||
|
||||
static_assert(is_subtype_of(CustomInt, int))
|
||||
```
|
||||
|
||||
### No subtypes of `float` and `complex`
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
Integer literals are _not_ subtypes of `float`, but the typing spec describes a special case for
|
||||
[`float` and `complex`] which accepts integers (and therefore also integer literals) in places where
|
||||
a `float` or `complex` is expected. We use the types `JustFloat` and `JustComplex` below, because ty
|
||||
recognizes an annotation of `float` as `int | float` to support that typing system special case.
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of, JustFloat, JustComplex
|
||||
from typing import Literal
|
||||
|
||||
# Not subtypes of `float` and `complex`
|
||||
static_assert(not is_subtype_of(Literal[0], JustFloat) and not is_subtype_of(Literal[0], JustComplex))
|
||||
static_assert(not is_subtype_of(Literal[1], JustFloat) and not is_subtype_of(Literal[1], JustComplex))
|
||||
static_assert(not is_subtype_of(Literal[54165], JustFloat) and not is_subtype_of(Literal[54165], JustComplex))
|
||||
```
|
||||
|
||||
The typing system special case can be seen in the following example:
|
||||
|
||||
```py
|
||||
a: JustFloat = 1 # error: [invalid-assignment]
|
||||
b: JustComplex = 1 # error: [invalid-assignment]
|
||||
|
||||
x: float = 1
|
||||
y: complex = 1
|
||||
```
|
||||
|
||||
### Subtypes of integer `Literal`s?
|
||||
|
||||
The only subtypes of an integer literal type _that can be named_ are the type itself and `Never`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of
|
||||
from typing_extensions import Never, Literal
|
||||
|
||||
static_assert(is_subtype_of(Literal[54165], Literal[54165]))
|
||||
static_assert(is_subtype_of(Never, Literal[54165]))
|
||||
```
|
||||
|
||||
## Disjointness of integer `Literal`s
|
||||
|
||||
Two integer literal types `Literal[a]` and `Literal[b]` are disjoint if `a != b`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_disjoint_from
|
||||
from typing import Literal
|
||||
|
||||
static_assert(is_disjoint_from(Literal[0], Literal[1]))
|
||||
static_assert(is_disjoint_from(Literal[0], Literal[54165]))
|
||||
|
||||
static_assert(not is_disjoint_from(Literal[0], Literal[0]))
|
||||
static_assert(not is_disjoint_from(Literal[54165], Literal[54165]))
|
||||
```
|
||||
|
||||
## Integer literal math
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
We support a whole range of arithmetic operations on integer literal types. For example, we can
|
||||
statically verify that (3, 4, 5) is a Pythagorean triple:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert
|
||||
|
||||
static_assert(3**2 + 4**2 == 5**2)
|
||||
```
|
||||
|
||||
Using unions of integer literals, we can even use this to solve equations over a finite domain
|
||||
(determine whether there is a solution or not):
|
||||
|
||||
```py
|
||||
from typing import Literal, assert_type
|
||||
|
||||
type Nat = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
def pythagorean_triples(a: Nat, b: Nat, c: Nat):
|
||||
# Answer is `bool`, because solutions do exist (3² + 4² = 5²)
|
||||
assert_type(a**2 + b**2 == c**2, bool)
|
||||
|
||||
def fermats_last_theorem(a: Nat, b: Nat, c: Nat):
|
||||
# Answer is `Literal[False]`, because no solutions exist
|
||||
assert_type(a**3 + b**3 == c**3, Literal[False])
|
||||
```
|
||||
|
||||
## Truthiness
|
||||
|
||||
Integer literals are always-truthy, except for `0`, which is always-falsy:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert
|
||||
|
||||
static_assert(-54165)
|
||||
static_assert(-1)
|
||||
static_assert(not 0)
|
||||
static_assert(1)
|
||||
static_assert(54165)
|
||||
```
|
||||
|
||||
This can be used for type-narrowing:
|
||||
|
||||
```py
|
||||
from typing_extensions import Literal, assert_type
|
||||
|
||||
def f(x: Literal[0, 1, 54365]):
|
||||
if x:
|
||||
assert_type(x, Literal[1, 54365])
|
||||
else:
|
||||
assert_type(x, Literal[0])
|
||||
```
|
||||
|
||||
[`float` and `complex`]: https://typing.readthedocs.io/en/latest/spec/special-types.html#special-cases-for-float-and-complex
|
||||
@@ -0,0 +1,185 @@
|
||||
# `Never`
|
||||
|
||||
`Never` represents the empty set of values.
|
||||
|
||||
## `Never` is a subtype of every type
|
||||
|
||||
The `Never` type is the bottom type of Python's type system. It is a subtype of every type, but no
|
||||
type is a subtype of `Never`, except for `Never` itself.
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of
|
||||
from typing_extensions import Never
|
||||
|
||||
class C: ...
|
||||
|
||||
static_assert(is_subtype_of(Never, int))
|
||||
static_assert(is_subtype_of(Never, object))
|
||||
static_assert(is_subtype_of(Never, C))
|
||||
static_assert(is_subtype_of(Never, Never))
|
||||
|
||||
static_assert(not is_subtype_of(int, Never))
|
||||
```
|
||||
|
||||
## `Never` is assignable to every type
|
||||
|
||||
`Never` is assignable to every type. This fact is useful when calling error-handling functions in a
|
||||
context that requires a value of a specific type. For example, changing the `Never` return type to
|
||||
`None` below would cause a type error:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_assignable_to
|
||||
from typing_extensions import Never, Any
|
||||
|
||||
static_assert(is_assignable_to(Never, int))
|
||||
static_assert(is_assignable_to(Never, object))
|
||||
static_assert(is_assignable_to(Never, Any))
|
||||
static_assert(is_assignable_to(Never, Never))
|
||||
|
||||
def raise_error() -> Never:
|
||||
raise Exception("...")
|
||||
|
||||
def f(divisor: int) -> None:
|
||||
x: float = (1 / divisor) if divisor != 0 else raise_error()
|
||||
```
|
||||
|
||||
## `Never` in annotations
|
||||
|
||||
`Never` can be used in functions to indicate that the function never returns. For example, if a
|
||||
function always raises an exception, if it calls `sys.exit()`, if it enters an infinite loop, or if
|
||||
it calls itself recursively. All of these functions "Never" return control back to the caller:
|
||||
|
||||
```py
|
||||
from typing_extensions import Never
|
||||
|
||||
def raises_unconditionally() -> Never:
|
||||
raise Exception("This function always raises an exception")
|
||||
|
||||
def exits_unconditionally() -> Never:
|
||||
import sys
|
||||
|
||||
return sys.exit(1)
|
||||
|
||||
def loops_forever() -> Never:
|
||||
while True:
|
||||
pass
|
||||
|
||||
def recursive_never() -> Never:
|
||||
return recursive_never()
|
||||
```
|
||||
|
||||
Similarly, if `Never` is used in parameter positions, it indicates that the function can "Never" be
|
||||
called, because it can never be passed a value of type `Never` (there are none):
|
||||
|
||||
```py
|
||||
def can_not_be_called(n: Never) -> int:
|
||||
return 0
|
||||
```
|
||||
|
||||
## `Never` is disjoint from every other type
|
||||
|
||||
Two types `A` and `B` are disjoint if their intersection is empty. Since `Never` has no inhabitants,
|
||||
it is disjoint from every other type:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_disjoint_from
|
||||
from typing_extensions import Never
|
||||
|
||||
class C: ...
|
||||
|
||||
static_assert(is_disjoint_from(Never, int))
|
||||
static_assert(is_disjoint_from(Never, object))
|
||||
static_assert(is_disjoint_from(Never, C))
|
||||
static_assert(is_disjoint_from(Never, Never))
|
||||
```
|
||||
|
||||
## Unions with `Never`
|
||||
|
||||
`Never` can always be removed from unions:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to
|
||||
from typing_extensions import Never
|
||||
|
||||
class P: ...
|
||||
class Q: ...
|
||||
|
||||
static_assert(is_equivalent_to(P | Never | Q | None, P | Q | None))
|
||||
```
|
||||
|
||||
## Intersections with `Never`
|
||||
|
||||
Intersecting with `Never` results in `Never`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to, Intersection
|
||||
from typing_extensions import Never
|
||||
|
||||
class P: ...
|
||||
class Q: ...
|
||||
|
||||
static_assert(is_equivalent_to(Intersection[P, Never, Q], Never))
|
||||
```
|
||||
|
||||
## `Never` is the complement of `object`
|
||||
|
||||
`object` describes the set of all possible values, while `Never` describes the empty set. The two
|
||||
types are complements of each other:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to, Not
|
||||
from typing_extensions import Never
|
||||
|
||||
static_assert(is_equivalent_to(Not[object], Never))
|
||||
static_assert(is_equivalent_to(Not[Never], object))
|
||||
```
|
||||
|
||||
This duality is also reflected in other facts:
|
||||
|
||||
- `Never` is a subtype of every type, while `object` is a supertype of every type.
|
||||
- `Never` is assignable to every type, while `object` is assignable from every type.
|
||||
- `Never` is disjoint from every type, while `object` overlaps with every type.
|
||||
- Building a union with `Never` is a no-op, intersecting with `object` is a no-op.
|
||||
- Interecting with `Never` results in `Never`, building a union with `object` results in `object`.
|
||||
|
||||
## Lists of `Never`
|
||||
|
||||
`list[Never]` is a reasonable type that is *not* equivalent to `Never`. The empty list inhabits this
|
||||
type:
|
||||
|
||||
```py
|
||||
from typing_extensions import Never
|
||||
|
||||
x: list[Never] = []
|
||||
```
|
||||
|
||||
## Tuples involving `Never`
|
||||
|
||||
A type like `tuple[int, Never]` has no inhabitants, and so it is equivalent to `Never`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to
|
||||
from typing_extensions import Never
|
||||
|
||||
static_assert(is_equivalent_to(tuple[int, Never], Never))
|
||||
```
|
||||
|
||||
Note that this is not the case for the homogenous tuple type `tuple[Never, ...]` though, because
|
||||
that type is inhabited by the empty tuple:
|
||||
|
||||
```py
|
||||
static_assert(not is_equivalent_to(tuple[Never, ...], Never))
|
||||
|
||||
t: tuple[Never, ...] = ()
|
||||
```
|
||||
|
||||
## `NoReturn` is the same as `Never`
|
||||
|
||||
The `NoReturn` type is a different name for `Never`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to
|
||||
from typing_extensions import NoReturn, Never
|
||||
|
||||
static_assert(is_equivalent_to(NoReturn, Never))
|
||||
```
|
||||
@@ -0,0 +1,80 @@
|
||||
# `None`
|
||||
|
||||
## `None` as a singleton type
|
||||
|
||||
The type `None` (or `NoneType`, see below) is a singleton type that has only one inhabitant: the
|
||||
object `None`.
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_singleton, is_equivalent_to
|
||||
|
||||
n: None = None
|
||||
|
||||
static_assert(is_singleton(None))
|
||||
```
|
||||
|
||||
Just like for other singleton types, the only subtypes of `None` are `None` itself and `Never`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of
|
||||
from typing_extensions import Never
|
||||
|
||||
static_assert(is_subtype_of(None, None))
|
||||
static_assert(is_subtype_of(Never, None))
|
||||
```
|
||||
|
||||
## Relationship to `Optional[T]`
|
||||
|
||||
The type `Optional[T]` is an alias for `T | None` (or `Union[T, None]`):
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to
|
||||
from typing import Optional, Union
|
||||
|
||||
class T: ...
|
||||
|
||||
static_assert(is_equivalent_to(Optional[T], T | None))
|
||||
static_assert(is_equivalent_to(Optional[T], Union[T, None]))
|
||||
```
|
||||
|
||||
## Type narrowing using `is`
|
||||
|
||||
Just like for other singleton types, we support type narrowing using `is` or `is not` checks:
|
||||
|
||||
```py
|
||||
from typing_extensions import assert_type
|
||||
|
||||
class T: ...
|
||||
|
||||
def f(x: T | None):
|
||||
if x is None:
|
||||
assert_type(x, None)
|
||||
else:
|
||||
assert_type(x, T)
|
||||
|
||||
assert_type(x, T | None)
|
||||
|
||||
if x is not None:
|
||||
assert_type(x, T)
|
||||
else:
|
||||
assert_type(x, None)
|
||||
```
|
||||
|
||||
## `NoneType`
|
||||
|
||||
`None` is special in that the name of the instance at runtime can be used as a type as well: The
|
||||
object `None` is an instance of type `None`. When a distinction between the two is needed, the
|
||||
spelling `NoneType` can be used, which is available since Python 3.10. `NoneType` is equivalent to
|
||||
`None`:
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.10"
|
||||
```
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to
|
||||
from types import NoneType
|
||||
|
||||
static_assert(is_equivalent_to(NoneType, None))
|
||||
```
|
||||
@@ -0,0 +1,120 @@
|
||||
# `Not[T]`
|
||||
|
||||
The type `Not[T]` is the complement of the type `T`. It describes the set of all values that are
|
||||
*not* in `T`.
|
||||
|
||||
## `Not[T]` is disjoint from `T`
|
||||
|
||||
`Not[T]` is disjoint from `T`:
|
||||
|
||||
```py
|
||||
from ty_extensions import Not, static_assert, is_disjoint_from
|
||||
|
||||
class T: ...
|
||||
class S(T): ...
|
||||
|
||||
static_assert(is_disjoint_from(Not[T], T))
|
||||
static_assert(is_disjoint_from(Not[T], S))
|
||||
```
|
||||
|
||||
## The union of `T` and `Not[T]` is equivalent to `object`
|
||||
|
||||
Together, `T` and `Not[T]` describe the set of all values. So the union of both types is equivalent
|
||||
to `object`:
|
||||
|
||||
```py
|
||||
from ty_extensions import Not, static_assert, is_equivalent_to
|
||||
|
||||
class T: ...
|
||||
|
||||
static_assert(is_equivalent_to(T | Not[T], object))
|
||||
```
|
||||
|
||||
## `Not[T]` reverses subtyping relationships
|
||||
|
||||
If `S <: T`, then `Not[T] <: Not[S]`:, similar to how negation in logic reverses the order of `<=`:
|
||||
|
||||
```py
|
||||
from ty_extensions import Not, static_assert, is_subtype_of
|
||||
|
||||
class T: ...
|
||||
class S(T): ...
|
||||
|
||||
static_assert(is_subtype_of(S, T))
|
||||
static_assert(is_subtype_of(Not[T], Not[S]))
|
||||
```
|
||||
|
||||
## `Not[T]` reverses assignability relationships
|
||||
|
||||
Assignability relationships are similarly reversed:
|
||||
|
||||
```py
|
||||
from ty_extensions import Not, Intersection, static_assert, is_assignable_to
|
||||
from typing import Any
|
||||
|
||||
class T: ...
|
||||
class S(T): ...
|
||||
|
||||
static_assert(is_assignable_to(S, T))
|
||||
static_assert(is_assignable_to(Not[T], Not[S]))
|
||||
|
||||
static_assert(is_assignable_to(Intersection[Any, S], Intersection[Any, T]))
|
||||
|
||||
static_assert(is_assignable_to(Not[Intersection[Any, S]], Not[Intersection[Any, T]]))
|
||||
```
|
||||
|
||||
## Subtyping and disjointness
|
||||
|
||||
If two types `P` and `Q` are disjoint, then `P` must be a subtype of `Not[Q]`, and vice versa:
|
||||
|
||||
```py
|
||||
from ty_extensions import Not, static_assert, is_subtype_of, is_disjoint_from
|
||||
from typing import final
|
||||
|
||||
@final
|
||||
class P: ...
|
||||
|
||||
@final
|
||||
class Q: ...
|
||||
|
||||
static_assert(is_disjoint_from(P, Q))
|
||||
|
||||
static_assert(is_subtype_of(P, Not[Q]))
|
||||
static_assert(is_subtype_of(Q, Not[P]))
|
||||
```
|
||||
|
||||
## De-Morgan's laws
|
||||
|
||||
Given two unrelated types `P` and `Q`, we can demonstrate De-Morgan's laws in the context of
|
||||
set-theoretic types:
|
||||
|
||||
```py
|
||||
from ty_extensions import Not, static_assert, is_equivalent_to, Intersection
|
||||
|
||||
class P: ...
|
||||
class Q: ...
|
||||
```
|
||||
|
||||
The negation of a union is the intersection of the negations:
|
||||
|
||||
```py
|
||||
static_assert(is_equivalent_to(Not[P | Q], Intersection[Not[P], Not[Q]]))
|
||||
```
|
||||
|
||||
Conversely, the negation of an intersection is the union of the negations:
|
||||
|
||||
```py
|
||||
static_assert(is_equivalent_to(Not[Intersection[P, Q]], Not[P] | Not[Q]))
|
||||
```
|
||||
|
||||
## Negation of gradual types
|
||||
|
||||
`Any` represents an unknown set of values. So `Not[Any]` also represents an unknown set of values.
|
||||
The two gradual types are equivalent:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_gradual_equivalent_to, Not
|
||||
from typing import Any
|
||||
|
||||
static_assert(is_gradual_equivalent_to(Not[Any], Any))
|
||||
```
|
||||
@@ -0,0 +1,78 @@
|
||||
# `object`
|
||||
|
||||
The `object` type represents the set of all Python objects.
|
||||
|
||||
## `object` is a supertype of all types
|
||||
|
||||
It is the top type in Python's type system, i.e., it is a supertype of all other types:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of
|
||||
|
||||
static_assert(is_subtype_of(int, object))
|
||||
static_assert(is_subtype_of(str, object))
|
||||
static_assert(is_subtype_of(type, object))
|
||||
static_assert(is_subtype_of(object, object))
|
||||
```
|
||||
|
||||
## Every type is assignable to `object`
|
||||
|
||||
Everything can be assigned to the type `object`. This fact can be used to create heterogeneous
|
||||
collections of objects (but also erases more specific type information):
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_assignable_to
|
||||
from typing_extensions import Any, Never
|
||||
|
||||
static_assert(is_assignable_to(int, object))
|
||||
static_assert(is_assignable_to(str | bytes, object))
|
||||
static_assert(is_assignable_to(type, object))
|
||||
static_assert(is_assignable_to(object, object))
|
||||
static_assert(is_assignable_to(Never, object))
|
||||
static_assert(is_assignable_to(Any, object))
|
||||
|
||||
x: list[object] = [1, "a", ()]
|
||||
```
|
||||
|
||||
## `object` overlaps with all types
|
||||
|
||||
There is no type that is disjoint from `object` except for `Never`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_disjoint_from
|
||||
from typing_extensions import Any, Never
|
||||
|
||||
static_assert(not is_disjoint_from(int, object))
|
||||
static_assert(not is_disjoint_from(str, object))
|
||||
static_assert(not is_disjoint_from(type, object))
|
||||
static_assert(not is_disjoint_from(object, object))
|
||||
static_assert(not is_disjoint_from(Any, object))
|
||||
static_assert(is_disjoint_from(Never, object))
|
||||
```
|
||||
|
||||
## Unions with `object`
|
||||
|
||||
Unions with `object` are equivalent to `object`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to
|
||||
|
||||
static_assert(is_equivalent_to(int | object | None, object))
|
||||
```
|
||||
|
||||
## Intersections with `object`
|
||||
|
||||
Intersecting with `object` is equivalent to the original type:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to, Intersection
|
||||
|
||||
class P: ...
|
||||
class Q: ...
|
||||
|
||||
static_assert(is_equivalent_to(Intersection[P, object, Q], Intersection[P, Q]))
|
||||
```
|
||||
|
||||
## `object` is the complement of `Never`
|
||||
|
||||
See corresponding section in the fact sheet for [`Never`](never.md).
|
||||
@@ -0,0 +1,166 @@
|
||||
# Tuples
|
||||
|
||||
## Tuples as product types
|
||||
|
||||
Tuples can be used to construct product types. Inhabitants of the type `tuple[P, Q]` are ordered
|
||||
pairs `(p, q)` where `p` is an inhabitant of `P` and `q` is an inhabitant of `Q`, analogous to the
|
||||
Cartesian product of sets.
|
||||
|
||||
```py
|
||||
from typing_extensions import assert_type
|
||||
|
||||
class P: ...
|
||||
class Q: ...
|
||||
|
||||
def _(p: P, q: Q):
|
||||
assert_type((p, q), tuple[P, Q])
|
||||
```
|
||||
|
||||
## Subtyping relationships
|
||||
|
||||
The type `tuple[S1, S2]` is a subtype of `tuple[T1, T2]` if and only if `S1` is a subtype of `T1`
|
||||
and `S2` is a subtype of `T2`, and similar for other lengths of tuples:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_subtype_of
|
||||
|
||||
class T1: ...
|
||||
class S1(T1): ...
|
||||
class T2: ...
|
||||
class S2(T2): ...
|
||||
|
||||
static_assert(is_subtype_of(tuple[S1], tuple[T1]))
|
||||
static_assert(not is_subtype_of(tuple[T1], tuple[S1]))
|
||||
|
||||
static_assert(is_subtype_of(tuple[S1, S2], tuple[T1, T2]))
|
||||
static_assert(not is_subtype_of(tuple[T1, S2], tuple[S1, T2]))
|
||||
static_assert(not is_subtype_of(tuple[S1, T2], tuple[T1, S2]))
|
||||
```
|
||||
|
||||
Different-length tuples are not related via subtyping:
|
||||
|
||||
```py
|
||||
static_assert(not is_subtype_of(tuple[S1], tuple[T1, T2]))
|
||||
```
|
||||
|
||||
## The empty tuple
|
||||
|
||||
The type of the empty tuple `()` is spelled `tuple[()]`. It is [not a singleton type], because
|
||||
different instances of `()` are not guaranteed to be the same object (even if this is the case in
|
||||
CPython at the time of writing).
|
||||
|
||||
The empty tuple can also be subclassed (further clarifying that it is not a singleton type):
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_singleton, is_subtype_of, is_equivalent_to, is_assignable_to
|
||||
|
||||
static_assert(not is_singleton(tuple[()]))
|
||||
|
||||
class AnotherEmptyTuple(tuple[()]): ...
|
||||
|
||||
static_assert(not is_equivalent_to(AnotherEmptyTuple, tuple[()]))
|
||||
|
||||
# TODO: These should not be errors
|
||||
# error: [static-assert-error]
|
||||
static_assert(is_subtype_of(AnotherEmptyTuple, tuple[()]))
|
||||
# error: [static-assert-error]
|
||||
static_assert(is_assignable_to(AnotherEmptyTuple, tuple[()]))
|
||||
```
|
||||
|
||||
## Non-empty tuples
|
||||
|
||||
For the same reason as above (two instances of a tuple with the same elements might not be the same
|
||||
object), non-empty tuples are also not singleton types — even if all their elements are singletons:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_singleton
|
||||
|
||||
static_assert(is_singleton(None))
|
||||
|
||||
static_assert(not is_singleton(tuple[None]))
|
||||
```
|
||||
|
||||
## Disjointness
|
||||
|
||||
A tuple `tuple[P1, P2]` is disjoint from a tuple `tuple[Q1, Q2]` if either `P1` is disjoint from
|
||||
`Q1` or if `P2` is disjoint from `Q2`:
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_disjoint_from
|
||||
from typing import final
|
||||
|
||||
@final
|
||||
class F1: ...
|
||||
|
||||
@final
|
||||
class F2: ...
|
||||
|
||||
class N1: ...
|
||||
class N2: ...
|
||||
|
||||
static_assert(is_disjoint_from(F1, F2))
|
||||
static_assert(not is_disjoint_from(N1, N2))
|
||||
|
||||
static_assert(is_disjoint_from(tuple[F1, F2], tuple[F2, F1]))
|
||||
static_assert(is_disjoint_from(tuple[F1, N1], tuple[F2, N2]))
|
||||
static_assert(is_disjoint_from(tuple[N1, F1], tuple[N2, F2]))
|
||||
static_assert(not is_disjoint_from(tuple[N1, N2], tuple[N2, N1]))
|
||||
```
|
||||
|
||||
We currently model tuple types to *not* be disjoint from arbitrary instance types, because we allow
|
||||
for the possibility of `tuple` to be subclassed
|
||||
|
||||
```py
|
||||
class C: ...
|
||||
|
||||
static_assert(not is_disjoint_from(tuple[int, str], C))
|
||||
|
||||
class CommonSubtype(tuple[int, str], C): ...
|
||||
```
|
||||
|
||||
Note: This is inconsistent with the fact that we model heterogeneous tuples to be disjoint from
|
||||
other heterogeneous tuples above:
|
||||
|
||||
```py
|
||||
class I1(tuple[F1, F2]): ...
|
||||
class I2(tuple[F2, F1]): ...
|
||||
|
||||
# TODO
|
||||
# This is a subtype of both `tuple[F1, F2]` and `tuple[F2, F1]`, so those two heterogeneous tuples
|
||||
# should not be disjoint from each other (see conflicting test above).
|
||||
class CommonSubtypeOfTuples(I1, I2): ...
|
||||
```
|
||||
|
||||
## Truthiness
|
||||
|
||||
The truthiness of the empty tuple is `False`:
|
||||
|
||||
```py
|
||||
from typing_extensions import assert_type, Literal
|
||||
|
||||
assert_type(bool(()), Literal[False])
|
||||
```
|
||||
|
||||
The truthiness of non-empty tuples is always `True`, even if all elements are falsy:
|
||||
|
||||
```py
|
||||
from typing_extensions import assert_type, Literal
|
||||
|
||||
assert_type(bool((False,)), Literal[True])
|
||||
assert_type(bool((False, False)), Literal[True])
|
||||
```
|
||||
|
||||
Both of these results are conflicting with the fact that tuples can be subclassed, and that we
|
||||
currently allow subclasses of `tuple` to overwrite `__bool__` (or `__len__`):
|
||||
|
||||
```py
|
||||
class NotAlwaysTruthyTuple(tuple[int]):
|
||||
def __bool__(self) -> bool:
|
||||
return False
|
||||
|
||||
# TODO: This assignment should be allowed
|
||||
# error: [invalid-assignment]
|
||||
t: tuple[int] = NotAlwaysTruthyTuple((1,))
|
||||
```
|
||||
|
||||
[not a singleton type]: https://discuss.python.org/t/should-we-specify-in-the-language-reference-that-the-empty-tuple-is-a-singleton/67957
|
||||
@@ -672,6 +672,29 @@ def f(x: int, y: str) -> None: ...
|
||||
c1: Callable[[int], None] = partial(f, y="a")
|
||||
```
|
||||
|
||||
### Classes with `__call__` as attribute
|
||||
|
||||
An instance type is assignable to a compatible callable type if the instance type's class has a
|
||||
callable `__call__` attribute.
|
||||
|
||||
TODO: for the moment, we don't consider the callable type as a bound-method descriptor, but this may
|
||||
change for better compatibility with mypy/pyright.
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
from ty_extensions import static_assert, is_assignable_to
|
||||
|
||||
def call_impl(a: int) -> str:
|
||||
return ""
|
||||
|
||||
class A:
|
||||
__call__: Callable[[int], str] = call_impl
|
||||
|
||||
static_assert(is_assignable_to(A, Callable[[int], str]))
|
||||
static_assert(not is_assignable_to(A, Callable[[int], int]))
|
||||
reveal_type(A()(1)) # revealed: str
|
||||
```
|
||||
|
||||
## Generics
|
||||
|
||||
### Assignability of generic types parameterized by gradual types
|
||||
|
||||
@@ -21,10 +21,7 @@ See the [typing documentation] for more information.
|
||||
as `int | float` and `int | float | complex`, respectively.
|
||||
|
||||
```py
|
||||
from ty_extensions import is_subtype_of, static_assert, TypeOf
|
||||
|
||||
type JustFloat = TypeOf[1.0]
|
||||
type JustComplex = TypeOf[1j]
|
||||
from ty_extensions import is_subtype_of, static_assert, JustFloat, JustComplex
|
||||
|
||||
static_assert(is_subtype_of(bool, bool))
|
||||
static_assert(is_subtype_of(bool, int))
|
||||
@@ -88,9 +85,7 @@ static_assert(is_subtype_of(C, object))
|
||||
|
||||
```py
|
||||
from typing_extensions import Literal, LiteralString
|
||||
from ty_extensions import is_subtype_of, static_assert, TypeOf
|
||||
|
||||
type JustFloat = TypeOf[1.0]
|
||||
from ty_extensions import is_subtype_of, static_assert, TypeOf, JustFloat
|
||||
|
||||
# Boolean literals
|
||||
static_assert(is_subtype_of(Literal[True], bool))
|
||||
@@ -1157,6 +1152,29 @@ def f(fn: Callable[[int], int]) -> None: ...
|
||||
f(a)
|
||||
```
|
||||
|
||||
### Classes with `__call__` as attribute
|
||||
|
||||
An instance type can be a subtype of a compatible callable type if the instance type's class has a
|
||||
callable `__call__` attribute.
|
||||
|
||||
TODO: for the moment, we don't consider the callable type as a bound-method descriptor, but this may
|
||||
change for better compatibility with mypy/pyright.
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
from ty_extensions import static_assert, is_subtype_of
|
||||
|
||||
def call_impl(a: int) -> str:
|
||||
return ""
|
||||
|
||||
class A:
|
||||
__call__: Callable[[int], str] = call_impl
|
||||
|
||||
static_assert(is_subtype_of(A, Callable[[int], str]))
|
||||
static_assert(not is_subtype_of(A, Callable[[int], int]))
|
||||
reveal_type(A()(1)) # revealed: str
|
||||
```
|
||||
|
||||
### Class literals
|
||||
|
||||
#### Classes with metaclasses
|
||||
|
||||
@@ -202,6 +202,10 @@ impl PythonPath {
|
||||
Self::SysPrefix(path.into(), SysPrefixPathOrigin::VirtualEnvVar)
|
||||
}
|
||||
|
||||
pub fn from_conda_prefix_var(path: impl Into<SystemPathBuf>) -> Self {
|
||||
Self::Resolve(path.into(), SysPrefixPathOrigin::CondaPrefixVar)
|
||||
}
|
||||
|
||||
pub fn from_cli_flag(path: SystemPathBuf) -> Self {
|
||||
Self::Resolve(path, SysPrefixPathOrigin::PythonCliFlag)
|
||||
}
|
||||
|
||||
@@ -580,6 +580,7 @@ impl fmt::Display for SysPrefixPath {
|
||||
pub enum SysPrefixPathOrigin {
|
||||
PythonCliFlag,
|
||||
VirtualEnvVar,
|
||||
CondaPrefixVar,
|
||||
Derived,
|
||||
LocalVenv,
|
||||
}
|
||||
@@ -590,7 +591,7 @@ impl SysPrefixPathOrigin {
|
||||
pub(crate) fn must_be_virtual_env(self) -> bool {
|
||||
match self {
|
||||
Self::LocalVenv | Self::VirtualEnvVar => true,
|
||||
Self::PythonCliFlag | Self::Derived => false,
|
||||
Self::PythonCliFlag | Self::Derived | Self::CondaPrefixVar => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -600,6 +601,7 @@ impl Display for SysPrefixPathOrigin {
|
||||
match self {
|
||||
Self::PythonCliFlag => f.write_str("`--python` argument"),
|
||||
Self::VirtualEnvVar => f.write_str("`VIRTUAL_ENV` environment variable"),
|
||||
Self::CondaPrefixVar => f.write_str("`CONDA_PREFIX` environment variable"),
|
||||
Self::Derived => f.write_str("derived `sys.prefix` path"),
|
||||
Self::LocalVenv => f.write_str("local virtual environment"),
|
||||
}
|
||||
|
||||
@@ -598,6 +598,10 @@ impl<'db> Type<'db> {
|
||||
matches!(self, Type::Dynamic(DynamicType::Todo(_)))
|
||||
}
|
||||
|
||||
pub const fn is_generic_alias(&self) -> bool {
|
||||
matches!(self, Type::GenericAlias(_))
|
||||
}
|
||||
|
||||
/// Replace references to the class `class` with a self-reference marker. This is currently
|
||||
/// used for recursive protocols, but could probably be extended to self-referential type-
|
||||
/// aliases and similar.
|
||||
@@ -1291,12 +1295,20 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
(Type::NominalInstance(_) | Type::ProtocolInstance(_), Type::Callable(_)) => {
|
||||
let call_symbol = self.member(db, "__call__").symbol;
|
||||
match call_symbol {
|
||||
Symbol::Type(Type::BoundMethod(call_function), _) => call_function
|
||||
.into_callable_type(db)
|
||||
.is_subtype_of(db, target),
|
||||
_ => false,
|
||||
let call_symbol = self
|
||||
.member_lookup_with_policy(
|
||||
db,
|
||||
Name::new_static("__call__"),
|
||||
MemberLookupPolicy::NO_INSTANCE_FALLBACK,
|
||||
)
|
||||
.symbol;
|
||||
// If the type of __call__ is a subtype of a callable type, this instance is.
|
||||
// Don't add other special cases here; our subtyping of a callable type
|
||||
// shouldn't get out of sync with the calls we will actually allow.
|
||||
if let Symbol::Type(t, Boundness::Bound) = call_symbol {
|
||||
t.is_subtype_of(db, target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
(Type::ProtocolInstance(left), Type::ProtocolInstance(right)) => {
|
||||
@@ -1641,12 +1653,20 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
(Type::NominalInstance(_) | Type::ProtocolInstance(_), Type::Callable(_)) => {
|
||||
let call_symbol = self.member(db, "__call__").symbol;
|
||||
match call_symbol {
|
||||
Symbol::Type(Type::BoundMethod(call_function), _) => call_function
|
||||
.into_callable_type(db)
|
||||
.is_assignable_to(db, target),
|
||||
_ => false,
|
||||
let call_symbol = self
|
||||
.member_lookup_with_policy(
|
||||
db,
|
||||
Name::new_static("__call__"),
|
||||
MemberLookupPolicy::NO_INSTANCE_FALLBACK,
|
||||
)
|
||||
.symbol;
|
||||
// If the type of __call__ is assignable to a callable type, this instance is.
|
||||
// Don't add other special cases here; our assignability to a callable type
|
||||
// shouldn't get out of sync with the calls we will actually allow.
|
||||
if let Symbol::Type(t, Boundness::Bound) = call_symbol {
|
||||
t.is_assignable_to(db, target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2547,9 +2567,13 @@ impl<'db> Type<'db> {
|
||||
// `Type::NominalInstance(type)` is equivalent to looking up the name in the
|
||||
// MRO of the class `object`.
|
||||
Type::NominalInstance(instance) if instance.class.is_known(db, KnownClass::Type) => {
|
||||
KnownClass::Object
|
||||
.to_class_literal(db)
|
||||
.find_name_in_mro_with_policy(db, name, policy)
|
||||
if policy.mro_no_object_fallback() {
|
||||
Some(Symbol::Unbound.into())
|
||||
} else {
|
||||
KnownClass::Object
|
||||
.to_class_literal(db)
|
||||
.find_name_in_mro_with_policy(db, name, policy)
|
||||
}
|
||||
}
|
||||
|
||||
Type::FunctionLiteral(_)
|
||||
@@ -2746,6 +2770,7 @@ impl<'db> Type<'db> {
|
||||
instance.display(db),
|
||||
owner.display(db)
|
||||
);
|
||||
|
||||
let descr_get = self.class_member(db, "__get__".into()).symbol;
|
||||
|
||||
if let Symbol::Type(descr_get, descr_get_boundness) = descr_get {
|
||||
@@ -3175,6 +3200,28 @@ impl<'db> Type<'db> {
|
||||
.into()
|
||||
};
|
||||
|
||||
let custom_getattribute_result = || {
|
||||
// Avoid cycles when looking up `__getattribute__`
|
||||
if "__getattribute__" == name.as_str() {
|
||||
return Symbol::Unbound.into();
|
||||
}
|
||||
|
||||
// Typeshed has a `__getattribute__` method defined on `builtins.object` so we
|
||||
// explicitly hide it here using `MemberLookupPolicy::MRO_NO_OBJECT_FALLBACK`.
|
||||
self.try_call_dunder_with_policy(
|
||||
db,
|
||||
"__getattribute__",
|
||||
&mut CallArgumentTypes::positional([Type::StringLiteral(
|
||||
StringLiteralType::new(db, Box::from(name.as_str())),
|
||||
)]),
|
||||
MemberLookupPolicy::MRO_NO_OBJECT_FALLBACK,
|
||||
)
|
||||
.map(|outcome| Symbol::bound(outcome.return_type(db)))
|
||||
// TODO: Handle call errors here.
|
||||
.unwrap_or(Symbol::Unbound)
|
||||
.into()
|
||||
};
|
||||
|
||||
match result {
|
||||
member @ SymbolAndQualifiers {
|
||||
symbol: Symbol::Type(_, Boundness::Bound),
|
||||
@@ -3183,11 +3230,13 @@ impl<'db> Type<'db> {
|
||||
member @ SymbolAndQualifiers {
|
||||
symbol: Symbol::Type(_, Boundness::PossiblyUnbound),
|
||||
qualifiers: _,
|
||||
} => member.or_fall_back_to(db, custom_getattr_result),
|
||||
} => member
|
||||
.or_fall_back_to(db, custom_getattribute_result)
|
||||
.or_fall_back_to(db, custom_getattr_result),
|
||||
SymbolAndQualifiers {
|
||||
symbol: Symbol::Unbound,
|
||||
qualifiers: _,
|
||||
} => custom_getattr_result(),
|
||||
} => custom_getattribute_result().or_fall_back_to(db, custom_getattr_result),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4365,7 +4414,7 @@ impl<'db> Type<'db> {
|
||||
db,
|
||||
name,
|
||||
&mut argument_types,
|
||||
MemberLookupPolicy::NO_INSTANCE_FALLBACK,
|
||||
MemberLookupPolicy::default(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4373,6 +4422,9 @@ impl<'db> Type<'db> {
|
||||
/// particular, this allows to specify `MemberLookupPolicy::MRO_NO_OBJECT_FALLBACK` to avoid
|
||||
/// looking up dunder methods on `object`, which is needed for functions like `__init__`,
|
||||
/// `__new__`, or `__setattr__`.
|
||||
///
|
||||
/// Note that `NO_INSTANCE_FALLBACK` is always added to the policy, since implicit calls to
|
||||
/// dunder methods never access instance members.
|
||||
fn try_call_dunder_with_policy(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
@@ -4380,8 +4432,14 @@ impl<'db> Type<'db> {
|
||||
argument_types: &mut CallArgumentTypes<'_, 'db>,
|
||||
policy: MemberLookupPolicy,
|
||||
) -> Result<Bindings<'db>, CallDunderError<'db>> {
|
||||
// Implicit calls to dunder methods never access instance members, so we pass
|
||||
// `NO_INSTANCE_FALLBACK` here in addition to other policies:
|
||||
match self
|
||||
.member_lookup_with_policy(db, name.into(), policy)
|
||||
.member_lookup_with_policy(
|
||||
db,
|
||||
name.into(),
|
||||
policy | MemberLookupPolicy::NO_INSTANCE_FALLBACK,
|
||||
)
|
||||
.symbol
|
||||
{
|
||||
Symbol::Type(dunder_callable, boundness) => {
|
||||
|
||||
@@ -667,15 +667,15 @@ impl<'db> Bindings<'db> {
|
||||
Some(KnownFunction::GetProtocolMembers) => {
|
||||
if let [Some(Type::ClassLiteral(class))] = overload.parameter_types() {
|
||||
if let Some(protocol_class) = class.into_protocol_class(db) {
|
||||
// TODO: actually a frozenset at runtime (requires support for legacy generic classes)
|
||||
overload.set_return_type(Type::Tuple(TupleType::new(
|
||||
db,
|
||||
protocol_class
|
||||
.interface(db)
|
||||
.members(db)
|
||||
.map(|member| Type::string_literal(db, member.name()))
|
||||
.collect::<Box<[Type<'db>]>>(),
|
||||
)));
|
||||
let member_names = protocol_class
|
||||
.interface(db)
|
||||
.members(db)
|
||||
.map(|member| Type::string_literal(db, member.name()));
|
||||
let specialization = UnionType::from_elements(db, member_names);
|
||||
overload.set_return_type(
|
||||
KnownClass::FrozenSet
|
||||
.to_specialized_instance(db, [specialization]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,10 @@ impl<'db> ClassType<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) const fn is_generic(self) -> bool {
|
||||
matches!(self, Self::Generic(_))
|
||||
}
|
||||
|
||||
/// Returns the class literal and specialization for this class. For a non-generic class, this
|
||||
/// is the class itself. For a generic alias, this is the alias's origin.
|
||||
pub(crate) fn class_literal(
|
||||
@@ -352,7 +356,7 @@ impl<'db> ClassType<'db> {
|
||||
ClassBase::Dynamic(_) => false,
|
||||
|
||||
// Protocol and Generic are not represented by a ClassType.
|
||||
ClassBase::Protocol(_) | ClassBase::Generic(_) => false,
|
||||
ClassBase::Protocol | ClassBase::Generic => false,
|
||||
|
||||
ClassBase::Class(base) => match (base, other) {
|
||||
(ClassType::NonGeneric(base), ClassType::NonGeneric(other)) => base == other,
|
||||
@@ -390,7 +394,7 @@ impl<'db> ClassType<'db> {
|
||||
ClassBase::Dynamic(_) => false,
|
||||
|
||||
// Protocol and Generic are not represented by a ClassType.
|
||||
ClassBase::Protocol(_) | ClassBase::Generic(_) => false,
|
||||
ClassBase::Protocol | ClassBase::Generic => false,
|
||||
|
||||
ClassBase::Class(base) => match (base, other) {
|
||||
(ClassType::NonGeneric(base), ClassType::NonGeneric(other)) => base == other,
|
||||
@@ -602,11 +606,6 @@ impl<'db> ClassLiteral<'db> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Return `true` if this class represents the builtin class `object`
|
||||
pub(crate) fn is_object(self, db: &'db dyn Db) -> bool {
|
||||
self.is_known(db, KnownClass::Object)
|
||||
}
|
||||
|
||||
fn file(self, db: &dyn Db) -> File {
|
||||
self.body_scope(db).file(db)
|
||||
}
|
||||
@@ -1068,7 +1067,7 @@ impl<'db> ClassLiteral<'db> {
|
||||
|
||||
for superclass in mro_iter {
|
||||
match superclass {
|
||||
ClassBase::Generic(_) | ClassBase::Protocol(_) => {
|
||||
ClassBase::Generic | ClassBase::Protocol => {
|
||||
// Skip over these very special class bases that aren't really classes.
|
||||
}
|
||||
ClassBase::Dynamic(_) => {
|
||||
@@ -1427,7 +1426,7 @@ impl<'db> ClassLiteral<'db> {
|
||||
|
||||
for superclass in self.iter_mro(db, specialization) {
|
||||
match superclass {
|
||||
ClassBase::Generic(_) | ClassBase::Protocol(_) => {
|
||||
ClassBase::Generic | ClassBase::Protocol => {
|
||||
// Skip over these very special class bases that aren't really classes.
|
||||
}
|
||||
ClassBase::Dynamic(_) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::Db;
|
||||
use crate::types::generics::{GenericContext, Specialization};
|
||||
use crate::types::generics::Specialization;
|
||||
use crate::types::{
|
||||
ClassType, DynamicType, KnownClass, KnownInstanceType, MroError, MroIterator, Type,
|
||||
TypeMapping, todo_type,
|
||||
@@ -19,11 +19,11 @@ pub enum ClassBase<'db> {
|
||||
Class(ClassType<'db>),
|
||||
/// Although `Protocol` is not a class in typeshed's stubs, it is at runtime,
|
||||
/// and can appear in the MRO of a class.
|
||||
Protocol(Option<GenericContext<'db>>),
|
||||
Protocol,
|
||||
/// Bare `Generic` cannot be subclassed directly in user code,
|
||||
/// but nonetheless appears in the MRO of classes that inherit from `Generic[T]`,
|
||||
/// `Protocol[T]`, or bare `Protocol`.
|
||||
Generic(Option<GenericContext<'db>>),
|
||||
Generic,
|
||||
}
|
||||
|
||||
impl<'db> ClassBase<'db> {
|
||||
@@ -35,60 +35,18 @@ impl<'db> ClassBase<'db> {
|
||||
match self {
|
||||
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
||||
Self::Class(class) => Self::Class(class.normalized(db)),
|
||||
Self::Protocol(generic_context) => {
|
||||
Self::Protocol(generic_context.map(|context| context.normalized(db)))
|
||||
}
|
||||
Self::Generic(generic_context) => {
|
||||
Self::Generic(generic_context.map(|context| context.normalized(db)))
|
||||
}
|
||||
Self::Protocol | Self::Generic => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn display(self, db: &'db dyn Db) -> impl std::fmt::Display + 'db {
|
||||
struct Display<'db> {
|
||||
base: ClassBase<'db>,
|
||||
db: &'db dyn Db,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Display<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.base {
|
||||
ClassBase::Dynamic(dynamic) => dynamic.fmt(f),
|
||||
ClassBase::Class(class @ ClassType::NonGeneric(_)) => {
|
||||
write!(f, "<class '{}'>", class.name(self.db))
|
||||
}
|
||||
ClassBase::Class(ClassType::Generic(alias)) => {
|
||||
write!(f, "<class '{}'>", alias.display(self.db))
|
||||
}
|
||||
ClassBase::Protocol(generic_context) => {
|
||||
f.write_str("typing.Protocol")?;
|
||||
if let Some(generic_context) = generic_context {
|
||||
generic_context.display(self.db).fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
ClassBase::Generic(generic_context) => {
|
||||
f.write_str("typing.Generic")?;
|
||||
if let Some(generic_context) = generic_context {
|
||||
generic_context.display(self.db).fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Display { base: self, db }
|
||||
}
|
||||
|
||||
pub(crate) fn name(self, db: &'db dyn Db) -> &'db str {
|
||||
match self {
|
||||
ClassBase::Class(class) => class.name(db),
|
||||
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
||||
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
||||
ClassBase::Dynamic(DynamicType::Todo(_) | DynamicType::TodoPEP695ParamSpec) => "@Todo",
|
||||
ClassBase::Protocol(_) => "Protocol",
|
||||
ClassBase::Generic(_) => "Generic",
|
||||
ClassBase::Protocol => "Protocol",
|
||||
ClassBase::Generic => "Generic",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,12 +213,8 @@ impl<'db> ClassBase<'db> {
|
||||
KnownInstanceType::Callable => {
|
||||
Self::try_from_type(db, todo_type!("Support for Callable as a base class"))
|
||||
}
|
||||
KnownInstanceType::Protocol(generic_context) => {
|
||||
Some(ClassBase::Protocol(generic_context))
|
||||
}
|
||||
KnownInstanceType::Generic(generic_context) => {
|
||||
Some(ClassBase::Generic(generic_context))
|
||||
}
|
||||
KnownInstanceType::Protocol(_) => Some(ClassBase::Protocol),
|
||||
KnownInstanceType::Generic(_) => Some(ClassBase::Generic),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -268,14 +222,14 @@ impl<'db> ClassBase<'db> {
|
||||
pub(super) fn into_class(self) -> Option<ClassType<'db>> {
|
||||
match self {
|
||||
Self::Class(class) => Some(class),
|
||||
Self::Dynamic(_) | Self::Generic(_) | Self::Protocol(_) => None,
|
||||
Self::Dynamic(_) | Self::Generic | Self::Protocol => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self {
|
||||
match self {
|
||||
Self::Class(class) => Self::Class(class.apply_type_mapping(db, type_mapping)),
|
||||
Self::Dynamic(_) | Self::Generic(_) | Self::Protocol(_) => self,
|
||||
Self::Dynamic(_) | Self::Generic | Self::Protocol => self,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +253,7 @@ impl<'db> ClassBase<'db> {
|
||||
.try_mro(db, specialization)
|
||||
.is_err_and(MroError::is_cycle)
|
||||
}
|
||||
ClassBase::Dynamic(_) | ClassBase::Generic(_) | ClassBase::Protocol(_) => false,
|
||||
ClassBase::Dynamic(_) | ClassBase::Generic | ClassBase::Protocol => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,12 +264,8 @@ impl<'db> ClassBase<'db> {
|
||||
additional_specialization: Option<Specialization<'db>>,
|
||||
) -> impl Iterator<Item = ClassBase<'db>> {
|
||||
match self {
|
||||
ClassBase::Protocol(context) => {
|
||||
ClassBaseMroIterator::length_3(db, self, ClassBase::Generic(context))
|
||||
}
|
||||
ClassBase::Dynamic(_) | ClassBase::Generic(_) => {
|
||||
ClassBaseMroIterator::length_2(db, self)
|
||||
}
|
||||
ClassBase::Protocol => ClassBaseMroIterator::length_3(db, self, ClassBase::Generic),
|
||||
ClassBase::Dynamic(_) | ClassBase::Generic => ClassBaseMroIterator::length_2(db, self),
|
||||
ClassBase::Class(class) => {
|
||||
ClassBaseMroIterator::from_class(db, class, additional_specialization)
|
||||
}
|
||||
@@ -338,12 +288,8 @@ impl<'db> From<ClassBase<'db>> for Type<'db> {
|
||||
match value {
|
||||
ClassBase::Dynamic(dynamic) => Type::Dynamic(dynamic),
|
||||
ClassBase::Class(class) => class.into(),
|
||||
ClassBase::Protocol(generic_context) => {
|
||||
Type::KnownInstance(KnownInstanceType::Protocol(generic_context))
|
||||
}
|
||||
ClassBase::Generic(generic_context) => {
|
||||
Type::KnownInstance(KnownInstanceType::Generic(generic_context))
|
||||
}
|
||||
ClassBase::Protocol => Type::KnownInstance(KnownInstanceType::Protocol(None)),
|
||||
ClassBase::Generic => Type::KnownInstance(KnownInstanceType::Generic(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::types::string_annotation::{
|
||||
};
|
||||
use crate::types::{KnownFunction, KnownInstanceType, Type, protocol_class::ProtocolClassLiteral};
|
||||
use crate::{Program, PythonVersionWithSource, declare_lint};
|
||||
use itertools::Itertools;
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, Span, SubDiagnostic};
|
||||
use ruff_db::files::system_path_to_file;
|
||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||
@@ -1698,10 +1699,7 @@ pub(super) fn report_implicit_return_type(
|
||||
let Some(class) = enclosing_class_of_method else {
|
||||
return;
|
||||
};
|
||||
if class
|
||||
.iter_mro(db, None)
|
||||
.any(|base| matches!(base, ClassBase::Protocol(_)))
|
||||
{
|
||||
if class.iter_mro(db, None).contains(&ClassBase::Protocol) {
|
||||
diagnostic.info(
|
||||
"Only functions in stub files, methods on protocol classes, \
|
||||
or methods with `@abstractmethod` are permitted to have empty bodies",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user