From 7f8f1ab2c114991ca213351112382938b7b03842 Mon Sep 17 00:00:00 2001
From: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
Date: Thu, 14 Aug 2025 13:23:43 -0400
Subject: [PATCH 001/160] [`pyflakes`] Add secondary annotation showing
previous definition (`F811`) (#19900)
## Summary
This is a second attempt at a first use of a new diagnostic feature
after #19886. I'll blame rustc for this one because it also has a
similar diagnostic:
We end up with a very similar diagnostic:
## Test Plan
New snapshots and manual tests above
---
crates/ruff/tests/lint.rs | 16 ++++++-------
crates/ruff_db/src/diagnostic/mod.rs | 15 ++++++++++++
crates/ruff_db/src/diagnostic/render.rs | 7 +++++-
crates/ruff_linter/src/checkers/ast/mod.rs | 13 ++++++++++-
.../pyflakes/rules/redefined_while_unused.rs | 12 +++++++++-
...ules__pyflakes__tests__F811_F811_0.py.snap | 9 +++++++-
...ules__pyflakes__tests__F811_F811_1.py.snap | 6 +++--
...les__pyflakes__tests__F811_F811_12.py.snap | 8 +++++--
...les__pyflakes__tests__F811_F811_15.py.snap | 7 +++++-
...les__pyflakes__tests__F811_F811_16.py.snap | 9 +++++++-
...les__pyflakes__tests__F811_F811_17.py.snap | 16 ++++++++++---
...ules__pyflakes__tests__F811_F811_2.py.snap | 6 +++--
...les__pyflakes__tests__F811_F811_21.py.snap | 10 +++++++-
...les__pyflakes__tests__F811_F811_23.py.snap | 7 ++++--
...les__pyflakes__tests__F811_F811_26.py.snap | 7 ++++--
...les__pyflakes__tests__F811_F811_28.py.snap | 7 ++++--
...es__pyflakes__tests__F811_F811_29.pyi.snap | 10 ++++++--
...ules__pyflakes__tests__F811_F811_3.py.snap | 6 +++--
...les__pyflakes__tests__F811_F811_30.py.snap | 23 ++++++++++++++-----
...les__pyflakes__tests__F811_F811_31.py.snap | 6 +++--
...les__pyflakes__tests__F811_F811_32.py.snap | 5 ++--
...ules__pyflakes__tests__F811_F811_4.py.snap | 6 +++--
...ules__pyflakes__tests__F811_F811_5.py.snap | 6 +++--
...ules__pyflakes__tests__F811_F811_6.py.snap | 6 +++--
...ules__pyflakes__tests__F811_F811_8.py.snap | 5 ++--
...shadowed_global_import_in_local_scope.snap | 7 ++++--
...shadowed_import_shadow_in_local_scope.snap | 7 ++++--
..._shadowed_local_import_in_local_scope.snap | 5 ++--
crates/ruff_linter/src/test.rs | 16 +++++++++----
29 files changed, 200 insertions(+), 63 deletions(-)
diff --git a/crates/ruff/tests/lint.rs b/crates/ruff/tests/lint.rs
index 52a374477b97b..c3f908c7fe6db 100644
--- a/crates/ruff/tests/lint.rs
+++ b/crates/ruff/tests/lint.rs
@@ -5588,15 +5588,15 @@ fn cookiecutter_globbing() -> Result<()> {
.args(STDIN_BASE_OPTIONS)
.arg("--select=F811")
.current_dir(tempdir.path()), @r"
- success: false
- exit_code: 1
- ----- stdout -----
- {{cookiecutter.repo_name}}/tests/maintest.py:3:8: F811 [*] Redefinition of unused `foo` from line 1
- Found 1 error.
- [*] 1 fixable with the `--fix` option.
+ success: false
+ exit_code: 1
+ ----- stdout -----
+ {{cookiecutter.repo_name}}/tests/maintest.py:3:8: F811 [*] Redefinition of unused `foo` from line 1: `foo` redefined here
+ Found 1 error.
+ [*] 1 fixable with the `--fix` option.
- ----- stderr -----
- ");
+ ----- stderr -----
+ ");
});
Ok(())
diff --git a/crates/ruff_db/src/diagnostic/mod.rs b/crates/ruff_db/src/diagnostic/mod.rs
index ddbc8f61e45f7..53b4247adccae 100644
--- a/crates/ruff_db/src/diagnostic/mod.rs
+++ b/crates/ruff_db/src/diagnostic/mod.rs
@@ -254,6 +254,11 @@ impl Diagnostic {
.find(|ann| ann.is_primary)
}
+ /// Returns a mutable borrow of all annotations of this diagnostic.
+ pub fn annotations_mut(&mut self) -> impl Iterator- {
+ Arc::make_mut(&mut self.inner).annotations.iter_mut()
+ }
+
/// Returns the "primary" span of this diagnostic if one exists.
///
/// When there are multiple primary spans, then the first one that was
@@ -310,6 +315,11 @@ impl Diagnostic {
&self.inner.subs
}
+ /// Returns a mutable borrow of the sub-diagnostics of this diagnostic.
+ pub fn sub_diagnostics_mut(&mut self) -> impl Iterator
- {
+ Arc::make_mut(&mut self.inner).subs.iter_mut()
+ }
+
/// Returns the fix for this diagnostic if it exists.
pub fn fix(&self) -> Option<&Fix> {
self.inner.fix.as_ref()
@@ -621,6 +631,11 @@ impl SubDiagnostic {
&self.inner.annotations
}
+ /// Returns a mutable borrow of the annotations of this sub-diagnostic.
+ pub fn annotations_mut(&mut self) -> impl Iterator
- {
+ self.inner.annotations.iter_mut()
+ }
+
/// Returns a shared borrow of the "primary" annotation of this diagnostic
/// if one exists.
///
diff --git a/crates/ruff_db/src/diagnostic/render.rs b/crates/ruff_db/src/diagnostic/render.rs
index eba3253c964cc..2b5230117e911 100644
--- a/crates/ruff_db/src/diagnostic/render.rs
+++ b/crates/ruff_db/src/diagnostic/render.rs
@@ -264,7 +264,12 @@ impl<'a> ResolvedDiagnostic<'a> {
.annotations
.iter()
.filter_map(|ann| {
- let path = ann.span.file.path(resolver);
+ let path = ann
+ .span
+ .file
+ .relative_path(resolver)
+ .to_str()
+ .unwrap_or_else(|| ann.span.file.path(resolver));
let diagnostic_source = ann.span.file.diagnostic_source(resolver);
ResolvedAnnotation::new(path, &diagnostic_source, ann, resolver)
})
diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs
index 76c3e82462c69..1437b1655dd0c 100644
--- a/crates/ruff_linter/src/checkers/ast/mod.rs
+++ b/crates/ruff_linter/src/checkers/ast/mod.rs
@@ -28,7 +28,7 @@ use itertools::Itertools;
use log::debug;
use rustc_hash::{FxHashMap, FxHashSet};
-use ruff_db::diagnostic::Diagnostic;
+use ruff_db::diagnostic::{Annotation, Diagnostic, IntoDiagnosticMessage, Span};
use ruff_diagnostics::{Applicability, Fix, IsolationLevel};
use ruff_notebook::{CellOffsets, NotebookIndex};
use ruff_python_ast::helpers::{collect_import_from_member, is_docstring_stmt, to_module_path};
@@ -3305,6 +3305,17 @@ impl DiagnosticGuard<'_, '_> {
Err(err) => log::debug!("Failed to create fix for {}: {}", self.name(), err),
}
}
+
+ /// Add a secondary annotation with the given message and range.
+ pub(crate) fn secondary_annotation<'a>(
+ &mut self,
+ message: impl IntoDiagnosticMessage + 'a,
+ range: impl Ranged,
+ ) {
+ let span = Span::from(self.context.source_file.clone()).with_range(range.range());
+ let ann = Annotation::secondary(span).message(message);
+ self.diagnostic.as_mut().unwrap().annotate(ann);
+ }
}
impl std::ops::Deref for DiagnosticGuard<'_, '_> {
diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/redefined_while_unused.rs b/crates/ruff_linter/src/rules/pyflakes/rules/redefined_while_unused.rs
index a60b67f82d064..65019a997b2cc 100644
--- a/crates/ruff_linter/src/rules/pyflakes/rules/redefined_while_unused.rs
+++ b/crates/ruff_linter/src/rules/pyflakes/rules/redefined_while_unused.rs
@@ -183,14 +183,24 @@ pub(crate) fn redefined_while_unused(checker: &Checker, scope_id: ScopeId, scope
// Create diagnostics for each statement.
for (source, entries) in &redefinitions {
for (shadowed, binding) in entries {
+ let name = binding.name(checker.source());
let mut diagnostic = checker.report_diagnostic(
RedefinedWhileUnused {
- name: binding.name(checker.source()).to_string(),
+ name: name.to_string(),
row: checker.compute_source_row(shadowed.start()),
},
binding.range(),
);
+ diagnostic.secondary_annotation(
+ format_args!("previous definition of `{name}` here"),
+ shadowed,
+ );
+
+ if let Some(ann) = diagnostic.primary_annotation_mut() {
+ ann.set_message(format_args!("`{name}` redefined here"));
+ }
+
if let Some(range) = binding.parent_range(checker.semantic()) {
diagnostic.set_parent(range.start());
}
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_0.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_0.py.snap
index 9dbabf2cf26a1..08c6403c54bdf 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_0.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_0.py.snap
@@ -5,7 +5,14 @@ F811 Redefinition of unused `bar` from line 6
--> F811_0.py:10:5
|
10 | def bar():
- | ^^^
+ | ^^^ `bar` redefined here
11 | pass
|
+ ::: F811_0.py:6:5
+ |
+ 5 | @foo
+ 6 | def bar():
+ | --- previous definition of `bar` here
+ 7 | pass
+ |
help: Remove definition: `bar`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_1.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_1.py.snap
index e666db4b813b0..5b01c3bdc7839 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_1.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_1.py.snap
@@ -2,9 +2,11 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `FU` from line 1
- --> F811_1.py:1:25
+ --> F811_1.py:1:14
|
1 | import fu as FU, bar as FU
- | ^^
+ | -- ^^ `FU` redefined here
+ | |
+ | previous definition of `FU` here
|
help: Remove definition: `FU`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_12.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_12.py.snap
index 58f521edf0ff7..8be7749183963 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_12.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_12.py.snap
@@ -2,12 +2,16 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `mixer` from line 2
- --> F811_12.py:6:20
+ --> F811_12.py:2:20
|
+1 | try:
+2 | from aa import mixer
+ | ----- previous definition of `mixer` here
+3 | except ImportError:
4 | pass
5 | else:
6 | from bb import mixer
- | ^^^^^
+ | ^^^^^ `mixer` redefined here
7 | mixer(123)
|
help: Remove definition: `mixer`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_15.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_15.py.snap
index d457a39a20b0f..e48bf8e55ed59 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_15.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_15.py.snap
@@ -5,7 +5,12 @@ F811 Redefinition of unused `fu` from line 1
--> F811_15.py:4:5
|
4 | def fu():
- | ^^
+ | ^^ `fu` redefined here
5 | pass
|
+ ::: F811_15.py:1:8
+ |
+1 | import fu
+ | -- previous definition of `fu` here
+ |
help: Remove definition: `fu`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_16.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_16.py.snap
index f8a1351dff7b0..704155bf81c73 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_16.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_16.py.snap
@@ -7,7 +7,14 @@ F811 Redefinition of unused `fu` from line 3
6 | def bar():
7 | def baz():
8 | def fu():
- | ^^
+ | ^^ `fu` redefined here
9 | pass
|
+ ::: F811_16.py:3:8
+ |
+1 | """Test that shadowing a global with a nested function generates a warning."""
+2 |
+3 | import fu
+ | -- previous definition of `fu` here
+ |
help: Remove definition: `fu`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_17.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_17.py.snap
index 6e16f5399270e..70cee8d8c0a5d 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_17.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_17.py.snap
@@ -6,10 +6,16 @@ F811 [*] Redefinition of unused `fu` from line 2
|
5 | def bar():
6 | import fu
- | ^^
+ | ^^ `fu` redefined here
7 |
8 | def baz():
|
+ ::: F811_17.py:2:8
+ |
+1 | """Test that shadowing a global name with a nested function generates a warning."""
+2 | import fu
+ | -- previous definition of `fu` here
+ |
help: Remove definition: `fu`
ℹ Safe fix
@@ -22,11 +28,15 @@ help: Remove definition: `fu`
9 8 | def fu():
F811 Redefinition of unused `fu` from line 6
- --> F811_17.py:9:13
+ --> F811_17.py:6:12
|
+ 5 | def bar():
+ 6 | import fu
+ | -- previous definition of `fu` here
+ 7 |
8 | def baz():
9 | def fu():
- | ^^
+ | ^^ `fu` redefined here
10 | pass
|
help: Remove definition: `fu`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_2.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_2.py.snap
index 05ec31f26c1b1..7aa2e1019d4b6 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_2.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_2.py.snap
@@ -2,9 +2,11 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `FU` from line 1
- --> F811_2.py:1:34
+ --> F811_2.py:1:23
|
1 | from moo import fu as FU, bar as FU
- | ^^
+ | -- ^^ `FU` redefined here
+ | |
+ | previous definition of `FU` here
|
help: Remove definition: `FU`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_21.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_21.py.snap
index 9cf6effbe6b7a..196596c3ce078 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_21.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_21.py.snap
@@ -7,9 +7,17 @@ F811 [*] Redefinition of unused `Sequence` from line 26
30 | from typing import (
31 | List, # noqa: F811
32 | Sequence,
- | ^^^^^^^^
+ | ^^^^^^^^ `Sequence` redefined here
33 | )
|
+ ::: F811_21.py:26:5
+ |
+24 | from typing import (
+25 | List, # noqa
+26 | Sequence, # noqa
+ | -------- previous definition of `Sequence` here
+27 | )
+ |
help: Remove definition: `Sequence`
ℹ Safe fix
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_23.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_23.py.snap
index d56b340e5b1fd..46b2551427257 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_23.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_23.py.snap
@@ -2,10 +2,13 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `foo` from line 3
- --> F811_23.py:4:15
+ --> F811_23.py:3:15
|
+1 | """Test that shadowing an explicit re-export produces a warning."""
+2 |
3 | import foo as foo
+ | --- previous definition of `foo` here
4 | import bar as foo
- | ^^^
+ | ^^^ `foo` redefined here
|
help: Remove definition: `foo`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_26.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_26.py.snap
index 2a8febc47ca9e..1025efb9fdebf 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_26.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_26.py.snap
@@ -2,12 +2,15 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `func` from line 2
- --> F811_26.py:5:9
+ --> F811_26.py:2:9
|
+1 | class Class:
+2 | def func(self):
+ | ---- previous definition of `func` here
3 | pass
4 |
5 | def func(self):
- | ^^^^
+ | ^^^^ `func` redefined here
6 | pass
|
help: Remove definition: `func`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_28.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_28.py.snap
index 302c8ebf9f742..cf120b2cd7ea0 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_28.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_28.py.snap
@@ -2,11 +2,14 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `datetime` from line 3
- --> F811_28.py:4:22
+ --> F811_28.py:3:8
|
+1 | """Regression test for: https://github.com/astral-sh/ruff/issues/10384"""
+2 |
3 | import datetime
+ | -------- previous definition of `datetime` here
4 | from datetime import datetime
- | ^^^^^^^^
+ | ^^^^^^^^ `datetime` redefined here
5 |
6 | datetime(1, 2, 3)
|
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_29.pyi.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_29.pyi.snap
index d2a1b5e0cac73..a7e005d2693a0 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_29.pyi.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_29.pyi.snap
@@ -2,11 +2,17 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `Bar` from line 3
- --> F811_29.pyi:8:1
+ --> F811_29.pyi:3:24
|
+1 | """Regression test for: https://github.com/astral-sh/ruff/issues/10509"""
+2 |
+3 | from foo import Bar as Bar
+ | --- previous definition of `Bar` here
+4 |
+5 | class Eggs:
6 | Bar: int # OK
7 |
8 | Bar = 1 # F811
- | ^^^
+ | ^^^ `Bar` redefined here
|
help: Remove definition: `Bar`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_3.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_3.py.snap
index 2e51c6831c08d..df164062ceadb 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_3.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_3.py.snap
@@ -2,9 +2,11 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `fu` from line 1
- --> F811_3.py:1:12
+ --> F811_3.py:1:8
|
1 | import fu; fu = 3
- | ^^
+ | -- ^^ `fu` redefined here
+ | |
+ | previous definition of `fu` here
|
help: Remove definition: `fu`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_30.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_30.py.snap
index 09bae7b5149e1..d0de3c478622b 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_30.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_30.py.snap
@@ -2,32 +2,43 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `bar` from line 10
- --> F811_30.py:12:9
+ --> F811_30.py:10:5
|
+ 8 | """Foo."""
+ 9 |
10 | bar = foo
+ | --- previous definition of `bar` here
11 |
12 | def bar(self) -> None:
- | ^^^
+ | ^^^ `bar` redefined here
13 | """Bar."""
|
help: Remove definition: `bar`
F811 Redefinition of unused `baz` from line 18
- --> F811_30.py:21:5
+ --> F811_30.py:18:9
|
+16 | class B:
+17 | """B."""
+18 | def baz(self) -> None:
+ | --- previous definition of `baz` here
19 | """Baz."""
20 |
21 | baz = 1
- | ^^^
+ | ^^^ `baz` redefined here
|
help: Remove definition: `baz`
F811 Redefinition of unused `foo` from line 26
- --> F811_30.py:29:12
+ --> F811_30.py:26:9
|
+24 | class C:
+25 | """C."""
+26 | def foo(self) -> None:
+ | --- previous definition of `foo` here
27 | """Foo."""
28 |
29 | bar = (foo := 1)
- | ^^^
+ | ^^^ `foo` redefined here
|
help: Remove definition: `foo`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_31.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_31.py.snap
index 7a08ea3888c08..1e8be05daaaad 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_31.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_31.py.snap
@@ -2,12 +2,14 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `baz` from line 17
- --> F811_31.py:19:29
+ --> F811_31.py:17:5
|
+16 | try:
17 | baz = None
+ | --- previous definition of `baz` here
18 |
19 | from some_module import baz
- | ^^^
+ | ^^^ `baz` redefined here
20 | except ImportError:
21 | pass
|
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_32.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_32.py.snap
index 6b00fc2d31197..c6a3a8d8fb45a 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_32.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_32.py.snap
@@ -2,12 +2,13 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 [*] Redefinition of unused `List` from line 4
- --> F811_32.py:5:5
+ --> F811_32.py:4:5
|
3 | from typing import (
4 | List,
+ | ---- previous definition of `List` here
5 | List,
- | ^^^^
+ | ^^^^ `List` redefined here
6 | )
|
help: Remove definition: `List`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_4.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_4.py.snap
index 11bb7bd8244c8..0148e0bde126c 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_4.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_4.py.snap
@@ -2,9 +2,11 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `fu` from line 1
- --> F811_4.py:1:12
+ --> F811_4.py:1:8
|
1 | import fu; fu, bar = 3
- | ^^
+ | -- ^^ `fu` redefined here
+ | |
+ | previous definition of `fu` here
|
help: Remove definition: `fu`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_5.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_5.py.snap
index 908d45c1bb073..420172d79e8a5 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_5.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_5.py.snap
@@ -2,9 +2,11 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 Redefinition of unused `fu` from line 1
- --> F811_5.py:1:13
+ --> F811_5.py:1:8
|
1 | import fu; [fu, bar] = 3
- | ^^
+ | -- ^^ `fu` redefined here
+ | |
+ | previous definition of `fu` here
|
help: Remove definition: `fu`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_6.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_6.py.snap
index e2c3c0cf88450..cd6894d8c03b0 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_6.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_6.py.snap
@@ -2,12 +2,14 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 [*] Redefinition of unused `os` from line 5
- --> F811_6.py:6:12
+ --> F811_6.py:5:12
|
+3 | i = 2
4 | if i == 1:
5 | import os
+ | -- previous definition of `os` here
6 | import os
- | ^^
+ | ^^ `os` redefined here
7 | os.path
|
help: Remove definition: `os`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_8.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_8.py.snap
index a3236f8fbe7f0..e198880e3779b 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_8.py.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F811_F811_8.py.snap
@@ -2,12 +2,13 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 [*] Redefinition of unused `os` from line 4
- --> F811_8.py:5:12
+ --> F811_8.py:4:12
|
3 | try:
4 | import os
+ | -- previous definition of `os` here
5 | import os
- | ^^
+ | ^^ `os` redefined here
6 | except:
7 | pass
|
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_global_import_in_local_scope.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_global_import_in_local_scope.snap
index e7ed86bd467b9..e8abef0b5368d 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_global_import_in_local_scope.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_global_import_in_local_scope.snap
@@ -19,11 +19,14 @@ help: Remove unused import: `os`
5 4 | import os
F811 [*] Redefinition of unused `os` from line 2
- --> :5:12
+ --> :2:8
|
+2 | import os
+ | -- previous definition of `os` here
+3 |
4 | def f():
5 | import os
- | ^^
+ | ^^ `os` redefined here
6 |
7 | # Despite this `del`, `import os` in `f` should still be flagged as shadowing an unused
|
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_import_shadow_in_local_scope.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_import_shadow_in_local_scope.snap
index 7076d537084c3..02e03119dcc67 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_import_shadow_in_local_scope.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_import_shadow_in_local_scope.snap
@@ -19,11 +19,14 @@ help: Remove unused import: `os`
5 4 | os = 1
F811 Redefinition of unused `os` from line 2
- --> :5:5
+ --> :2:8
|
+2 | import os
+ | -- previous definition of `os` here
+3 |
4 | def f():
5 | os = 1
- | ^^
+ | ^^ `os` redefined here
6 | print(os)
|
help: Remove definition: `os`
diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_local_import_in_local_scope.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_local_import_in_local_scope.snap
index e96cdc07f7f11..41041f52628a9 100644
--- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_local_import_in_local_scope.snap
+++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__del_shadowed_local_import_in_local_scope.snap
@@ -2,12 +2,13 @@
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811 [*] Redefinition of unused `os` from line 3
- --> :4:12
+ --> :3:12
|
2 | def f():
3 | import os
+ | -- previous definition of `os` here
4 | import os
- | ^^
+ | ^^ `os` redefined here
5 |
6 | # Despite this `del`, `import os` should still be flagged as shadowing an unused
|
diff --git a/crates/ruff_linter/src/test.rs b/crates/ruff_linter/src/test.rs
index 02eca4ca05848..2dee7dcbb26ae 100644
--- a/crates/ruff_linter/src/test.rs
+++ b/crates/ruff_linter/src/test.rs
@@ -9,7 +9,7 @@ use anyhow::Result;
use itertools::Itertools;
use rustc_hash::FxHashMap;
-use ruff_db::diagnostic::Diagnostic;
+use ruff_db::diagnostic::{Diagnostic, Span};
use ruff_notebook::Notebook;
#[cfg(not(fuzzing))]
use ruff_notebook::NotebookError;
@@ -281,10 +281,16 @@ Either ensure you always emit a fix or change `Violation::FIX_AVAILABILITY` to e
// noqa offset and the source file
let range = diagnostic.expect_range();
diagnostic.set_noqa_offset(directives.noqa_line_for.resolve(range.start()));
- if let Some(annotation) = diagnostic.primary_annotation_mut() {
- annotation.set_span(
- ruff_db::diagnostic::Span::from(source_code.clone()).with_range(range),
- );
+ // This part actually is necessary to avoid long relative paths in snapshots.
+ for annotation in diagnostic.annotations_mut() {
+ let range = annotation.get_span().range().unwrap();
+ annotation.set_span(Span::from(source_code.clone()).with_range(range));
+ }
+ for sub in diagnostic.sub_diagnostics_mut() {
+ for annotation in sub.annotations_mut() {
+ let range = annotation.get_span().range().unwrap();
+ annotation.set_span(Span::from(source_code.clone()).with_range(range));
+ }
}
diagnostic
From ce938fe2056ded2a471a74922293e5ec9d61e6b0 Mon Sep 17 00:00:00 2001
From: Micha Reiser
Date: Thu, 14 Aug 2025 20:38:39 +0200
Subject: [PATCH 002/160] [ty] Speedup project file discovery (#19913)
---
crates/ruff_db/src/files.rs | 7 +++--
crates/ty_project/src/db.rs | 10 ++++++
crates/ty_project/src/walk.rs | 57 ++++++++++++-----------------------
3 files changed, 33 insertions(+), 41 deletions(-)
diff --git a/crates/ruff_db/src/files.rs b/crates/ruff_db/src/files.rs
index 9f6bcbbdd15ff..ff8c9c8fc394a 100644
--- a/crates/ruff_db/src/files.rs
+++ b/crates/ruff_db/src/files.rs
@@ -87,11 +87,12 @@ impl Files {
.system_by_path
.entry(absolute.clone())
.or_insert_with(|| {
- tracing::trace!("Adding file '{path}'");
-
let metadata = db.system().path_metadata(path);
+
+ tracing::trace!("Adding file '{absolute}'");
+
let durability = self
- .root(db, path)
+ .root(db, &absolute)
.map_or(Durability::default(), |root| root.durability(db));
let builder = File::builder(FilePath::System(absolute))
diff --git a/crates/ty_project/src/db.rs b/crates/ty_project/src/db.rs
index 1315811866798..a59006689bbac 100644
--- a/crates/ty_project/src/db.rs
+++ b/crates/ty_project/src/db.rs
@@ -21,6 +21,8 @@ mod changes;
#[salsa::db]
pub trait Db: SemanticDb {
fn project(&self) -> Project;
+
+ fn dyn_clone(&self) -> Box;
}
#[salsa::db]
@@ -484,6 +486,10 @@ impl Db for ProjectDatabase {
fn project(&self) -> Project {
self.project.unwrap()
}
+
+ fn dyn_clone(&self) -> Box {
+ Box::new(self.clone())
+ }
}
#[cfg(feature = "format")]
@@ -611,6 +617,10 @@ pub(crate) mod tests {
fn project(&self) -> Project {
self.project.unwrap()
}
+
+ fn dyn_clone(&self) -> Box {
+ Box::new(self.clone())
+ }
}
#[salsa::db]
diff --git a/crates/ty_project/src/walk.rs b/crates/ty_project/src/walk.rs
index ea161e187d7f4..8c9958c4166c6 100644
--- a/crates/ty_project/src/walk.rs
+++ b/crates/ty_project/src/walk.rs
@@ -4,7 +4,7 @@ use ruff_db::files::{File, system_path_to_file};
use ruff_db::system::walk_directory::{ErrorKind, WalkDirectoryBuilder, WalkState};
use ruff_db::system::{SystemPath, SystemPathBuf};
use ruff_python_ast::PySourceType;
-use rustc_hash::{FxBuildHasher, FxHashSet};
+use rustc_hash::FxHashSet;
use std::path::PathBuf;
use thiserror::Error;
@@ -163,20 +163,24 @@ impl<'a> ProjectFilesWalker<'a> {
/// Walks the project paths and collects the paths of all files that
/// are included in the project.
- pub(crate) fn walk_paths(self) -> (Vec, Vec) {
- let paths = std::sync::Mutex::new(Vec::new());
+ pub(crate) fn collect_vec(self, db: &dyn Db) -> (Vec, Vec) {
+ let files = std::sync::Mutex::new(Vec::new());
let diagnostics = std::sync::Mutex::new(Vec::new());
self.walker.run(|| {
- Box::new(|entry| {
+ let db = db.dyn_clone();
+ let filter = &self.filter;
+ let files = &files;
+ let diagnostics = &diagnostics;
+
+ Box::new(move |entry| {
match entry {
Ok(entry) => {
// Skip excluded directories unless they were explicitly passed to the walker
// (which is the case passed to `ty check `).
if entry.file_type().is_directory() {
if entry.depth() > 0 {
- let directory_included = self
- .filter
+ let directory_included = filter
.is_directory_included(entry.path(), GlobFilterCheckMode::TopDown);
return match directory_included {
IncludeResult::Included => WalkState::Continue,
@@ -210,8 +214,7 @@ impl<'a> ProjectFilesWalker<'a> {
// For all files, except the ones that were explicitly passed to the walker (CLI),
// check if they're included in the project.
if entry.depth() > 0 {
- match self
- .filter
+ match filter
.is_file_included(entry.path(), GlobFilterCheckMode::TopDown)
{
IncludeResult::Included => {},
@@ -232,8 +235,11 @@ impl<'a> ProjectFilesWalker<'a> {
}
}
- let mut paths = paths.lock().unwrap();
- paths.push(entry.into_path());
+ // If this returns `Err`, then the file was deleted between now and when the walk callback was called.
+ // We can ignore this.
+ if let Ok(file) = system_path_to_file(&*db, entry.path()) {
+ files.lock().unwrap().push(file);
+ }
}
}
Err(error) => match error.kind() {
@@ -274,39 +280,14 @@ impl<'a> ProjectFilesWalker<'a> {
});
(
- paths.into_inner().unwrap(),
+ files.into_inner().unwrap(),
diagnostics.into_inner().unwrap(),
)
}
- pub(crate) fn collect_vec(self, db: &dyn Db) -> (Vec, Vec) {
- let (paths, diagnostics) = self.walk_paths();
-
- (
- paths
- .into_iter()
- .filter_map(move |path| {
- // If this returns `None`, then the file was deleted between the `walk_directory` call and now.
- // We can ignore this.
- system_path_to_file(db, &path).ok()
- })
- .collect(),
- diagnostics,
- )
- }
-
pub(crate) fn collect_set(self, db: &dyn Db) -> (FxHashSet, Vec) {
- let (paths, diagnostics) = self.walk_paths();
-
- let mut files = FxHashSet::with_capacity_and_hasher(paths.len(), FxBuildHasher);
-
- for path in paths {
- if let Ok(file) = system_path_to_file(db, &path) {
- files.insert(file);
- }
- }
-
- (files, diagnostics)
+ let (files, diagnostics) = self.collect_vec(db);
+ (files.into_iter().collect(), diagnostics)
}
}
From 82350a398e2bd8ed57db8fed94b0eae2071b446f Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Thu, 14 Aug 2025 22:14:31 +0100
Subject: [PATCH 003/160] [ty] Remove use of `ClassBase::try_from_type` from
`super()` machinery (#19902)
---
.../resources/mdtest/class/super.md | 16 ++++++++
crates/ty_python_semantic/src/types.rs | 41 +++++++++++--------
2 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/class/super.md b/crates/ty_python_semantic/resources/mdtest/class/super.md
index ecffca0fb65d1..c7b6e0ef803af 100644
--- a/crates/ty_python_semantic/resources/mdtest/class/super.md
+++ b/crates/ty_python_semantic/resources/mdtest/class/super.md
@@ -331,6 +331,9 @@ instance or a subclass of the first. If either condition is violated, a `TypeErr
runtime.
```py
+import typing
+import collections
+
def f(x: int):
# error: [invalid-super-argument] "`int` is not a valid class"
super(x, x)
@@ -367,6 +370,19 @@ reveal_type(super(B, A))
reveal_type(super(B, object))
super(object, object()).__class__
+
+# Not all objects valid in a class's bases list are valid as the first argument to `super()`.
+# For example, it's valid to inherit from `typing.ChainMap`, but it's not valid as the first argument to `super()`.
+#
+# error: [invalid-super-argument] "`typing.ChainMap` is not a valid class"
+reveal_type(super(typing.ChainMap, collections.ChainMap())) # revealed: Unknown
+
+# Meanwhile, it's not valid to inherit from unsubscripted `typing.Generic`,
+# but it *is* valid as the first argument to `super()`.
+reveal_type(super(typing.Generic, typing.SupportsInt)) # revealed: >
+
+def _(x: type[typing.Any], y: typing.Any):
+ reveal_type(super(x, y)) # revealed:
```
### Instance Member Access via `super`
diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs
index 3c6a9d2e8caec..2ae65d7f90557 100644
--- a/crates/ty_python_semantic/src/types.rs
+++ b/crates/ty_python_semantic/src/types.rs
@@ -9526,23 +9526,32 @@ impl<'db> BoundSuperType<'db> {
));
}
- // TODO: having to get a class-literal just to pass it in here is silly.
- // `BoundSuperType` should probably not be using `ClassBase::try_from_type` here;
- // this also leads to false negatives in some cases. See discussion in
- // .
- let pivot_class = ClassBase::try_from_type(
- db,
- pivot_class_type,
- KnownClass::Object
- .to_class_literal(db)
- .into_class_literal()
- .expect("`object` should always exist in typeshed"),
- )
- .ok_or({
- BoundSuperError::InvalidPivotClassType {
- pivot_class: pivot_class_type,
+ // We don't use `Classbase::try_from_type` here because:
+ // - There are objects that may validly be present in a class's bases list
+ // but are not valid as pivot classes, e.g. `typing.ChainMap`
+ // - There are objects that are not valid in a class's bases list
+ // but are valid as pivot classes, e.g. unsubscripted `typing.Generic`
+ let pivot_class = match pivot_class_type {
+ Type::ClassLiteral(class) => ClassBase::Class(ClassType::NonGeneric(class)),
+ Type::GenericAlias(class) => ClassBase::Class(ClassType::Generic(class)),
+ Type::SubclassOf(subclass_of) if subclass_of.subclass_of().is_dynamic() => {
+ ClassBase::Dynamic(
+ subclass_of
+ .subclass_of()
+ .into_dynamic()
+ .expect("Checked in branch arm"),
+ )
}
- })?;
+ Type::SpecialForm(SpecialFormType::Protocol) => ClassBase::Protocol,
+ Type::SpecialForm(SpecialFormType::Generic) => ClassBase::Generic,
+ Type::SpecialForm(SpecialFormType::TypedDict) => ClassBase::TypedDict,
+ Type::Dynamic(dynamic) => ClassBase::Dynamic(dynamic),
+ _ => {
+ return Err(BoundSuperError::InvalidPivotClassType {
+ pivot_class: pivot_class_type,
+ });
+ }
+ };
let owner = SuperOwnerKind::try_from_type(db, owner_type)
.and_then(|owner| {
From f6093452edf5e54463e3d3ad2a3ada9d89b97ae5 Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Thu, 14 Aug 2025 22:25:45 +0100
Subject: [PATCH 004/160] [ty] Synthesize read-only properties for all declared
members on `NamedTuple` classes (#19899)
---
.../resources/mdtest/named_tuple.md | 63 ++++++++++++++++++-
crates/ty_python_semantic/src/types/class.rs | 16 ++++-
2 files changed, 74 insertions(+), 5 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/named_tuple.md b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
index 3530ac4da4f1f..e642b25b2eb8d 100644
--- a/crates/ty_python_semantic/resources/mdtest/named_tuple.md
+++ b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
@@ -74,8 +74,16 @@ Person(3, "Eve", 99, "extra")
# error: [invalid-argument-type]
Person(id="3", name="Eve")
-# TODO: over-writing NamedTuple fields should be an error
+reveal_type(Person.id) # revealed: property
+reveal_type(Person.name) # revealed: property
+reveal_type(Person.age) # revealed: property
+
+# TODO... the error is correct, but this is not the friendliest error message
+# for assigning to a read-only property :-)
+#
+# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `id` on type `Person` with custom `__set__` method"
alice.id = 42
+# error: [invalid-assignment]
bob.age = None
```
@@ -151,9 +159,42 @@ from typing import NamedTuple
class User(NamedTuple):
id: int
name: str
+ age: int | None
+ nickname: str
class SuperUser(User):
- id: int # this should be an error
+ # TODO: this should be an error because it implies that the `id` attribute on
+ # `SuperUser` is mutable, but the read-only `id` property from the superclass
+ # has not been overridden in the class body
+ id: int
+
+ # this is fine; overriding a read-only attribute with a mutable one
+ # does not conflict with the Liskov Substitution Principle
+ name: str = "foo"
+
+ # this is also fine
+ @property
+ def age(self) -> int:
+ return super().age or 42
+
+ def now_called_robert(self):
+ self.name = "Robert" # fine because overridden with a mutable attribute
+
+ # TODO: this should cause us to emit an error as we're assigning to a read-only property
+ # inherited from the `NamedTuple` superclass (requires https://github.com/astral-sh/ty/issues/159)
+ self.nickname = "Bob"
+
+james = SuperUser(0, "James", 42, "Jimmy")
+
+# fine because the property on the superclass was overridden with a mutable attribute
+# on the subclass
+james.name = "Robert"
+
+# TODO: the error is correct (can't assign to the read-only property inherited from the superclass)
+# but the error message could be friendlier :-)
+#
+# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `nickname` on type `SuperUser` with custom `__set__` method"
+james.nickname = "Bob"
```
### Generic named tuples
@@ -164,13 +205,29 @@ python-version = "3.12"
```
```py
-from typing import NamedTuple
+from typing import NamedTuple, Generic, TypeVar
class Property[T](NamedTuple):
name: str
value: T
reveal_type(Property("height", 3.4)) # revealed: Property[float]
+reveal_type(Property.value) # revealed: property
+reveal_type(Property.value.fget) # revealed: (self, /) -> Unknown
+reveal_type(Property[str].value.fget) # revealed: (self, /) -> str
+reveal_type(Property("height", 3.4).value) # revealed: float
+
+T = TypeVar("T")
+
+class LegacyProperty(NamedTuple, Generic[T]):
+ name: str
+ value: T
+
+reveal_type(LegacyProperty("height", 42)) # revealed: LegacyProperty[int]
+reveal_type(LegacyProperty.value) # revealed: property
+reveal_type(LegacyProperty.value.fget) # revealed: (self, /) -> Unknown
+reveal_type(LegacyProperty[str].value.fget) # revealed: (self, /) -> str
+reveal_type(LegacyProperty("height", 3.4).value) # revealed: float
```
## Attributes on `NamedTuple`
diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs
index 0940ec1f6def9..60cf7c491e417 100644
--- a/crates/ty_python_semantic/src/types/class.rs
+++ b/crates/ty_python_semantic/src/types/class.rs
@@ -24,8 +24,8 @@ use crate::types::tuple::{TupleSpec, TupleType};
use crate::types::{
ApplyTypeMappingVisitor, BareTypeAliasType, Binding, BoundSuperError, BoundSuperType,
CallableType, DataclassParams, DeprecatedInstance, HasRelationToVisitor, KnownInstanceType,
- NormalizedVisitor, StringLiteralType, TypeAliasType, TypeMapping, TypeRelation,
- TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, declaration_type,
+ NormalizedVisitor, PropertyInstanceType, StringLiteralType, TypeAliasType, TypeMapping,
+ TypeRelation, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, declaration_type,
infer_definition_types, todo_type,
};
use crate::{
@@ -1862,6 +1862,18 @@ impl<'db> ClassLiteral<'db> {
.with_qualifiers(TypeQualifiers::CLASS_VAR);
}
+ if CodeGeneratorKind::NamedTuple.matches(db, self) {
+ if let Some(field) = self.own_fields(db, specialization).get(name) {
+ let property_getter_signature = Signature::new(
+ Parameters::new([Parameter::positional_only(Some(Name::new_static("self")))]),
+ Some(field.declared_ty),
+ );
+ let property_getter = CallableType::single(db, property_getter_signature);
+ let property = PropertyInstanceType::new(db, Some(property_getter), None);
+ return Place::bound(Type::PropertyInstance(property)).into();
+ }
+ }
+
let body_scope = self.body_scope(db);
let symbol = class_symbol(db, body_scope, name).map_type(|ty| {
// The `__new__` and `__init__` members of a non-specialized generic class are handled
From 957320c0f17080a9ccfd788b9d6ed998050b0052 Mon Sep 17 00:00:00 2001
From: Andrii Turov
Date: Fri, 15 Aug 2025 00:38:33 +0300
Subject: [PATCH 005/160] [ty] Add diagnostics for invalid `await` expressions
(#19711)
## Summary
This PR adds a new lint, `invalid-await`, for all sorts of reasons why
an object may not be `await`able, as discussed in astral-sh/ty#919.
Precisely, `__await__` is guarded against being missing, possibly
unbound, or improperly defined (expects additional arguments or doesn't
return an iterator).
Of course, diagnostics need to be fine-tuned. If `__await__` cannot be
called with no extra arguments, it indicates an error (or a quirk?) in
the method signature, not at the call site. Without any doubt, such an
object is not `Awaitable`, but I feel like talking about arguments for
an *implicit* call is a bit leaky.
I didn't reference any actual diagnostic messages in the lint
definition, because I want to hear feedback first.
Also, there's no mention of the actual required method signature for
`__await__` anywhere in the docs. The only reference I had is the
`typing` stub. I basically ended up linking `[Awaitable]` to ["must
implement
`__await__`"](https://docs.python.org/3/library/collections.abc.html#collections.abc.Awaitable),
which is insufficient on its own.
## Test Plan
The following code was tested:
```python
import asyncio
import typing
class Awaitable:
def __await__(self) -> typing.Generator[typing.Any, None, int]:
yield None
return 5
class NoDunderMethod:
pass
class InvalidAwaitArgs:
def __await__(self, value: int) -> int:
return value
class InvalidAwaitReturn:
def __await__(self) -> int:
return 5
class InvalidAwaitReturnImplicit:
def __await__(self):
pass
async def main() -> None:
result = await Awaitable() # valid
result = await NoDunderMethod() # `__await__` is missing
result = await InvalidAwaitReturn() # `__await__` returns `int`, which is not a valid iterator
result = await InvalidAwaitArgs() # `__await__` expects additional arguments and cannot be called implicitly
result = await InvalidAwaitReturnImplicit() # `__await__` returns `Unknown`, which is not a valid iterator
asyncio.run(main())
```
---------
Co-authored-by: Carl Meyer
---
crates/ty/docs/rules.md | 154 +++++++++++-------
.../mdtest/diagnostics/invalid_await.md | 105 ++++++++++++
...2\200\246_-_Basic_(f15db7dc447d0795).snap" | 41 +++++
...h_mis\342\200\246_(9ce1ee3cd1c9c8d1).snap" | 41 +++++
...h_pos\342\200\246_(e3444b7a7f960d04).snap" | 47 ++++++
...eturn\342\200\246_(fedf62ffaca0f2d7).snap" | 45 +++++
..._awai\342\200\246_(d78580fb6720e4ea).snap" | 35 ++++
...initi\342\200\246_(15b05c126b6ae968).snap" | 43 +++++
...initi\342\200\246_(ccb69f512135dd61).snap" | 43 +++++
crates/ty_python_semantic/src/types.rs | 143 +++++++++++++---
.../src/types/diagnostic.rs | 31 ++++
.../ty_python_semantic/src/types/function.rs | 1 -
crates/ty_python_semantic/src/types/infer.rs | 6 +-
ty.schema.json | 10 ++
14 files changed, 661 insertions(+), 84 deletions(-)
create mode 100644 crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
create mode 100644 "crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Basic_(f15db7dc447d0795).snap"
create mode 100644 "crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_mis\342\200\246_(9ce1ee3cd1c9c8d1).snap"
create mode 100644 "crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_pos\342\200\246_(e3444b7a7f960d04).snap"
create mode 100644 "crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Invalid_union_return\342\200\246_(fedf62ffaca0f2d7).snap"
create mode 100644 "crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Non-callable_`__awai\342\200\246_(d78580fb6720e4ea).snap"
create mode 100644 "crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(15b05c126b6ae968).snap"
create mode 100644 "crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(ccb69f512135dd61).snap"
diff --git a/crates/ty/docs/rules.md b/crates/ty/docs/rules.md
index 3db6a2b32b1bb..9aadce2eca419 100644
--- a/crates/ty/docs/rules.md
+++ b/crates/ty/docs/rules.md
@@ -36,7 +36,7 @@ def test(): -> "int":
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L101)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L102)
**What it does**
@@ -58,7 +58,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L145)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L146)
**What it does**
@@ -88,7 +88,7 @@ f(int) # error
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L171)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L172)
**What it does**
@@ -117,7 +117,7 @@ a = 1
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L196)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L197)
**What it does**
@@ -147,7 +147,7 @@ class C(A, B): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L222)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L223)
**What it does**
@@ -177,7 +177,7 @@ class B(A): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L287)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L288)
**What it does**
@@ -202,7 +202,7 @@ class B(A, A): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only) ·
-[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L308)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L309)
**What it does**
@@ -306,7 +306,7 @@ def test(): -> "Literal[5]":
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L450)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L451)
**What it does**
@@ -334,7 +334,7 @@ class C(A, B): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L474)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L475)
**What it does**
@@ -358,7 +358,7 @@ t[3] # IndexError: tuple index out of range
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict) ·
-[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L340)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L341)
**What it does**
@@ -445,7 +445,7 @@ an atypical memory layout.
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L519)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L520)
**What it does**
@@ -470,7 +470,7 @@ func("foo") # error: [invalid-argument-type]
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L559)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L560)
**What it does**
@@ -496,7 +496,7 @@ a: int = ''
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1563)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1594)
**What it does**
@@ -523,12 +523,46 @@ C().instance_var = 3 # okay
C.instance_var = 3 # error: Cannot assign to instance variable
```
+## `invalid-await`
+
+
+Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
+[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await) ·
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L582)
+
+
+**What it does**
+
+Checks for `await` being used with types that are not [Awaitable].
+
+**Why is this bad?**
+
+Such expressions will lead to `TypeError` being raised at runtime.
+
+**Examples**
+
+```python
+import asyncio
+
+class InvalidAwait:
+ def __await__(self) -> int:
+ return 5
+
+async def main() -> None:
+ await InvalidAwait() # error: [invalid-await]
+ await 42 # error: [invalid-await]
+
+asyncio.run(main())
+```
+
+[Awaitable]: https://docs.python.org/3/library/collections.abc.html#collections.abc.Awaitable
+
## `invalid-base`
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L581)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L612)
**What it does**
@@ -550,7 +584,7 @@ class A(42): ... # error: [invalid-base]
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L632)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L663)
**What it does**
@@ -575,7 +609,7 @@ with 1:
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L653)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L684)
**What it does**
@@ -602,7 +636,7 @@ a: str
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L676)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L707)
**What it does**
@@ -644,7 +678,7 @@ except ZeroDivisionError:
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L712)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L743)
**What it does**
@@ -675,7 +709,7 @@ class C[U](Generic[T]): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key) ·
-[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L494)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L495)
**What it does**
@@ -704,7 +738,7 @@ alice["height"] # KeyError: 'height'
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L738)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L769)
**What it does**
@@ -737,7 +771,7 @@ def f(t: TypeVar("U")): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L787)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L818)
**What it does**
@@ -769,7 +803,7 @@ class B(metaclass=f): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L814)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L845)
**What it does**
@@ -817,7 +851,7 @@ def foo(x: int) -> int: ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L857)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L888)
**What it does**
@@ -841,7 +875,7 @@ def f(a: int = ''): ...
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L422)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L423)
**What it does**
@@ -873,7 +907,7 @@ TypeError: Protocols can only inherit from other protocols, got
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L877)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L908)
Checks for `raise` statements that raise non-exceptions or use invalid
@@ -920,7 +954,7 @@ def g():
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L540)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L541)
**What it does**
@@ -943,7 +977,7 @@ def func() -> int:
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L920)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L951)
**What it does**
@@ -997,7 +1031,7 @@ TODO #14889
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L766)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L797)
**What it does**
@@ -1022,7 +1056,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L959)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L990)
**What it does**
@@ -1050,7 +1084,7 @@ TYPE_CHECKING = ''
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L983)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1014)
**What it does**
@@ -1078,7 +1112,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call) ·
-[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1035)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1066)
**What it does**
@@ -1110,7 +1144,7 @@ f(10) # Error
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition) ·
-[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1007)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1038)
**What it does**
@@ -1142,7 +1176,7 @@ class C:
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1063)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1094)
**What it does**
@@ -1175,7 +1209,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1092)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1123)
**What it does**
@@ -1198,7 +1232,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1111)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1142)
**What it does**
@@ -1225,7 +1259,7 @@ func("string") # error: [no-matching-overload]
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1134)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1165)
**What it does**
@@ -1247,7 +1281,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1152)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1183)
**What it does**
@@ -1271,7 +1305,7 @@ for i in 34: # TypeError: 'int' object is not iterable
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1203)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1234)
**What it does**
@@ -1325,7 +1359,7 @@ def test(): -> "int":
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1539)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1570)
**What it does**
@@ -1353,7 +1387,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1294)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1325)
**What it does**
@@ -1380,7 +1414,7 @@ class B(A): ... # Error raised here
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1339)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1370)
**What it does**
@@ -1405,7 +1439,7 @@ f("foo") # Error raised here
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1317)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1348)
**What it does**
@@ -1431,7 +1465,7 @@ def _(x: int):
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1360)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1391)
**What it does**
@@ -1475,7 +1509,7 @@ class A:
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1417)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1448)
**What it does**
@@ -1500,7 +1534,7 @@ f(x=1, y=2) # Error raised here
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1438)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1469)
**What it does**
@@ -1526,7 +1560,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1460)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1491)
**What it does**
@@ -1549,7 +1583,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1479)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1510)
**What it does**
@@ -1572,7 +1606,7 @@ print(x) # NameError: name 'x' is not defined
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1172)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1203)
**What it does**
@@ -1607,7 +1641,7 @@ b1 < b2 < b1 # exception raised here
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1498)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1529)
**What it does**
@@ -1633,7 +1667,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
Default level: [`error`](../rules.md#rule-levels "This lint has a default level of 'error'.") ·
[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#L1520)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1551)
**What it does**
@@ -1656,7 +1690,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated) ·
-[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L266)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L267)
**What it does**
@@ -1709,7 +1743,7 @@ a = 20 / 0 # type: ignore
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[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#L1224)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1255)
**What it does**
@@ -1735,7 +1769,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[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#L119)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L120)
**What it does**
@@ -1765,7 +1799,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[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#L1246)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1277)
**What it does**
@@ -1795,7 +1829,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[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#L1591)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1622)
**What it does**
@@ -1820,7 +1854,7 @@ cast(int, f()) # Redundant
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[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#L1399)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1430)
**What it does**
@@ -1871,7 +1905,7 @@ a = 20 / 0 # ty: ignore[division-by-zero]
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global) ·
-[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1612)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1643)
**What it does**
@@ -1925,7 +1959,7 @@ def g():
Default level: [`warn`](../rules.md#rule-levels "This lint has a default level of 'warn'.") ·
[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#L599)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L630)
**What it does**
@@ -1962,7 +1996,7 @@ class D(C): ... # error: [unsupported-base]
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
[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#L248)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L249)
**What it does**
@@ -1984,7 +2018,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
Default level: [`ignore`](../rules.md#rule-levels "This lint has a default level of 'ignore'.") ·
[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#L1272)
+[View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1303)
**What it does**
diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
new file mode 100644
index 0000000000000..60d3439366f17
--- /dev/null
+++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
@@ -0,0 +1,105 @@
+# Invalid await diagnostics
+
+
+
+## Basic
+
+This is a test showcasing a primitive case where an object is not awaitable.
+
+```py
+async def main() -> None:
+ await 1 # error: [invalid-await]
+```
+
+## Custom type with missing `__await__`
+
+This diagnostic also points to the class definition if available.
+
+```py
+class MissingAwait:
+ pass
+
+async def main() -> None:
+ await MissingAwait() # error: [invalid-await]
+```
+
+## Custom type with possibly unbound `__await__`
+
+This diagnostic also points to the method definition if available.
+
+```py
+from datetime import datetime
+
+class PossiblyUnbound:
+ if datetime.today().weekday() == 0:
+ def __await__(self):
+ yield
+
+async def main() -> None:
+ await PossiblyUnbound() # error: [invalid-await]
+```
+
+## `__await__` definition with extra arguments
+
+Currently, the signature of `__await__` isn't checked for conformity with the `Awaitable` protocol
+directly. Instead, individual anomalies are reported, such as the following. Here, the diagnostic
+reports that the object is not implicitly awaitable, while also pointing at the function parameters.
+
+```py
+class InvalidAwaitArgs:
+ def __await__(self, value: int):
+ yield value
+
+async def main() -> None:
+ await InvalidAwaitArgs() # error: [invalid-await]
+```
+
+## Non-callable `__await__`
+
+This diagnostic doesn't point to the attribute definition, but complains about it being possibly not
+awaitable.
+
+```py
+class NonCallableAwait:
+ __await__ = 42
+
+async def main() -> None:
+ await NonCallableAwait() # error: [invalid-await]
+```
+
+## `__await__` definition with explicit invalid return type
+
+`__await__` must return a valid iterator. This diagnostic also points to the method definition if
+available.
+
+```py
+class InvalidAwaitReturn:
+ def __await__(self) -> int:
+ return 5
+
+async def main() -> None:
+ await InvalidAwaitReturn() # error: [invalid-await]
+```
+
+## Invalid union return type
+
+When multiple potential definitions of `__await__` exist, all of them must be proper in order for an
+instance to be awaitable. In this specific case, no specific function definition is highlighted.
+
+```py
+import typing
+from datetime import datetime
+
+class UnawaitableUnion:
+ if datetime.today().weekday() == 6:
+
+ def __await__(self) -> typing.Generator[typing.Any, None, None]:
+ yield
+ else:
+
+ def __await__(self) -> int:
+ return 5
+
+async def main() -> None:
+ await UnawaitableUnion() # error: [invalid-await]
+```
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Basic_(f15db7dc447d0795).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Basic_(f15db7dc447d0795).snap"
new file mode 100644
index 0000000000000..c4304a77ee004
--- /dev/null
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Basic_(f15db7dc447d0795).snap"
@@ -0,0 +1,41 @@
+---
+source: crates/ty_test/src/lib.rs
+expression: snapshot
+---
+---
+mdtest name: invalid_await.md - Invalid await diagnostics - Basic
+mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
+---
+
+# Python source files
+
+## mdtest_snippet.py
+
+```
+1 | async def main() -> None:
+2 | await 1 # error: [invalid-await]
+```
+
+# Diagnostics
+
+```
+error[invalid-await]: `Literal[1]` is not awaitable
+ --> src/mdtest_snippet.py:2:11
+ |
+ 1 | async def main() -> None:
+ 2 | await 1 # error: [invalid-await]
+ | ^
+ |
+ ::: stdlib/builtins.pyi:337:7
+ |
+335 | _LiteralInteger = _PositiveInteger | _NegativeInteger | Literal[0] # noqa: Y026 # TODO: Use TypeAlias once mypy bugs are fixed
+336 |
+337 | class int:
+ | --- type defined here
+338 | """int([x]) -> integer
+339 | int(x, base=10) -> integer
+ |
+info: `__await__` is missing
+info: rule `invalid-await` is enabled by default
+
+```
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_mis\342\200\246_(9ce1ee3cd1c9c8d1).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_mis\342\200\246_(9ce1ee3cd1c9c8d1).snap"
new file mode 100644
index 0000000000000..fcf21676b7e7b
--- /dev/null
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_mis\342\200\246_(9ce1ee3cd1c9c8d1).snap"
@@ -0,0 +1,41 @@
+---
+source: crates/ty_test/src/lib.rs
+expression: snapshot
+---
+---
+mdtest name: invalid_await.md - Invalid await diagnostics - Custom type with missing `__await__`
+mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
+---
+
+# Python source files
+
+## mdtest_snippet.py
+
+```
+1 | class MissingAwait:
+2 | pass
+3 |
+4 | async def main() -> None:
+5 | await MissingAwait() # error: [invalid-await]
+```
+
+# Diagnostics
+
+```
+error[invalid-await]: `MissingAwait` is not awaitable
+ --> src/mdtest_snippet.py:5:11
+ |
+4 | async def main() -> None:
+5 | await MissingAwait() # error: [invalid-await]
+ | ^^^^^^^^^^^^^^
+ |
+ ::: src/mdtest_snippet.py:1:7
+ |
+1 | class MissingAwait:
+ | ------------ type defined here
+2 | pass
+ |
+info: `__await__` is missing
+info: rule `invalid-await` is enabled by default
+
+```
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_pos\342\200\246_(e3444b7a7f960d04).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_pos\342\200\246_(e3444b7a7f960d04).snap"
new file mode 100644
index 0000000000000..22233a6acda59
--- /dev/null
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Custom_type_with_pos\342\200\246_(e3444b7a7f960d04).snap"
@@ -0,0 +1,47 @@
+---
+source: crates/ty_test/src/lib.rs
+expression: snapshot
+---
+---
+mdtest name: invalid_await.md - Invalid await diagnostics - Custom type with possibly unbound `__await__`
+mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
+---
+
+# Python source files
+
+## mdtest_snippet.py
+
+```
+1 | from datetime import datetime
+2 |
+3 | class PossiblyUnbound:
+4 | if datetime.today().weekday() == 0:
+5 | def __await__(self):
+6 | yield
+7 |
+8 | async def main() -> None:
+9 | await PossiblyUnbound() # error: [invalid-await]
+```
+
+# Diagnostics
+
+```
+error[invalid-await]: `PossiblyUnbound` is not awaitable
+ --> src/mdtest_snippet.py:9:11
+ |
+8 | async def main() -> None:
+9 | await PossiblyUnbound() # error: [invalid-await]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ ::: src/mdtest_snippet.py:5:13
+ |
+3 | class PossiblyUnbound:
+4 | if datetime.today().weekday() == 0:
+5 | def __await__(self):
+ | --------------- method defined here
+6 | yield
+ |
+info: `__await__` is possibly unbound
+info: rule `invalid-await` is enabled by default
+
+```
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Invalid_union_return\342\200\246_(fedf62ffaca0f2d7).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Invalid_union_return\342\200\246_(fedf62ffaca0f2d7).snap"
new file mode 100644
index 0000000000000..302b21afc7e6d
--- /dev/null
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Invalid_union_return\342\200\246_(fedf62ffaca0f2d7).snap"
@@ -0,0 +1,45 @@
+---
+source: crates/ty_test/src/lib.rs
+expression: snapshot
+---
+---
+mdtest name: invalid_await.md - Invalid await diagnostics - Invalid union return type
+mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
+---
+
+# Python source files
+
+## mdtest_snippet.py
+
+```
+ 1 | import typing
+ 2 | from datetime import datetime
+ 3 |
+ 4 | class UnawaitableUnion:
+ 5 | if datetime.today().weekday() == 6:
+ 6 |
+ 7 | def __await__(self) -> typing.Generator[typing.Any, None, None]:
+ 8 | yield
+ 9 | else:
+10 |
+11 | def __await__(self) -> int:
+12 | return 5
+13 |
+14 | async def main() -> None:
+15 | await UnawaitableUnion() # error: [invalid-await]
+```
+
+# Diagnostics
+
+```
+error[invalid-await]: `UnawaitableUnion` is not awaitable
+ --> src/mdtest_snippet.py:15:11
+ |
+14 | async def main() -> None:
+15 | await UnawaitableUnion() # error: [invalid-await]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+info: `__await__` returns `Generator[Any, None, None] | int`, which is not a valid iterator
+info: rule `invalid-await` is enabled by default
+
+```
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Non-callable_`__awai\342\200\246_(d78580fb6720e4ea).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Non-callable_`__awai\342\200\246_(d78580fb6720e4ea).snap"
new file mode 100644
index 0000000000000..890ea11b49759
--- /dev/null
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_Non-callable_`__awai\342\200\246_(d78580fb6720e4ea).snap"
@@ -0,0 +1,35 @@
+---
+source: crates/ty_test/src/lib.rs
+expression: snapshot
+---
+---
+mdtest name: invalid_await.md - Invalid await diagnostics - Non-callable `__await__`
+mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
+---
+
+# Python source files
+
+## mdtest_snippet.py
+
+```
+1 | class NonCallableAwait:
+2 | __await__ = 42
+3 |
+4 | async def main() -> None:
+5 | await NonCallableAwait() # error: [invalid-await]
+```
+
+# Diagnostics
+
+```
+error[invalid-await]: `NonCallableAwait` is not awaitable
+ --> src/mdtest_snippet.py:5:11
+ |
+4 | async def main() -> None:
+5 | await NonCallableAwait() # error: [invalid-await]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+info: `__await__` is possibly not callable
+info: rule `invalid-await` is enabled by default
+
+```
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(15b05c126b6ae968).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(15b05c126b6ae968).snap"
new file mode 100644
index 0000000000000..c5fe4db415df7
--- /dev/null
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(15b05c126b6ae968).snap"
@@ -0,0 +1,43 @@
+---
+source: crates/ty_test/src/lib.rs
+expression: snapshot
+---
+---
+mdtest name: invalid_await.md - Invalid await diagnostics - `__await__` definition with extra arguments
+mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
+---
+
+# Python source files
+
+## mdtest_snippet.py
+
+```
+1 | class InvalidAwaitArgs:
+2 | def __await__(self, value: int):
+3 | yield value
+4 |
+5 | async def main() -> None:
+6 | await InvalidAwaitArgs() # error: [invalid-await]
+```
+
+# Diagnostics
+
+```
+error[invalid-await]: `InvalidAwaitArgs` is not awaitable
+ --> src/mdtest_snippet.py:6:11
+ |
+5 | async def main() -> None:
+6 | await InvalidAwaitArgs() # error: [invalid-await]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ ::: src/mdtest_snippet.py:2:18
+ |
+1 | class InvalidAwaitArgs:
+2 | def __await__(self, value: int):
+ | ------------------ parameters here
+3 | yield value
+ |
+info: `__await__` requires arguments and cannot be called implicitly
+info: rule `invalid-await` is enabled by default
+
+```
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(ccb69f512135dd61).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(ccb69f512135dd61).snap"
new file mode 100644
index 0000000000000..b7fa723787875
--- /dev/null
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid_await.md_-_Invalid_await_diagno\342\200\246_-_`__await__`_definiti\342\200\246_(ccb69f512135dd61).snap"
@@ -0,0 +1,43 @@
+---
+source: crates/ty_test/src/lib.rs
+expression: snapshot
+---
+---
+mdtest name: invalid_await.md - Invalid await diagnostics - `__await__` definition with explicit invalid return type
+mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
+---
+
+# Python source files
+
+## mdtest_snippet.py
+
+```
+1 | class InvalidAwaitReturn:
+2 | def __await__(self) -> int:
+3 | return 5
+4 |
+5 | async def main() -> None:
+6 | await InvalidAwaitReturn() # error: [invalid-await]
+```
+
+# Diagnostics
+
+```
+error[invalid-await]: `InvalidAwaitReturn` is not awaitable
+ --> src/mdtest_snippet.py:6:11
+ |
+5 | async def main() -> None:
+6 | await InvalidAwaitReturn() # error: [invalid-await]
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ ::: src/mdtest_snippet.py:2:9
+ |
+1 | class InvalidAwaitReturn:
+2 | def __await__(self) -> int:
+ | ---------------------- method defined here
+3 | return 5
+ |
+info: `__await__` returns `int`, which is not a valid iterator
+info: rule `invalid-await` is enabled by default
+
+```
diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs
index 2ae65d7f90557..89b66a6b343a3 100644
--- a/crates/ty_python_semantic/src/types.rs
+++ b/crates/ty_python_semantic/src/types.rs
@@ -41,7 +41,7 @@ use crate::types::call::{Binding, Bindings, CallArguments, CallableBinding};
use crate::types::class::{CodeGeneratorKind, Field};
pub(crate) use crate::types::class_base::ClassBase;
use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
-use crate::types::diagnostic::{INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
+use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
use crate::types::enums::{enum_metadata, is_single_member_enum};
use crate::types::function::{
DataclassTransformerParams, FunctionSpans, FunctionType, KnownFunction,
@@ -4778,20 +4778,24 @@ impl<'db> Type<'db> {
mode: EvaluationMode,
) -> Result>, IterationError<'db>> {
if mode.is_async() {
- let try_call_dunder_anext_on_iterator = |iterator: Type<'db>| {
+ let try_call_dunder_anext_on_iterator = |iterator: Type<'db>| -> Result<
+ Result, AwaitError<'db>>,
+ CallDunderError<'db>,
+ > {
iterator
.try_call_dunder(db, "__anext__", CallArguments::none())
- .map(|dunder_anext_outcome| {
- dunder_anext_outcome.return_type(db).resolve_await(db)
- })
+ .map(|dunder_anext_outcome| dunder_anext_outcome.return_type(db).try_await(db))
};
return match self.try_call_dunder(db, "__aiter__", CallArguments::none()) {
Ok(dunder_aiter_bindings) => {
let iterator = dunder_aiter_bindings.return_type(db);
match try_call_dunder_anext_on_iterator(iterator) {
- Ok(result) => Ok(Cow::Owned(TupleSpec::homogeneous(result))),
- Err(dunder_anext_error) => {
+ Ok(Ok(result)) => Ok(Cow::Owned(TupleSpec::homogeneous(result))),
+ Ok(Err(AwaitError::InvalidReturnType(..))) => {
+ Err(IterationError::UnboundAiterError)
+ } // TODO: __anext__ is bound, but is not properly awaitable
+ Err(dunder_anext_error) | Ok(Err(AwaitError::Call(dunder_anext_error))) => {
Err(IterationError::IterReturnsInvalidIterator {
iterator,
dunder_error: dunder_anext_error,
@@ -4996,7 +5000,7 @@ impl<'db> Type<'db> {
(Ok(enter), Ok(_)) => {
let ty = enter.return_type(db);
Ok(if mode.is_async() {
- ty.resolve_await(db)
+ ty.try_await(db).unwrap_or(Type::unknown())
} else {
ty
})
@@ -5005,7 +5009,7 @@ impl<'db> Type<'db> {
let ty = enter.return_type(db);
Err(ContextManagerError::Exit {
enter_return_type: if mode.is_async() {
- ty.resolve_await(db)
+ ty.try_await(db).unwrap_or(Type::unknown())
} else {
ty
},
@@ -5024,15 +5028,17 @@ impl<'db> Type<'db> {
}
/// Resolve the type of an `await …` expression where `self` is the type of the awaitable.
- fn resolve_await(self, db: &'db dyn Db) -> Type<'db> {
- // TODO: Add proper error handling and rename this method to `try_await`.
- self.try_call_dunder(db, "__await__", CallArguments::none())
- .map_or(Type::unknown(), |result| {
- result
- .return_type(db)
- .generator_return_type(db)
- .unwrap_or_else(Type::unknown)
- })
+ fn try_await(self, db: &'db dyn Db) -> Result, AwaitError<'db>> {
+ let await_result = self.try_call_dunder(db, "__await__", CallArguments::none());
+ match await_result {
+ Ok(bindings) => {
+ let return_type = bindings.return_type(db);
+ Ok(return_type.generator_return_type(db).ok_or_else(|| {
+ AwaitError::InvalidReturnType(return_type, Box::new(bindings))
+ })?)
+ }
+ Err(call_error) => Err(AwaitError::Call(call_error)),
+ }
}
/// Get the return type of a `yield from …` expression where `self` is the type of the generator.
@@ -5068,6 +5074,8 @@ impl<'db> Type<'db> {
None
}
}
+ Type::Union(union) => union.try_map(db, |ty| ty.generator_return_type(db)),
+ ty @ (Type::Dynamic(_) | Type::Never) => Some(ty),
_ => None,
}
}
@@ -7224,6 +7232,97 @@ impl<'db> TypeVarBoundOrConstraints<'db> {
}
}
+/// Error returned if a type is not awaitable.
+#[derive(Debug)]
+enum AwaitError<'db> {
+ /// `__await__` is either missing, potentially unbound or cannot be called with provided
+ /// arguments.
+ Call(CallDunderError<'db>),
+ /// `__await__` resolved successfully, but its return type is known not to be a generator.
+ InvalidReturnType(Type<'db>, Box>),
+}
+
+impl<'db> AwaitError<'db> {
+ fn report_diagnostic(
+ &self,
+ context: &InferContext<'db, '_>,
+ context_expression_type: Type<'db>,
+ context_expression_node: ast::AnyNodeRef,
+ ) {
+ let Some(builder) = context.report_lint(&INVALID_AWAIT, context_expression_node) else {
+ return;
+ };
+
+ let db = context.db();
+
+ let mut diag = builder.into_diagnostic(
+ format_args!("`{type}` is not awaitable", type = context_expression_type.display(db)),
+ );
+ match self {
+ Self::Call(CallDunderError::CallError(CallErrorKind::BindingError, bindings)) => {
+ diag.info("`__await__` requires arguments and cannot be called implicitly");
+ if let Some(definition_spans) = bindings.callable_type().function_spans(db) {
+ diag.annotate(
+ Annotation::secondary(definition_spans.parameters)
+ .message("parameters here"),
+ );
+ }
+ }
+ Self::Call(CallDunderError::CallError(
+ kind @ (CallErrorKind::NotCallable | CallErrorKind::PossiblyNotCallable),
+ bindings,
+ )) => {
+ let possibly = if matches!(kind, CallErrorKind::PossiblyNotCallable) {
+ " possibly"
+ } else {
+ ""
+ };
+ diag.info(format_args!("`__await__` is{possibly} not callable"));
+ if let Some(definition) = bindings.callable_type().definition(db) {
+ if let Some(definition_range) = definition.focus_range(db) {
+ diag.annotate(
+ Annotation::secondary(definition_range.into())
+ .message("attribute defined here"),
+ );
+ }
+ }
+ }
+ Self::Call(CallDunderError::PossiblyUnbound(bindings)) => {
+ diag.info("`__await__` is possibly unbound");
+ if let Some(definition_spans) = bindings.callable_type().function_spans(db) {
+ diag.annotate(
+ Annotation::secondary(definition_spans.signature)
+ .message("method defined here"),
+ );
+ }
+ }
+ Self::Call(CallDunderError::MethodNotAvailable) => {
+ diag.info("`__await__` is missing");
+ if let Some(type_definition) = context_expression_type.definition(db) {
+ if let Some(definition_range) = type_definition.focus_range(db) {
+ diag.annotate(
+ Annotation::secondary(definition_range.into())
+ .message("type defined here"),
+ );
+ }
+ }
+ }
+ Self::InvalidReturnType(return_type, bindings) => {
+ diag.info(format_args!(
+ "`__await__` returns `{return_type}`, which is not a valid iterator",
+ return_type = return_type.display(db)
+ ));
+ if let Some(definition_spans) = bindings.callable_type().function_spans(db) {
+ diag.annotate(
+ Annotation::secondary(definition_spans.signature)
+ .message("method defined here"),
+ );
+ }
+ }
+ }
+ }
+}
+
/// Error returned if a type is not (or may not be) a context manager.
#[derive(Debug)]
enum ContextManagerError<'db> {
@@ -7447,11 +7546,11 @@ impl<'db> IterationError<'db> {
match self {
Self::IterReturnsInvalidIterator {
dunder_error, mode, ..
- } => dunder_error.return_type(db).map(|ty| {
+ } => dunder_error.return_type(db).and_then(|ty| {
if mode.is_async() {
- ty.resolve_await(db)
+ ty.try_await(db).ok()
} else {
- ty
+ Some(ty)
}
}),
@@ -7466,7 +7565,7 @@ impl<'db> IterationError<'db> {
"__anext__",
CallArguments::none(),
))
- .map(|ty| ty.resolve_await(db))
+ .and_then(|ty| ty.try_await(db).ok())
} else {
return_type(dunder_iter_bindings.return_type(db).try_call_dunder(
db,
diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs
index 6339383005bf3..113d0fa508a7b 100644
--- a/crates/ty_python_semantic/src/types/diagnostic.rs
+++ b/crates/ty_python_semantic/src/types/diagnostic.rs
@@ -45,6 +45,7 @@ pub(crate) fn register_lints(registry: &mut LintRegistryBuilder) {
registry.register_lint(&INVALID_ARGUMENT_TYPE);
registry.register_lint(&INVALID_RETURN_TYPE);
registry.register_lint(&INVALID_ASSIGNMENT);
+ registry.register_lint(&INVALID_AWAIT);
registry.register_lint(&INVALID_BASE);
registry.register_lint(&INVALID_CONTEXT_MANAGER);
registry.register_lint(&INVALID_DECLARATION);
@@ -578,6 +579,36 @@ declare_lint! {
}
}
+declare_lint! {
+ /// ## What it does
+ /// Checks for `await` being used with types that are not [Awaitable].
+ ///
+ /// ## Why is this bad?
+ /// Such expressions will lead to `TypeError` being raised at runtime.
+ ///
+ /// ## Examples
+ /// ```python
+ /// import asyncio
+ ///
+ /// class InvalidAwait:
+ /// def __await__(self) -> int:
+ /// return 5
+ ///
+ /// async def main() -> None:
+ /// await InvalidAwait() # error: [invalid-await]
+ /// await 42 # error: [invalid-await]
+ ///
+ /// asyncio.run(main())
+ /// ```
+ ///
+ /// [Awaitable]: https://docs.python.org/3/library/collections.abc.html#collections.abc.Awaitable
+ pub(crate) static INVALID_AWAIT = {
+ summary: "detects awaiting on types that don't support it",
+ status: LintStatus::preview("1.0.0"),
+ default_level: Level::Error,
+ }
+}
+
declare_lint! {
/// ## What it does
/// Checks for class definitions that have bases which are not instances of `type`.
diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs
index 8a38ea0a84f67..632425f16c3be 100644
--- a/crates/ty_python_semantic/src/types/function.rs
+++ b/crates/ty_python_semantic/src/types/function.rs
@@ -94,7 +94,6 @@ pub(crate) struct FunctionSpans {
pub(crate) name: Span,
/// The span of the parameter list, including the opening and
/// closing parentheses.
- #[expect(dead_code)]
pub(crate) parameters: Span,
/// The span of the annotated return type, if present.
pub(crate) return_type: Option,
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index 8bba369c3b819..3f8ade1195f34 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -6380,7 +6380,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
node_index: _,
value,
} = await_expression;
- self.infer_expression(value).resolve_await(self.db())
+ let expr_type = self.infer_expression(value);
+ expr_type.try_await(self.db()).unwrap_or_else(|err| {
+ err.report_diagnostic(&self.context, expr_type, value.as_ref().into());
+ Type::unknown()
+ })
}
// Perform narrowing with applicable constraints between the current scope and the enclosing scope.
diff --git a/ty.schema.json b/ty.schema.json
index bcec1c768522d..d94057ef9e1b3 100644
--- a/ty.schema.json
+++ b/ty.schema.json
@@ -461,6 +461,16 @@
}
]
},
+ "invalid-await": {
+ "title": "detects awaiting on types that don't support it",
+ "description": "## What it does\nChecks for `await` being used with types that are not [Awaitable].\n\n## Why is this bad?\nSuch expressions will lead to `TypeError` being raised at runtime.\n\n## Examples\n```python\nimport asyncio\n\nclass InvalidAwait:\n def __await__(self) -> int:\n return 5\n\nasync def main() -> None:\n await InvalidAwait() # error: [invalid-await]\n await 42 # error: [invalid-await]\n\nasyncio.run(main())\n```\n\n[Awaitable]: https://docs.python.org/3/library/collections.abc.html#collections.abc.Awaitable",
+ "default": "error",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Level"
+ }
+ ]
+ },
"invalid-base": {
"title": "detects class bases that will cause the class definition to raise an exception at runtime",
"description": "## What it does\nChecks for class definitions that have bases which are not instances of `type`.\n\n## Why is this bad?\nClass definitions with bases like this will lead to `TypeError` being raised at runtime.\n\n## Examples\n```python\nclass A(42): ... # error: [invalid-base]\n```",
From 0e5577ab562303f4767d8be4d310d698e01a2329 Mon Sep 17 00:00:00 2001
From: Shunsuke Shibayama <45118249+mtshiba@users.noreply.github.com>
Date: Fri, 15 Aug 2025 09:52:52 +0900
Subject: [PATCH 006/160] [ty] fix lazy snapshot sweeping in nested scopes
(#19908)
## Summary
This PR closes astral-sh/ty#955.
## Test Plan
New test cases in `narrowing/conditionals/nested.md`.
---
.../mdtest/narrow/conditionals/nested.md | 21 +++++++++++++
.../ty_python_semantic/src/semantic_index.rs | 30 +++++++++----------
.../src/semantic_index/builder.rs | 28 ++++++++++++-----
3 files changed, 56 insertions(+), 23 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md b/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md
index ea674c8df3ffb..4ab60f5e2c163 100644
--- a/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md
+++ b/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md
@@ -240,6 +240,21 @@ def f(x: str | None):
# When there is a reassignment, any narrowing constraints on the place are invalidated in lazy scopes.
x = None
+
+def f(x: str | None):
+ def _():
+ if x is not None:
+ def closure():
+ reveal_type(x) # revealed: str | None
+ x = None
+
+def f(x: str | None):
+ class C:
+ def _():
+ if x is not None:
+ def closure():
+ reveal_type(x) # revealed: str
+ x = None # This assignment is not visible in the inner lazy scope, so narrowing is still valid.
```
If a variable defined in a private scope is never reassigned, narrowing remains in effect in the
@@ -256,6 +271,12 @@ def f(const: str | None):
reveal_type(const) # revealed: str
[reveal_type(const) for _ in range(1)] # revealed: str
+
+def f(const: str | None):
+ def _():
+ if const is not None:
+ def closure():
+ reveal_type(const) # revealed: str
```
And even if there is an attribute or subscript assignment to the variable, narrowing of the variable
diff --git a/crates/ty_python_semantic/src/semantic_index.rs b/crates/ty_python_semantic/src/semantic_index.rs
index c195059b38d18..71ab64f736a5a 100644
--- a/crates/ty_python_semantic/src/semantic_index.rs
+++ b/crates/ty_python_semantic/src/semantic_index.rs
@@ -165,7 +165,7 @@ pub(crate) fn attribute_scopes<'db, 's>(
let index = semantic_index(db, file);
let class_scope_id = class_body_scope.file_scope_id(db);
- ChildrenIter::new(index, class_scope_id).filter_map(move |(child_scope_id, scope)| {
+ ChildrenIter::new(&index.scopes, class_scope_id).filter_map(move |(child_scope_id, scope)| {
let (function_scope_id, function_scope) =
if scope.node().scope_kind() == ScopeKind::TypeParams {
// This could be a generic method with a type-params scope.
@@ -372,18 +372,18 @@ impl<'db> SemanticIndex<'db> {
/// Returns an iterator over the descendent scopes of `scope`.
#[allow(unused)]
pub(crate) fn descendent_scopes(&self, scope: FileScopeId) -> DescendantsIter<'_> {
- DescendantsIter::new(self, scope)
+ DescendantsIter::new(&self.scopes, scope)
}
/// Returns an iterator over the direct child scopes of `scope`.
#[allow(unused)]
pub(crate) fn child_scopes(&self, scope: FileScopeId) -> ChildrenIter<'_> {
- ChildrenIter::new(self, scope)
+ ChildrenIter::new(&self.scopes, scope)
}
/// Returns an iterator over all ancestors of `scope`, starting with `scope` itself.
pub(crate) fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter<'_> {
- AncestorsIter::new(self, scope)
+ AncestorsIter::new(&self.scopes, scope)
}
/// Returns an iterator over ancestors of `scope` that are visible for name resolution,
@@ -401,7 +401,7 @@ impl<'db> SemanticIndex<'db> {
/// ```
/// The `method` function can see the global scope but not the class scope.
pub(crate) fn visible_ancestor_scopes(&self, scope: FileScopeId) -> VisibleAncestorsIter<'_> {
- VisibleAncestorsIter::new(self, scope)
+ VisibleAncestorsIter::new(&self.scopes, scope)
}
/// Returns the [`definition::Definition`] salsa ingredient(s) for `definition_key`.
@@ -542,9 +542,9 @@ pub(crate) struct AncestorsIter<'a> {
}
impl<'a> AncestorsIter<'a> {
- fn new(module_table: &'a SemanticIndex, start: FileScopeId) -> Self {
+ fn new(scopes: &'a IndexSlice, start: FileScopeId) -> Self {
Self {
- scopes: &module_table.scopes,
+ scopes,
next_id: Some(start),
}
}
@@ -571,10 +571,10 @@ pub(crate) struct VisibleAncestorsIter<'a> {
}
impl<'a> VisibleAncestorsIter<'a> {
- fn new(module_table: &'a SemanticIndex, start: FileScopeId) -> Self {
- let starting_scope = &module_table.scopes[start];
+ fn new(scopes: &'a IndexSlice, start: FileScopeId) -> Self {
+ let starting_scope = &scopes[start];
Self {
- inner: AncestorsIter::new(module_table, start),
+ inner: AncestorsIter::new(scopes, start),
starting_scope_kind: starting_scope.kind(),
yielded_count: 0,
}
@@ -617,9 +617,9 @@ pub(crate) struct DescendantsIter<'a> {
}
impl<'a> DescendantsIter<'a> {
- fn new(index: &'a SemanticIndex, scope_id: FileScopeId) -> Self {
- let scope = &index.scopes[scope_id];
- let scopes = &index.scopes[scope.descendants()];
+ fn new(scopes: &'a IndexSlice, scope_id: FileScopeId) -> Self {
+ let scope = &scopes[scope_id];
+ let scopes = &scopes[scope.descendants()];
Self {
next_id: scope_id + 1,
@@ -654,8 +654,8 @@ pub(crate) struct ChildrenIter<'a> {
}
impl<'a> ChildrenIter<'a> {
- pub(crate) fn new(module_index: &'a SemanticIndex, parent: FileScopeId) -> Self {
- let descendants = DescendantsIter::new(module_index, parent);
+ pub(crate) fn new(scopes: &'a IndexSlice, parent: FileScopeId) -> Self {
+ let descendants = DescendantsIter::new(scopes, parent);
Self {
parent,
diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs
index 1a9b6b01a91b6..943715fd11bc0 100644
--- a/crates/ty_python_semantic/src/semantic_index/builder.rs
+++ b/crates/ty_python_semantic/src/semantic_index/builder.rs
@@ -47,7 +47,7 @@ use crate::semantic_index::symbol::{ScopedSymbolId, Symbol};
use crate::semantic_index::use_def::{
EnclosingSnapshotKey, FlowSnapshot, ScopedEnclosingSnapshotId, UseDefMapBuilder,
};
-use crate::semantic_index::{ExpressionsScopeMap, SemanticIndex};
+use crate::semantic_index::{ExpressionsScopeMap, SemanticIndex, VisibleAncestorsIter};
use crate::semantic_model::HasTrackedScope;
use crate::unpack::{EvaluationMode, Unpack, UnpackKind, UnpackPosition, UnpackValue};
use crate::{Db, Program};
@@ -400,16 +400,28 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
}
}
- /// Any lazy snapshots of places that have been reassigned or modified are no longer valid, so delete them.
+ /// Any lazy snapshots of places that have been reassigned are no longer valid, so delete them.
fn sweep_lazy_snapshots(&mut self, popped_scope_id: FileScopeId) {
+ // Retain only snapshots that are either eager
+ // || (enclosing_scope != popped_scope && popped_scope is not a visible ancestor of enclosing_scope)
+ // || enclosing_place is not a symbol or not reassigned
+ // <=> remove those that are lazy
+ // && (enclosing_scope == popped_scope || popped_scope is a visible ancestor of enclosing_scope)
+ // && enclosing_place is a symbol and reassigned
self.enclosing_snapshots.retain(|key, _| {
- let place_table = &self.place_tables[key.enclosing_scope];
+ let popped_place_table = &self.place_tables[popped_scope_id];
key.nested_laziness.is_eager()
- || key.enclosing_scope != popped_scope_id
- || !key
- .enclosing_place
- .as_symbol()
- .is_some_and(|symbol_id| place_table.symbol(symbol_id).is_reassigned())
+ || (key.enclosing_scope != popped_scope_id
+ && VisibleAncestorsIter::new(&self.scopes, key.enclosing_scope)
+ .all(|(ancestor, _)| ancestor != popped_scope_id))
+ || !key.enclosing_place.as_symbol().is_some_and(|symbol_id| {
+ let name = &self.place_tables[key.enclosing_scope]
+ .symbol(symbol_id)
+ .name();
+ popped_place_table.symbol_id(name).is_some_and(|symbol_id| {
+ popped_place_table.symbol(symbol_id).is_reassigned()
+ })
+ })
});
}
From bd4506aac56228af83d8ad76569530b3b32be473 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 14 Aug 2025 18:09:35 -0700
Subject: [PATCH 007/160] [ty] Sync vendored typeshed stubs (#19923)
Close and reopen this PR to trigger CI
---------
Co-authored-by: typeshedbot <>
Co-authored-by: Carl Meyer
---
crates/ty_ide/src/goto_type_definition.rs | 112 +-
.../resources/mdtest/call/methods.md | 2 +-
.../vendor/typeshed/source_commit.txt | 2 +-
.../vendor/typeshed/stdlib/_compression.pyi | 3 +-
.../vendor/typeshed/stdlib/_contextvars.pyi | 2 +-
.../vendor/typeshed/stdlib/_ctypes.pyi | 3 +
.../typeshed/stdlib/_frozen_importlib.pyi | 11 +
.../stdlib/_frozen_importlib_external.pyi | 17 +-
.../vendor/typeshed/stdlib/_gdbm.pyi | 3 +-
.../typeshed/stdlib/_interpchannels.pyi | 12 +-
.../vendor/typeshed/stdlib/_interpreters.pyi | 4 +-
.../vendor/typeshed/stdlib/_io.pyi | 1 +
.../vendor/typeshed/stdlib/_msi.pyi | 5 +
.../vendor/typeshed/stdlib/_operator.pyi | 1 +
.../vendor/typeshed/stdlib/_pickle.pyi | 1 +
.../vendor/typeshed/stdlib/_socket.pyi | 1053 ++++++++---------
.../vendor/typeshed/stdlib/_ssl.pyi | 214 ++--
.../vendor/typeshed/stdlib/_tkinter.pyi | 3 +-
.../vendor/typeshed/stdlib/_winapi.pyi | 3 +
.../vendor/typeshed/stdlib/_zstd.pyi | 10 +-
.../vendor/typeshed/stdlib/array.pyi | 31 +-
.../vendor/typeshed/stdlib/ast.pyi | 19 +-
.../typeshed/stdlib/asyncio/coroutines.pyi | 3 +-
.../vendor/typeshed/stdlib/asyncio/events.pyi | 6 +-
.../stdlib/asyncio/format_helpers.pyi | 3 +-
.../typeshed/stdlib/asyncio/streams.pyi | 3 +-
.../vendor/typeshed/stdlib/asyncio/tasks.pyi | 5 +-
.../vendor/typeshed/stdlib/asyncio/trsock.pyi | 31 +-
.../vendor/typeshed/stdlib/bdb.pyi | 4 +-
.../vendor/typeshed/stdlib/binascii.pyi | 6 +-
.../vendor/typeshed/stdlib/builtins.pyi | 22 +
.../vendor/typeshed/stdlib/bz2.pyi | 4 +-
.../vendor/typeshed/stdlib/codecs.pyi | 12 +-
.../typeshed/stdlib/collections/__init__.pyi | 5 +-
.../stdlib/concurrent/futures/_base.pyi | 3 +-
.../stdlib/concurrent/futures/interpreter.pyi | 59 +-
.../vendor/typeshed/stdlib/configparser.pyi | 29 +-
.../vendor/typeshed/stdlib/dataclasses.pyi | 1 +
.../vendor/typeshed/stdlib/dbm/__init__.pyi | 1 +
.../typeshed/stdlib/email/headerregistry.pyi | 3 +-
.../vendor/typeshed/stdlib/email/message.pyi | 4 +-
.../typeshed/stdlib/encodings/__init__.pyi | 4 +
.../vendor/typeshed/stdlib/fcntl.pyi | 172 +--
.../vendor/typeshed/stdlib/functools.pyi | 6 +-
.../vendor/typeshed/stdlib/gettext.pyi | 19 +-
.../vendor/typeshed/stdlib/glob.pyi | 12 +-
.../vendor/typeshed/stdlib/gzip.pyi | 3 +-
.../vendor/typeshed/stdlib/hashlib.pyi | 4 +-
.../vendor/typeshed/stdlib/html/parser.pyi | 6 +-
.../vendor/typeshed/stdlib/imp.pyi | 3 +-
.../typeshed/stdlib/importlib/__init__.pyi | 2 +
.../vendor/typeshed/stdlib/importlib/_abc.pyi | 5 +
.../vendor/typeshed/stdlib/importlib/abc.pyi | 9 +-
.../stdlib/importlib/metadata/__init__.pyi | 5 +-
.../vendor/typeshed/stdlib/importlib/util.pyi | 14 +-
.../vendor/typeshed/stdlib/inspect.pyi | 7 +-
.../vendor/typeshed/stdlib/locale.pyi | 22 +-
.../typeshed/stdlib/logging/__init__.pyi | 4 +-
.../typeshed/stdlib/logging/handlers.pyi | 3 +-
.../vendor/typeshed/stdlib/mailbox.pyi | 5 +-
.../typeshed/stdlib/multiprocessing/heap.pyi | 3 +-
.../stdlib/multiprocessing/sharedctypes.pyi | 4 +-
.../ty_vendored/vendor/typeshed/stdlib/nt.pyi | 3 +
.../vendor/typeshed/stdlib/numbers.pyi | 16 +-
.../vendor/typeshed/stdlib/os/__init__.pyi | 2 +
.../typeshed/stdlib/pathlib/__init__.pyi | 37 +-
.../vendor/typeshed/stdlib/pkgutil.pyi | 53 +-
.../vendor/typeshed/stdlib/platform.pyi | 45 +-
.../vendor/typeshed/stdlib/pty.pyi | 42 +-
.../vendor/typeshed/stdlib/pydoc.pyi | 3 +-
.../vendor/typeshed/stdlib/quopri.pyi | 3 +-
.../ty_vendored/vendor/typeshed/stdlib/re.pyi | 11 +-
.../vendor/typeshed/stdlib/shutil.pyi | 7 +-
.../vendor/typeshed/stdlib/smtpd.pyi | 3 +-
.../vendor/typeshed/stdlib/smtplib.pyi | 3 +-
.../vendor/typeshed/stdlib/socket.pyi | 4 +-
.../typeshed/stdlib/sqlite3/__init__.pyi | 4 +
.../vendor/typeshed/stdlib/ssl.pyi | 161 +--
.../vendor/typeshed/stdlib/sys/__init__.pyi | 13 +
.../vendor/typeshed/stdlib/termios.pyi | 533 ++++-----
.../vendor/typeshed/stdlib/time.pyi | 3 +-
.../typeshed/stdlib/tkinter/__init__.pyi | 6 +
.../vendor/typeshed/stdlib/tkinter/dnd.pyi | 3 +-
.../vendor/typeshed/stdlib/tkinter/font.pyi | 4 +-
.../vendor/typeshed/stdlib/tkinter/ttk.pyi | 6 +-
.../vendor/typeshed/stdlib/tty.pyi | 14 +-
.../vendor/typeshed/stdlib/turtle.pyi | 7 +-
.../vendor/typeshed/stdlib/typing.pyi | 32 +-
.../typeshed/stdlib/typing_extensions.pyi | 6 +-
.../vendor/typeshed/stdlib/unittest/case.pyi | 3 +-
.../vendor/typeshed/stdlib/unittest/main.pyi | 3 +-
.../vendor/typeshed/stdlib/unittest/mock.pyi | 4 +-
.../typeshed/stdlib/unittest/runner.pyi | 4 +-
.../vendor/typeshed/stdlib/urllib/request.pyi | 7 +-
.../vendor/typeshed/stdlib/winreg.pyi | 2 +-
.../typeshed/stdlib/xml/dom/minidom.pyi | 4 +-
.../stdlib/xml/etree/ElementInclude.pyi | 3 +-
.../typeshed/stdlib/xml/etree/ElementTree.pyi | 1 +
.../typeshed/stdlib/xml/sax/__init__.pyi | 3 +-
.../vendor/typeshed/stdlib/xmlrpc/client.pyi | 3 +-
.../vendor/typeshed/stdlib/xmlrpc/server.pyi | 8 +-
.../typeshed/stdlib/zipfile/__init__.pyi | 10 +-
.../vendor/typeshed/stdlib/zipimport.pyi | 98 +-
.../vendor/typeshed/stdlib/zlib.pyi | 12 +-
.../typeshed/stdlib/zoneinfo/_common.pyi | 3 +-
105 files changed, 1832 insertions(+), 1388 deletions(-)
diff --git a/crates/ty_ide/src/goto_type_definition.rs b/crates/ty_ide/src/goto_type_definition.rs
index 1ec3e85db3dbb..4d8f06f354577 100644
--- a/crates/ty_ide/src/goto_type_definition.rs
+++ b/crates/ty_ide/src/goto_type_definition.rs
@@ -197,16 +197,16 @@ mod tests {
"#,
);
- assert_snapshot!(test.goto_type_definition(), @r#"
+ assert_snapshot!(test.goto_type_definition(), @r###"
info[goto-type-definition]: Type definition
- --> stdlib/builtins.pyi:892:7
+ --> stdlib/builtins.pyi:901:7
|
- 890 | def __getitem__(self, key: int, /) -> str | int | None: ...
- 891 |
- 892 | class str(Sequence[str]):
+ 899 | def __getitem__(self, key: int, /) -> str | int | None: ...
+ 900 |
+ 901 | class str(Sequence[str]):
| ^^^
- 893 | """str(object='') -> str
- 894 | str(bytes_or_buffer[, encoding[, errors]]) -> str
+ 902 | """str(object='') -> str
+ 903 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
info: Source
--> main.py:4:13
@@ -216,7 +216,7 @@ mod tests {
4 | a
| ^
|
- "#);
+ "###);
}
#[test]
fn goto_type_of_expression_with_literal_node() {
@@ -226,16 +226,16 @@ mod tests {
"#,
);
- assert_snapshot!(test.goto_type_definition(), @r#"
+ assert_snapshot!(test.goto_type_definition(), @r###"
info[goto-type-definition]: Type definition
- --> stdlib/builtins.pyi:892:7
+ --> stdlib/builtins.pyi:901:7
|
- 890 | def __getitem__(self, key: int, /) -> str | int | None: ...
- 891 |
- 892 | class str(Sequence[str]):
+ 899 | def __getitem__(self, key: int, /) -> str | int | None: ...
+ 900 |
+ 901 | class str(Sequence[str]):
| ^^^
- 893 | """str(object='') -> str
- 894 | str(bytes_or_buffer[, encoding[, errors]]) -> str
+ 902 | """str(object='') -> str
+ 903 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
info: Source
--> main.py:2:22
@@ -243,7 +243,7 @@ mod tests {
2 | a: str = "test"
| ^^^^^^
|
- "#);
+ "###);
}
#[test]
@@ -342,16 +342,16 @@ mod tests {
"#,
);
- assert_snapshot!(test.goto_type_definition(), @r#"
+ assert_snapshot!(test.goto_type_definition(), @r###"
info[goto-type-definition]: Type definition
- --> stdlib/builtins.pyi:892:7
+ --> stdlib/builtins.pyi:901:7
|
- 890 | def __getitem__(self, key: int, /) -> str | int | None: ...
- 891 |
- 892 | class str(Sequence[str]):
+ 899 | def __getitem__(self, key: int, /) -> str | int | None: ...
+ 900 |
+ 901 | class str(Sequence[str]):
| ^^^
- 893 | """str(object='') -> str
- 894 | str(bytes_or_buffer[, encoding[, errors]]) -> str
+ 902 | """str(object='') -> str
+ 903 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
info: Source
--> main.py:4:18
@@ -361,7 +361,7 @@ mod tests {
4 | test(a= "123")
| ^
|
- "#);
+ "###);
}
#[test]
@@ -411,16 +411,16 @@ f(**kwargs)
"#,
);
- assert_snapshot!(test.goto_type_definition(), @r#"
+ assert_snapshot!(test.goto_type_definition(), @r###"
info[goto-type-definition]: Type definition
- --> stdlib/builtins.pyi:2890:7
+ --> stdlib/builtins.pyi:2901:7
|
- 2888 | """See PEP 585"""
- 2889 |
- 2890 | class dict(MutableMapping[_KT, _VT]):
+ 2899 | """See PEP 585"""
+ 2900 |
+ 2901 | class dict(MutableMapping[_KT, _VT]):
| ^^^^
- 2891 | """dict() -> new empty dictionary
- 2892 | dict(mapping) -> new dictionary initialized from a mapping object's
+ 2902 | """dict() -> new empty dictionary
+ 2903 | dict(mapping) -> new dictionary initialized from a mapping object's
|
info: Source
--> main.py:6:5
@@ -430,7 +430,7 @@ f(**kwargs)
6 | f(**kwargs)
| ^^^^^^
|
- "#);
+ "###);
}
#[test]
@@ -442,16 +442,16 @@ f(**kwargs)
"#,
);
- assert_snapshot!(test.goto_type_definition(), @r#"
+ assert_snapshot!(test.goto_type_definition(), @r###"
info[goto-type-definition]: Type definition
- --> stdlib/builtins.pyi:892:7
+ --> stdlib/builtins.pyi:901:7
|
- 890 | def __getitem__(self, key: int, /) -> str | int | None: ...
- 891 |
- 892 | class str(Sequence[str]):
+ 899 | def __getitem__(self, key: int, /) -> str | int | None: ...
+ 900 |
+ 901 | class str(Sequence[str]):
| ^^^
- 893 | """str(object='') -> str
- 894 | str(bytes_or_buffer[, encoding[, errors]]) -> str
+ 902 | """str(object='') -> str
+ 903 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
info: Source
--> main.py:3:17
@@ -460,7 +460,7 @@ f(**kwargs)
3 | a
| ^
|
- "#);
+ "###);
}
#[test]
@@ -535,16 +535,16 @@ f(**kwargs)
"#,
);
- assert_snapshot!(test.goto_type_definition(), @r#"
+ assert_snapshot!(test.goto_type_definition(), @r###"
info[goto-type-definition]: Type definition
- --> stdlib/builtins.pyi:892:7
+ --> stdlib/builtins.pyi:901:7
|
- 890 | def __getitem__(self, key: int, /) -> str | int | None: ...
- 891 |
- 892 | class str(Sequence[str]):
+ 899 | def __getitem__(self, key: int, /) -> str | int | None: ...
+ 900 |
+ 901 | class str(Sequence[str]):
| ^^^
- 893 | """str(object='') -> str
- 894 | str(bytes_or_buffer[, encoding[, errors]]) -> str
+ 902 | """str(object='') -> str
+ 903 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
info: Source
--> main.py:4:27
@@ -554,7 +554,7 @@ f(**kwargs)
4 | print(a)
| ^
|
- "#);
+ "###);
}
#[test]
@@ -566,7 +566,7 @@ f(**kwargs)
"#,
);
- assert_snapshot!(test.goto_type_definition(), @r#"
+ assert_snapshot!(test.goto_type_definition(), @r###"
info[goto-type-definition]: Type definition
--> stdlib/types.pyi:922:11
|
@@ -585,14 +585,14 @@ f(**kwargs)
|
info[goto-type-definition]: Type definition
- --> stdlib/builtins.pyi:892:7
+ --> stdlib/builtins.pyi:901:7
|
- 890 | def __getitem__(self, key: int, /) -> str | int | None: ...
- 891 |
- 892 | class str(Sequence[str]):
+ 899 | def __getitem__(self, key: int, /) -> str | int | None: ...
+ 900 |
+ 901 | class str(Sequence[str]):
| ^^^
- 893 | """str(object='') -> str
- 894 | str(bytes_or_buffer[, encoding[, errors]]) -> str
+ 902 | """str(object='') -> str
+ 903 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
info: Source
--> main.py:3:17
@@ -601,7 +601,7 @@ f(**kwargs)
3 | a
| ^
|
- "#);
+ "###);
}
impl CursorTest {
diff --git a/crates/ty_python_semantic/resources/mdtest/call/methods.md b/crates/ty_python_semantic/resources/mdtest/call/methods.md
index 1d6b020832be2..9bac69ea59393 100644
--- a/crates/ty_python_semantic/resources/mdtest/call/methods.md
+++ b/crates/ty_python_semantic/resources/mdtest/call/methods.md
@@ -198,7 +198,7 @@ python-version = "3.12"
```py
type IntOrStr = int | str
-reveal_type(IntOrStr.__or__) # revealed: bound method typing.TypeAliasType.__or__(right: Any) -> _SpecialForm
+reveal_type(IntOrStr.__or__) # revealed: bound method typing.TypeAliasType.__or__(right: Any, /) -> _SpecialForm
```
## Method calls on types not disjoint from `None`
diff --git a/crates/ty_vendored/vendor/typeshed/source_commit.txt b/crates/ty_vendored/vendor/typeshed/source_commit.txt
index 01a13b0ad731f..b09efe98fe9b4 100644
--- a/crates/ty_vendored/vendor/typeshed/source_commit.txt
+++ b/crates/ty_vendored/vendor/typeshed/source_commit.txt
@@ -1 +1 @@
-3f08a4ed10b321c378107c236a06a33584869a9b
+893b9a760deb3be64d13c748318e95a752230961
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_compression.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_compression.pyi
index de5f90fcdefad..12eafa626744d 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_compression.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_compression.pyi
@@ -5,10 +5,11 @@
from _typeshed import Incomplete, WriteableBuffer
from collections.abc import Callable
from io import DEFAULT_BUFFER_SIZE, BufferedIOBase, RawIOBase
-from typing import Any, Protocol
+from typing import Any, Protocol, type_check_only
BUFFER_SIZE = DEFAULT_BUFFER_SIZE
+@type_check_only
class _Reader(Protocol):
def read(self, n: int, /) -> bytes: ...
def seekable(self) -> bool: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_contextvars.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_contextvars.pyi
index 7c00448f38dcd..a46b110a8c128 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_contextvars.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_contextvars.pyi
@@ -68,7 +68,7 @@ class Token(Generic[_T]):
"""Enter into Token context manager."""
def __exit__(
- self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
+ self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None, /
) -> None:
"""Exit from Token context manager, restore the linked ContextVar."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_ctypes.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_ctypes.pyi
index cce031feed544..ba3f209bef962 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_ctypes.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_ctypes.pyi
@@ -131,7 +131,10 @@ class _SimpleCData(_CData, Generic[_T], metaclass=_PyCSimpleType):
def __init__(self, value: _T = ...) -> None: ... # pyright: ignore[reportInvalidTypeVarUse]
def __ctypes_from_outparam__(self, /) -> _T: ... # type: ignore[override]
+@type_check_only
class _CanCastTo(_CData): ...
+
+@type_check_only
class _PointerLike(_CanCastTo): ...
# This type is not exposed. It calls itself _ctypes.PyCPointerType.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib.pyi
index a6f58ca3f8b95..84326d57da611 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib.pyi
@@ -15,6 +15,7 @@ from _typeshed.importlib import LoaderProtocol
from collections.abc import Mapping, Sequence
from types import ModuleType
from typing import Any, ClassVar
+from typing_extensions import deprecated
# Signature of `builtins.__import__` should be kept identical to `importlib.__import__`
def __import__(
@@ -117,6 +118,7 @@ class BuiltinImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader)
# MetaPathFinder
if sys.version_info < (3, 12):
@classmethod
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `find_spec()` instead.")
def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None:
"""Find the built-in module.
@@ -153,6 +155,10 @@ class BuiltinImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader)
# Loader
if sys.version_info < (3, 12):
@staticmethod
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "The module spec is now used by the import machinery to generate a module repr."
+ )
def module_repr(module: types.ModuleType) -> str:
"""Return repr for the module.
@@ -187,6 +193,7 @@ class FrozenImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader):
# MetaPathFinder
if sys.version_info < (3, 12):
@classmethod
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `find_spec()` instead.")
def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None:
"""Find a frozen module.
@@ -221,6 +228,10 @@ class FrozenImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader):
# Loader
if sys.version_info < (3, 12):
@staticmethod
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "The module spec is now used by the import machinery to generate a module repr."
+ )
def module_repr(m: types.ModuleType) -> str:
"""Return repr for the module.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib_external.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib_external.pyi
index 7db0d7a7b0955..8986a981e9ffa 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib_external.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_frozen_importlib_external.pyi
@@ -97,6 +97,7 @@ class WindowsRegistryFinder(importlib.abc.MetaPathFinder):
if sys.version_info < (3, 12):
@classmethod
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `find_spec()` instead.")
def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None:
"""Find module named in the registry.
@@ -157,6 +158,7 @@ class PathFinder(importlib.abc.MetaPathFinder):
"""
if sys.version_info < (3, 12):
@classmethod
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `find_spec()` instead.")
def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None:
"""find the module on sys.path or 'path' based on sys.path_hooks and
sys.path_importer_cache.
@@ -374,7 +376,10 @@ if sys.version_info >= (3, 11):
def get_resource_reader(self, module: types.ModuleType) -> importlib.readers.NamespaceReader: ...
if sys.version_info < (3, 12):
@staticmethod
- @deprecated("module_repr() is deprecated, and has been removed in Python 3.12")
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "The module spec is now used by the import machinery to generate a module repr."
+ )
def module_repr(module: types.ModuleType) -> str:
"""Return repr for the module.
@@ -404,7 +409,10 @@ else:
"""
if sys.version_info >= (3, 10):
@staticmethod
- @deprecated("module_repr() is deprecated, and has been removed in Python 3.12")
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "The module spec is now used by the import machinery to generate a module repr."
+ )
def module_repr(module: types.ModuleType) -> str:
"""Return repr for the module.
@@ -415,7 +423,10 @@ else:
def get_resource_reader(self, module: types.ModuleType) -> importlib.readers.NamespaceReader: ...
else:
@classmethod
- @deprecated("module_repr() is deprecated, and has been removed in Python 3.12")
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "The module spec is now used by the import machinery to generate a module repr."
+ )
def module_repr(cls, module: types.ModuleType) -> str:
"""Return repr for the module.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_gdbm.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_gdbm.pyi
index cb7174535c383..58bd1d41d3588 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_gdbm.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_gdbm.pyi
@@ -13,7 +13,7 @@ values() methods are not supported.
import sys
from _typeshed import ReadOnlyBuffer, StrOrBytesPath
from types import TracebackType
-from typing import TypeVar, overload
+from typing import TypeVar, overload, type_check_only
from typing_extensions import Self, TypeAlias
if sys.platform != "win32":
@@ -25,6 +25,7 @@ if sys.platform != "win32":
class error(OSError): ...
# Actual typename gdbm, not exposed by the implementation
+ @type_check_only
class _gdbm:
def firstkey(self) -> bytes | None: ...
def nextkey(self, key: _KeyType) -> bytes | None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_interpchannels.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_interpchannels.pyi
index 3b4a9abc8a8c8..987ca4566c1a0 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_interpchannels.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_interpchannels.pyi
@@ -29,9 +29,9 @@ class ChannelID:
def recv(self) -> Self:
"""the 'recv' end of the channel"""
- def __eq__(self, other: object) -> bool: ...
- def __ge__(self, other: ChannelID) -> bool: ...
- def __gt__(self, other: ChannelID) -> bool: ...
+ def __eq__(self, other: object, /) -> bool: ...
+ def __ge__(self, other: ChannelID, /) -> bool: ...
+ def __gt__(self, other: ChannelID, /) -> bool: ...
def __hash__(self) -> int: ...
def __index__(self) -> int:
"""Return self converted to an integer, if self is suitable for use as an index into a list."""
@@ -39,9 +39,9 @@ class ChannelID:
def __int__(self) -> int:
"""int(self)"""
- def __le__(self, other: ChannelID) -> bool: ...
- def __lt__(self, other: ChannelID) -> bool: ...
- def __ne__(self, other: object) -> bool: ...
+ def __le__(self, other: ChannelID, /) -> bool: ...
+ def __lt__(self, other: ChannelID, /) -> bool: ...
+ def __ne__(self, other: object, /) -> bool: ...
@final
class ChannelInfo(structseq[int], tuple[bool, bool, bool, int, int, int, int, int]):
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_interpreters.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_interpreters.pyi
index 6ddd89b7acab8..be2e5f184c86a 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_interpreters.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_interpreters.pyi
@@ -123,8 +123,8 @@ def exec(
def call(
id: SupportsIndex,
callable: Callable[..., _R],
- args: tuple[object, ...] | None = None,
- kwargs: dict[str, object] | None = None,
+ args: tuple[Any, ...] | None = None,
+ kwargs: dict[str, Any] | None = None,
*,
restrict: bool = False,
) -> tuple[_R, types.SimpleNamespace]:
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_io.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_io.pyi
index 44c25aca9c7be..ef07b92aaf339 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_io.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_io.pyi
@@ -367,6 +367,7 @@ class BytesIO(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc]
Returns the new absolute position.
"""
+@type_check_only
class _BufferedReaderStream(Protocol):
def read(self, n: int = ..., /) -> bytes: ...
# Optional: def readall(self) -> bytes: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_msi.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_msi.pyi
index 2ed64bbad48f9..b828147122bd5 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_msi.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_msi.pyi
@@ -1,10 +1,12 @@
"""Documentation"""
import sys
+from typing import type_check_only
if sys.platform == "win32":
class MSIError(Exception): ...
# Actual typename View, not exposed by the implementation
+ @type_check_only
class _View:
def Execute(self, params: _Record | None = ...) -> None: ...
def GetColumnInfo(self, kind: int) -> _Record: ...
@@ -16,6 +18,7 @@ if sys.platform == "win32":
__init__: None # type: ignore[assignment]
# Actual typename SummaryInformation, not exposed by the implementation
+ @type_check_only
class _SummaryInformation:
def GetProperty(self, field: int) -> int | bytes | None: ...
def GetPropertyCount(self) -> int: ...
@@ -26,6 +29,7 @@ if sys.platform == "win32":
__init__: None # type: ignore[assignment]
# Actual typename Database, not exposed by the implementation
+ @type_check_only
class _Database:
def OpenView(self, sql: str) -> _View: ...
def Commit(self) -> None: ...
@@ -36,6 +40,7 @@ if sys.platform == "win32":
__init__: None # type: ignore[assignment]
# Actual typename Record, not exposed by the implementation
+ @type_check_only
class _Record:
def GetFieldCount(self) -> int: ...
def GetInteger(self, field: int) -> int: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_operator.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_operator.pyi
index ca4bbcf6d3404..7e893a6e4211d 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_operator.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_operator.pyi
@@ -37,6 +37,7 @@ class _SupportsDunderGT(Protocol):
class _SupportsDunderLE(Protocol):
def __le__(self, other: Any, /) -> Any: ...
+@type_check_only
class _SupportsDunderGE(Protocol):
def __ge__(self, other: Any, /) -> Any: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_pickle.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_pickle.pyi
index 58d7d02b33331..de25ab866c53f 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_pickle.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_pickle.pyi
@@ -6,6 +6,7 @@ from pickle import PickleBuffer as PickleBuffer
from typing import Any, Protocol, type_check_only
from typing_extensions import TypeAlias
+@type_check_only
class _ReadableFileobj(Protocol):
def read(self, n: int, /) -> bytes: ...
def readline(self) -> bytes: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_socket.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_socket.pyi
index a024ff0b82004..f5abc17748389 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_socket.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_socket.pyi
@@ -7,7 +7,7 @@ import sys
from _typeshed import ReadableBuffer, WriteableBuffer
from collections.abc import Iterable
from socket import error as error, gaierror as gaierror, herror as herror, timeout as timeout
-from typing import Any, SupportsIndex, overload
+from typing import Any, Final, SupportsIndex, overload
from typing_extensions import CapsuleType, TypeAlias
_CMSG: TypeAlias = tuple[int, int, bytes]
@@ -24,23 +24,23 @@ _RetAddress: TypeAlias = Any
# https://docs.python.org/3/library/socket.html#constants
if sys.platform != "win32":
- AF_UNIX: int
+ AF_UNIX: Final[int]
-AF_INET: int
-AF_INET6: int
+AF_INET: Final[int]
+AF_INET6: Final[int]
-AF_UNSPEC: int
+AF_UNSPEC: Final[int]
-SOCK_STREAM: int
-SOCK_DGRAM: int
-SOCK_RAW: int
-SOCK_RDM: int
-SOCK_SEQPACKET: int
+SOCK_STREAM: Final[int]
+SOCK_DGRAM: Final[int]
+SOCK_RAW: Final[int]
+SOCK_RDM: Final[int]
+SOCK_SEQPACKET: Final[int]
if sys.platform == "linux":
# Availability: Linux >= 2.6.27
- SOCK_CLOEXEC: int
- SOCK_NONBLOCK: int
+ SOCK_CLOEXEC: Final[int]
+ SOCK_NONBLOCK: Final[int]
# --------------------
# Many constants of these forms, documented in the Unix documentation on
@@ -61,329 +61,329 @@ if sys.platform == "linux":
# TCP_*
# --------------------
-SO_ACCEPTCONN: int
-SO_BROADCAST: int
-SO_DEBUG: int
-SO_DONTROUTE: int
-SO_ERROR: int
-SO_KEEPALIVE: int
-SO_LINGER: int
-SO_OOBINLINE: int
-SO_RCVBUF: int
-SO_RCVLOWAT: int
-SO_RCVTIMEO: int
-SO_REUSEADDR: int
-SO_SNDBUF: int
-SO_SNDLOWAT: int
-SO_SNDTIMEO: int
-SO_TYPE: int
+SO_ACCEPTCONN: Final[int]
+SO_BROADCAST: Final[int]
+SO_DEBUG: Final[int]
+SO_DONTROUTE: Final[int]
+SO_ERROR: Final[int]
+SO_KEEPALIVE: Final[int]
+SO_LINGER: Final[int]
+SO_OOBINLINE: Final[int]
+SO_RCVBUF: Final[int]
+SO_RCVLOWAT: Final[int]
+SO_RCVTIMEO: Final[int]
+SO_REUSEADDR: Final[int]
+SO_SNDBUF: Final[int]
+SO_SNDLOWAT: Final[int]
+SO_SNDTIMEO: Final[int]
+SO_TYPE: Final[int]
if sys.platform != "linux":
- SO_USELOOPBACK: int
+ SO_USELOOPBACK: Final[int]
if sys.platform == "win32":
- SO_EXCLUSIVEADDRUSE: int
+ SO_EXCLUSIVEADDRUSE: Final[int]
if sys.platform != "win32":
- SO_REUSEPORT: int
+ SO_REUSEPORT: Final[int]
if sys.platform != "darwin" or sys.version_info >= (3, 13):
- SO_BINDTODEVICE: int
+ SO_BINDTODEVICE: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
- SO_DOMAIN: int
- SO_MARK: int
- SO_PASSCRED: int
- SO_PASSSEC: int
- SO_PEERCRED: int
- SO_PEERSEC: int
- SO_PRIORITY: int
- SO_PROTOCOL: int
+ SO_DOMAIN: Final[int]
+ SO_MARK: Final[int]
+ SO_PASSCRED: Final[int]
+ SO_PASSSEC: Final[int]
+ SO_PEERCRED: Final[int]
+ SO_PEERSEC: Final[int]
+ SO_PRIORITY: Final[int]
+ SO_PROTOCOL: Final[int]
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
- SO_SETFIB: int
+ SO_SETFIB: Final[int]
if sys.platform == "linux" and sys.version_info >= (3, 13):
- SO_BINDTOIFINDEX: int
+ SO_BINDTOIFINDEX: Final[int]
-SOMAXCONN: int
+SOMAXCONN: Final[int]
-MSG_CTRUNC: int
-MSG_DONTROUTE: int
-MSG_OOB: int
-MSG_PEEK: int
-MSG_TRUNC: int
-MSG_WAITALL: int
+MSG_CTRUNC: Final[int]
+MSG_DONTROUTE: Final[int]
+MSG_OOB: Final[int]
+MSG_PEEK: Final[int]
+MSG_TRUNC: Final[int]
+MSG_WAITALL: Final[int]
if sys.platform != "win32":
- MSG_DONTWAIT: int
- MSG_EOR: int
- MSG_NOSIGNAL: int # Sometimes this exists on darwin, sometimes not
+ MSG_DONTWAIT: Final[int]
+ MSG_EOR: Final[int]
+ MSG_NOSIGNAL: Final[int] # Sometimes this exists on darwin, sometimes not
if sys.platform != "darwin":
- MSG_ERRQUEUE: int
+ MSG_ERRQUEUE: Final[int]
if sys.platform == "win32":
- MSG_BCAST: int
- MSG_MCAST: int
+ MSG_BCAST: Final[int]
+ MSG_MCAST: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
- MSG_CMSG_CLOEXEC: int
- MSG_CONFIRM: int
- MSG_FASTOPEN: int
- MSG_MORE: int
+ MSG_CMSG_CLOEXEC: Final[int]
+ MSG_CONFIRM: Final[int]
+ MSG_FASTOPEN: Final[int]
+ MSG_MORE: Final[int]
if sys.platform != "win32" and sys.platform != "linux":
- MSG_EOF: int
+ MSG_EOF: Final[int]
if sys.platform != "win32" and sys.platform != "linux" and sys.platform != "darwin":
- MSG_NOTIFICATION: int
- MSG_BTAG: int # Not FreeBSD either
- MSG_ETAG: int # Not FreeBSD either
-
-SOL_IP: int
-SOL_SOCKET: int
-SOL_TCP: int
-SOL_UDP: int
+ MSG_NOTIFICATION: Final[int]
+ MSG_BTAG: Final[int] # Not FreeBSD either
+ MSG_ETAG: Final[int] # Not FreeBSD either
+
+SOL_IP: Final[int]
+SOL_SOCKET: Final[int]
+SOL_TCP: Final[int]
+SOL_UDP: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
# Defined in socket.h for Linux, but these aren't always present for
# some reason.
- SOL_ATALK: int
- SOL_AX25: int
- SOL_HCI: int
- SOL_IPX: int
- SOL_NETROM: int
- SOL_ROSE: int
+ SOL_ATALK: Final[int]
+ SOL_AX25: Final[int]
+ SOL_HCI: Final[int]
+ SOL_IPX: Final[int]
+ SOL_NETROM: Final[int]
+ SOL_ROSE: Final[int]
if sys.platform != "win32":
- SCM_RIGHTS: int
+ SCM_RIGHTS: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
- SCM_CREDENTIALS: int
+ SCM_CREDENTIALS: Final[int]
if sys.platform != "win32" and sys.platform != "linux":
- SCM_CREDS: int
-
-IPPROTO_ICMP: int
-IPPROTO_IP: int
-IPPROTO_RAW: int
-IPPROTO_TCP: int
-IPPROTO_UDP: int
-IPPROTO_AH: int
-IPPROTO_DSTOPTS: int
-IPPROTO_EGP: int
-IPPROTO_ESP: int
-IPPROTO_FRAGMENT: int
-IPPROTO_HOPOPTS: int
-IPPROTO_ICMPV6: int
-IPPROTO_IDP: int
-IPPROTO_IGMP: int
-IPPROTO_IPV6: int
-IPPROTO_NONE: int
-IPPROTO_PIM: int
-IPPROTO_PUP: int
-IPPROTO_ROUTING: int
-IPPROTO_SCTP: int
+ SCM_CREDS: Final[int]
+
+IPPROTO_ICMP: Final[int]
+IPPROTO_IP: Final[int]
+IPPROTO_RAW: Final[int]
+IPPROTO_TCP: Final[int]
+IPPROTO_UDP: Final[int]
+IPPROTO_AH: Final[int]
+IPPROTO_DSTOPTS: Final[int]
+IPPROTO_EGP: Final[int]
+IPPROTO_ESP: Final[int]
+IPPROTO_FRAGMENT: Final[int]
+IPPROTO_HOPOPTS: Final[int]
+IPPROTO_ICMPV6: Final[int]
+IPPROTO_IDP: Final[int]
+IPPROTO_IGMP: Final[int]
+IPPROTO_IPV6: Final[int]
+IPPROTO_NONE: Final[int]
+IPPROTO_PIM: Final[int]
+IPPROTO_PUP: Final[int]
+IPPROTO_ROUTING: Final[int]
+IPPROTO_SCTP: Final[int]
if sys.platform != "linux":
- IPPROTO_GGP: int
- IPPROTO_IPV4: int
- IPPROTO_MAX: int
- IPPROTO_ND: int
+ IPPROTO_GGP: Final[int]
+ IPPROTO_IPV4: Final[int]
+ IPPROTO_MAX: Final[int]
+ IPPROTO_ND: Final[int]
if sys.platform == "win32":
- IPPROTO_CBT: int
- IPPROTO_ICLFXBM: int
- IPPROTO_IGP: int
- IPPROTO_L2TP: int
- IPPROTO_PGM: int
- IPPROTO_RDP: int
- IPPROTO_ST: int
+ IPPROTO_CBT: Final[int]
+ IPPROTO_ICLFXBM: Final[int]
+ IPPROTO_IGP: Final[int]
+ IPPROTO_L2TP: Final[int]
+ IPPROTO_PGM: Final[int]
+ IPPROTO_RDP: Final[int]
+ IPPROTO_ST: Final[int]
if sys.platform != "win32":
- IPPROTO_GRE: int
- IPPROTO_IPIP: int
- IPPROTO_RSVP: int
- IPPROTO_TP: int
+ IPPROTO_GRE: Final[int]
+ IPPROTO_IPIP: Final[int]
+ IPPROTO_RSVP: Final[int]
+ IPPROTO_TP: Final[int]
if sys.platform != "win32" and sys.platform != "linux":
- IPPROTO_EON: int
- IPPROTO_HELLO: int
- IPPROTO_IPCOMP: int
- IPPROTO_XTP: int
+ IPPROTO_EON: Final[int]
+ IPPROTO_HELLO: Final[int]
+ IPPROTO_IPCOMP: Final[int]
+ IPPROTO_XTP: Final[int]
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
- IPPROTO_BIP: int # Not FreeBSD either
- IPPROTO_MOBILE: int # Not FreeBSD either
- IPPROTO_VRRP: int # Not FreeBSD either
+ IPPROTO_BIP: Final[int] # Not FreeBSD either
+ IPPROTO_MOBILE: Final[int] # Not FreeBSD either
+ IPPROTO_VRRP: Final[int] # Not FreeBSD either
if sys.platform == "linux":
# Availability: Linux >= 2.6.20, FreeBSD >= 10.1
- IPPROTO_UDPLITE: int
+ IPPROTO_UDPLITE: Final[int]
if sys.version_info >= (3, 10) and sys.platform == "linux":
- IPPROTO_MPTCP: int
-
-IPPORT_RESERVED: int
-IPPORT_USERRESERVED: int
-
-INADDR_ALLHOSTS_GROUP: int
-INADDR_ANY: int
-INADDR_BROADCAST: int
-INADDR_LOOPBACK: int
-INADDR_MAX_LOCAL_GROUP: int
-INADDR_NONE: int
-INADDR_UNSPEC_GROUP: int
-
-IP_ADD_MEMBERSHIP: int
-IP_DROP_MEMBERSHIP: int
-IP_HDRINCL: int
-IP_MULTICAST_IF: int
-IP_MULTICAST_LOOP: int
-IP_MULTICAST_TTL: int
-IP_OPTIONS: int
+ IPPROTO_MPTCP: Final[int]
+
+IPPORT_RESERVED: Final[int]
+IPPORT_USERRESERVED: Final[int]
+
+INADDR_ALLHOSTS_GROUP: Final[int]
+INADDR_ANY: Final[int]
+INADDR_BROADCAST: Final[int]
+INADDR_LOOPBACK: Final[int]
+INADDR_MAX_LOCAL_GROUP: Final[int]
+INADDR_NONE: Final[int]
+INADDR_UNSPEC_GROUP: Final[int]
+
+IP_ADD_MEMBERSHIP: Final[int]
+IP_DROP_MEMBERSHIP: Final[int]
+IP_HDRINCL: Final[int]
+IP_MULTICAST_IF: Final[int]
+IP_MULTICAST_LOOP: Final[int]
+IP_MULTICAST_TTL: Final[int]
+IP_OPTIONS: Final[int]
if sys.platform != "linux":
- IP_RECVDSTADDR: int
+ IP_RECVDSTADDR: Final[int]
if sys.version_info >= (3, 10):
- IP_RECVTOS: int
-IP_TOS: int
-IP_TTL: int
+ IP_RECVTOS: Final[int]
+IP_TOS: Final[int]
+IP_TTL: Final[int]
if sys.platform != "win32":
- IP_DEFAULT_MULTICAST_LOOP: int
- IP_DEFAULT_MULTICAST_TTL: int
- IP_MAX_MEMBERSHIPS: int
- IP_RECVOPTS: int
- IP_RECVRETOPTS: int
- IP_RETOPTS: int
+ IP_DEFAULT_MULTICAST_LOOP: Final[int]
+ IP_DEFAULT_MULTICAST_TTL: Final[int]
+ IP_MAX_MEMBERSHIPS: Final[int]
+ IP_RECVOPTS: Final[int]
+ IP_RECVRETOPTS: Final[int]
+ IP_RETOPTS: Final[int]
if sys.version_info >= (3, 13) and sys.platform == "linux":
- CAN_RAW_ERR_FILTER: int
+ CAN_RAW_ERR_FILTER: Final[int]
if sys.version_info >= (3, 14):
- IP_RECVTTL: int
+ IP_RECVTTL: Final[int]
if sys.platform == "win32" or sys.platform == "linux":
- IPV6_RECVERR: int
- IP_RECVERR: int
- SO_ORIGINAL_DST: int
+ IPV6_RECVERR: Final[int]
+ IP_RECVERR: Final[int]
+ SO_ORIGINAL_DST: Final[int]
if sys.platform == "win32":
- SOL_RFCOMM: int
- SO_BTH_ENCRYPT: int
- SO_BTH_MTU: int
- SO_BTH_MTU_MAX: int
- SO_BTH_MTU_MIN: int
- TCP_QUICKACK: int
+ SOL_RFCOMM: Final[int]
+ SO_BTH_ENCRYPT: Final[int]
+ SO_BTH_MTU: Final[int]
+ SO_BTH_MTU_MAX: Final[int]
+ SO_BTH_MTU_MIN: Final[int]
+ TCP_QUICKACK: Final[int]
if sys.platform == "linux":
- IP_FREEBIND: int
- IP_RECVORIGDSTADDR: int
- VMADDR_CID_LOCAL: int
+ IP_FREEBIND: Final[int]
+ IP_RECVORIGDSTADDR: Final[int]
+ VMADDR_CID_LOCAL: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
- IP_TRANSPARENT: int
+ IP_TRANSPARENT: Final[int]
if sys.platform != "win32" and sys.platform != "darwin" and sys.version_info >= (3, 11):
- IP_BIND_ADDRESS_NO_PORT: int
+ IP_BIND_ADDRESS_NO_PORT: Final[int]
if sys.version_info >= (3, 12):
- IP_ADD_SOURCE_MEMBERSHIP: int
- IP_BLOCK_SOURCE: int
- IP_DROP_SOURCE_MEMBERSHIP: int
- IP_PKTINFO: int
- IP_UNBLOCK_SOURCE: int
-
-IPV6_CHECKSUM: int
-IPV6_JOIN_GROUP: int
-IPV6_LEAVE_GROUP: int
-IPV6_MULTICAST_HOPS: int
-IPV6_MULTICAST_IF: int
-IPV6_MULTICAST_LOOP: int
-IPV6_RECVTCLASS: int
-IPV6_TCLASS: int
-IPV6_UNICAST_HOPS: int
-IPV6_V6ONLY: int
-IPV6_DONTFRAG: int
-IPV6_HOPLIMIT: int
-IPV6_HOPOPTS: int
-IPV6_PKTINFO: int
-IPV6_RECVRTHDR: int
-IPV6_RTHDR: int
+ IP_ADD_SOURCE_MEMBERSHIP: Final[int]
+ IP_BLOCK_SOURCE: Final[int]
+ IP_DROP_SOURCE_MEMBERSHIP: Final[int]
+ IP_PKTINFO: Final[int]
+ IP_UNBLOCK_SOURCE: Final[int]
+
+IPV6_CHECKSUM: Final[int]
+IPV6_JOIN_GROUP: Final[int]
+IPV6_LEAVE_GROUP: Final[int]
+IPV6_MULTICAST_HOPS: Final[int]
+IPV6_MULTICAST_IF: Final[int]
+IPV6_MULTICAST_LOOP: Final[int]
+IPV6_RECVTCLASS: Final[int]
+IPV6_TCLASS: Final[int]
+IPV6_UNICAST_HOPS: Final[int]
+IPV6_V6ONLY: Final[int]
+IPV6_DONTFRAG: Final[int]
+IPV6_HOPLIMIT: Final[int]
+IPV6_HOPOPTS: Final[int]
+IPV6_PKTINFO: Final[int]
+IPV6_RECVRTHDR: Final[int]
+IPV6_RTHDR: Final[int]
if sys.platform != "win32":
- IPV6_RTHDR_TYPE_0: int
- IPV6_DSTOPTS: int
- IPV6_NEXTHOP: int
- IPV6_PATHMTU: int
- IPV6_RECVDSTOPTS: int
- IPV6_RECVHOPLIMIT: int
- IPV6_RECVHOPOPTS: int
- IPV6_RECVPATHMTU: int
- IPV6_RECVPKTINFO: int
- IPV6_RTHDRDSTOPTS: int
+ IPV6_RTHDR_TYPE_0: Final[int]
+ IPV6_DSTOPTS: Final[int]
+ IPV6_NEXTHOP: Final[int]
+ IPV6_PATHMTU: Final[int]
+ IPV6_RECVDSTOPTS: Final[int]
+ IPV6_RECVHOPLIMIT: Final[int]
+ IPV6_RECVHOPOPTS: Final[int]
+ IPV6_RECVPATHMTU: Final[int]
+ IPV6_RECVPKTINFO: Final[int]
+ IPV6_RTHDRDSTOPTS: Final[int]
if sys.platform != "win32" and sys.platform != "linux":
- IPV6_USE_MIN_MTU: int
-
-EAI_AGAIN: int
-EAI_BADFLAGS: int
-EAI_FAIL: int
-EAI_FAMILY: int
-EAI_MEMORY: int
-EAI_NODATA: int
-EAI_NONAME: int
-EAI_SERVICE: int
-EAI_SOCKTYPE: int
+ IPV6_USE_MIN_MTU: Final[int]
+
+EAI_AGAIN: Final[int]
+EAI_BADFLAGS: Final[int]
+EAI_FAIL: Final[int]
+EAI_FAMILY: Final[int]
+EAI_MEMORY: Final[int]
+EAI_NODATA: Final[int]
+EAI_NONAME: Final[int]
+EAI_SERVICE: Final[int]
+EAI_SOCKTYPE: Final[int]
if sys.platform != "win32":
- EAI_ADDRFAMILY: int
- EAI_OVERFLOW: int
- EAI_SYSTEM: int
+ EAI_ADDRFAMILY: Final[int]
+ EAI_OVERFLOW: Final[int]
+ EAI_SYSTEM: Final[int]
if sys.platform != "win32" and sys.platform != "linux":
- EAI_BADHINTS: int
- EAI_MAX: int
- EAI_PROTOCOL: int
-
-AI_ADDRCONFIG: int
-AI_ALL: int
-AI_CANONNAME: int
-AI_NUMERICHOST: int
-AI_NUMERICSERV: int
-AI_PASSIVE: int
-AI_V4MAPPED: int
+ EAI_BADHINTS: Final[int]
+ EAI_MAX: Final[int]
+ EAI_PROTOCOL: Final[int]
+
+AI_ADDRCONFIG: Final[int]
+AI_ALL: Final[int]
+AI_CANONNAME: Final[int]
+AI_NUMERICHOST: Final[int]
+AI_NUMERICSERV: Final[int]
+AI_PASSIVE: Final[int]
+AI_V4MAPPED: Final[int]
if sys.platform != "win32" and sys.platform != "linux":
- AI_DEFAULT: int
- AI_MASK: int
- AI_V4MAPPED_CFG: int
-
-NI_DGRAM: int
-NI_MAXHOST: int
-NI_MAXSERV: int
-NI_NAMEREQD: int
-NI_NOFQDN: int
-NI_NUMERICHOST: int
-NI_NUMERICSERV: int
+ AI_DEFAULT: Final[int]
+ AI_MASK: Final[int]
+ AI_V4MAPPED_CFG: Final[int]
+
+NI_DGRAM: Final[int]
+NI_MAXHOST: Final[int]
+NI_MAXSERV: Final[int]
+NI_NAMEREQD: Final[int]
+NI_NOFQDN: Final[int]
+NI_NUMERICHOST: Final[int]
+NI_NUMERICSERV: Final[int]
if sys.platform == "linux" and sys.version_info >= (3, 13):
- NI_IDN: int
+ NI_IDN: Final[int]
-TCP_FASTOPEN: int
-TCP_KEEPCNT: int
-TCP_KEEPINTVL: int
-TCP_MAXSEG: int
-TCP_NODELAY: int
+TCP_FASTOPEN: Final[int]
+TCP_KEEPCNT: Final[int]
+TCP_KEEPINTVL: Final[int]
+TCP_MAXSEG: Final[int]
+TCP_NODELAY: Final[int]
if sys.platform != "win32":
- TCP_NOTSENT_LOWAT: int
+ TCP_NOTSENT_LOWAT: Final[int]
if sys.platform != "darwin":
- TCP_KEEPIDLE: int
+ TCP_KEEPIDLE: Final[int]
if sys.version_info >= (3, 10) and sys.platform == "darwin":
- TCP_KEEPALIVE: int
+ TCP_KEEPALIVE: Final[int]
if sys.version_info >= (3, 11) and sys.platform == "darwin":
- TCP_CONNECTION_INFO: int
+ TCP_CONNECTION_INFO: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
- TCP_CONGESTION: int
- TCP_CORK: int
- TCP_DEFER_ACCEPT: int
- TCP_INFO: int
- TCP_LINGER2: int
- TCP_QUICKACK: int
- TCP_SYNCNT: int
- TCP_USER_TIMEOUT: int
- TCP_WINDOW_CLAMP: int
+ TCP_CONGESTION: Final[int]
+ TCP_CORK: Final[int]
+ TCP_DEFER_ACCEPT: Final[int]
+ TCP_INFO: Final[int]
+ TCP_LINGER2: Final[int]
+ TCP_QUICKACK: Final[int]
+ TCP_SYNCNT: Final[int]
+ TCP_USER_TIMEOUT: Final[int]
+ TCP_WINDOW_CLAMP: Final[int]
if sys.platform == "linux" and sys.version_info >= (3, 12):
- TCP_CC_INFO: int
- TCP_FASTOPEN_CONNECT: int
- TCP_FASTOPEN_KEY: int
- TCP_FASTOPEN_NO_COOKIE: int
- TCP_INQ: int
- TCP_MD5SIG: int
- TCP_MD5SIG_EXT: int
- TCP_QUEUE_SEQ: int
- TCP_REPAIR: int
- TCP_REPAIR_OPTIONS: int
- TCP_REPAIR_QUEUE: int
- TCP_REPAIR_WINDOW: int
- TCP_SAVED_SYN: int
- TCP_SAVE_SYN: int
- TCP_THIN_DUPACK: int
- TCP_THIN_LINEAR_TIMEOUTS: int
- TCP_TIMESTAMP: int
- TCP_TX_DELAY: int
- TCP_ULP: int
- TCP_ZEROCOPY_RECEIVE: int
+ TCP_CC_INFO: Final[int]
+ TCP_FASTOPEN_CONNECT: Final[int]
+ TCP_FASTOPEN_KEY: Final[int]
+ TCP_FASTOPEN_NO_COOKIE: Final[int]
+ TCP_INQ: Final[int]
+ TCP_MD5SIG: Final[int]
+ TCP_MD5SIG_EXT: Final[int]
+ TCP_QUEUE_SEQ: Final[int]
+ TCP_REPAIR: Final[int]
+ TCP_REPAIR_OPTIONS: Final[int]
+ TCP_REPAIR_QUEUE: Final[int]
+ TCP_REPAIR_WINDOW: Final[int]
+ TCP_SAVED_SYN: Final[int]
+ TCP_SAVE_SYN: Final[int]
+ TCP_THIN_DUPACK: Final[int]
+ TCP_THIN_LINEAR_TIMEOUTS: Final[int]
+ TCP_TIMESTAMP: Final[int]
+ TCP_TX_DELAY: Final[int]
+ TCP_ULP: Final[int]
+ TCP_ZEROCOPY_RECEIVE: Final[int]
# --------------------
# Specifically documented constants
@@ -391,250 +391,250 @@ if sys.platform == "linux" and sys.version_info >= (3, 12):
if sys.platform == "linux":
# Availability: Linux >= 2.6.25, NetBSD >= 8
- AF_CAN: int
- PF_CAN: int
- SOL_CAN_BASE: int
- SOL_CAN_RAW: int
- CAN_EFF_FLAG: int
- CAN_EFF_MASK: int
- CAN_ERR_FLAG: int
- CAN_ERR_MASK: int
- CAN_RAW: int
- CAN_RAW_FILTER: int
- CAN_RAW_LOOPBACK: int
- CAN_RAW_RECV_OWN_MSGS: int
- CAN_RTR_FLAG: int
- CAN_SFF_MASK: int
+ AF_CAN: Final[int]
+ PF_CAN: Final[int]
+ SOL_CAN_BASE: Final[int]
+ SOL_CAN_RAW: Final[int]
+ CAN_EFF_FLAG: Final[int]
+ CAN_EFF_MASK: Final[int]
+ CAN_ERR_FLAG: Final[int]
+ CAN_ERR_MASK: Final[int]
+ CAN_RAW: Final[int]
+ CAN_RAW_FILTER: Final[int]
+ CAN_RAW_LOOPBACK: Final[int]
+ CAN_RAW_RECV_OWN_MSGS: Final[int]
+ CAN_RTR_FLAG: Final[int]
+ CAN_SFF_MASK: Final[int]
if sys.version_info < (3, 11):
- CAN_RAW_ERR_FILTER: int
+ CAN_RAW_ERR_FILTER: Final[int]
if sys.platform == "linux":
# Availability: Linux >= 2.6.25
- CAN_BCM: int
- CAN_BCM_TX_SETUP: int
- CAN_BCM_TX_DELETE: int
- CAN_BCM_TX_READ: int
- CAN_BCM_TX_SEND: int
- CAN_BCM_RX_SETUP: int
- CAN_BCM_RX_DELETE: int
- CAN_BCM_RX_READ: int
- CAN_BCM_TX_STATUS: int
- CAN_BCM_TX_EXPIRED: int
- CAN_BCM_RX_STATUS: int
- CAN_BCM_RX_TIMEOUT: int
- CAN_BCM_RX_CHANGED: int
- CAN_BCM_SETTIMER: int
- CAN_BCM_STARTTIMER: int
- CAN_BCM_TX_COUNTEVT: int
- CAN_BCM_TX_ANNOUNCE: int
- CAN_BCM_TX_CP_CAN_ID: int
- CAN_BCM_RX_FILTER_ID: int
- CAN_BCM_RX_CHECK_DLC: int
- CAN_BCM_RX_NO_AUTOTIMER: int
- CAN_BCM_RX_ANNOUNCE_RESUME: int
- CAN_BCM_TX_RESET_MULTI_IDX: int
- CAN_BCM_RX_RTR_FRAME: int
- CAN_BCM_CAN_FD_FRAME: int
+ CAN_BCM: Final[int]
+ CAN_BCM_TX_SETUP: Final[int]
+ CAN_BCM_TX_DELETE: Final[int]
+ CAN_BCM_TX_READ: Final[int]
+ CAN_BCM_TX_SEND: Final[int]
+ CAN_BCM_RX_SETUP: Final[int]
+ CAN_BCM_RX_DELETE: Final[int]
+ CAN_BCM_RX_READ: Final[int]
+ CAN_BCM_TX_STATUS: Final[int]
+ CAN_BCM_TX_EXPIRED: Final[int]
+ CAN_BCM_RX_STATUS: Final[int]
+ CAN_BCM_RX_TIMEOUT: Final[int]
+ CAN_BCM_RX_CHANGED: Final[int]
+ CAN_BCM_SETTIMER: Final[int]
+ CAN_BCM_STARTTIMER: Final[int]
+ CAN_BCM_TX_COUNTEVT: Final[int]
+ CAN_BCM_TX_ANNOUNCE: Final[int]
+ CAN_BCM_TX_CP_CAN_ID: Final[int]
+ CAN_BCM_RX_FILTER_ID: Final[int]
+ CAN_BCM_RX_CHECK_DLC: Final[int]
+ CAN_BCM_RX_NO_AUTOTIMER: Final[int]
+ CAN_BCM_RX_ANNOUNCE_RESUME: Final[int]
+ CAN_BCM_TX_RESET_MULTI_IDX: Final[int]
+ CAN_BCM_RX_RTR_FRAME: Final[int]
+ CAN_BCM_CAN_FD_FRAME: Final[int]
if sys.platform == "linux":
# Availability: Linux >= 3.6
- CAN_RAW_FD_FRAMES: int
+ CAN_RAW_FD_FRAMES: Final[int]
# Availability: Linux >= 4.1
- CAN_RAW_JOIN_FILTERS: int
+ CAN_RAW_JOIN_FILTERS: Final[int]
# Availability: Linux >= 2.6.25
- CAN_ISOTP: int
+ CAN_ISOTP: Final[int]
# Availability: Linux >= 5.4
- CAN_J1939: int
-
- J1939_MAX_UNICAST_ADDR: int
- J1939_IDLE_ADDR: int
- J1939_NO_ADDR: int
- J1939_NO_NAME: int
- J1939_PGN_REQUEST: int
- J1939_PGN_ADDRESS_CLAIMED: int
- J1939_PGN_ADDRESS_COMMANDED: int
- J1939_PGN_PDU1_MAX: int
- J1939_PGN_MAX: int
- J1939_NO_PGN: int
-
- SO_J1939_FILTER: int
- SO_J1939_PROMISC: int
- SO_J1939_SEND_PRIO: int
- SO_J1939_ERRQUEUE: int
-
- SCM_J1939_DEST_ADDR: int
- SCM_J1939_DEST_NAME: int
- SCM_J1939_PRIO: int
- SCM_J1939_ERRQUEUE: int
-
- J1939_NLA_PAD: int
- J1939_NLA_BYTES_ACKED: int
- J1939_EE_INFO_NONE: int
- J1939_EE_INFO_TX_ABORT: int
- J1939_FILTER_MAX: int
+ CAN_J1939: Final[int]
+
+ J1939_MAX_UNICAST_ADDR: Final[int]
+ J1939_IDLE_ADDR: Final[int]
+ J1939_NO_ADDR: Final[int]
+ J1939_NO_NAME: Final[int]
+ J1939_PGN_REQUEST: Final[int]
+ J1939_PGN_ADDRESS_CLAIMED: Final[int]
+ J1939_PGN_ADDRESS_COMMANDED: Final[int]
+ J1939_PGN_PDU1_MAX: Final[int]
+ J1939_PGN_MAX: Final[int]
+ J1939_NO_PGN: Final[int]
+
+ SO_J1939_FILTER: Final[int]
+ SO_J1939_PROMISC: Final[int]
+ SO_J1939_SEND_PRIO: Final[int]
+ SO_J1939_ERRQUEUE: Final[int]
+
+ SCM_J1939_DEST_ADDR: Final[int]
+ SCM_J1939_DEST_NAME: Final[int]
+ SCM_J1939_PRIO: Final[int]
+ SCM_J1939_ERRQUEUE: Final[int]
+
+ J1939_NLA_PAD: Final[int]
+ J1939_NLA_BYTES_ACKED: Final[int]
+ J1939_EE_INFO_NONE: Final[int]
+ J1939_EE_INFO_TX_ABORT: Final[int]
+ J1939_FILTER_MAX: Final[int]
if sys.version_info >= (3, 12) and sys.platform != "linux" and sys.platform != "win32" and sys.platform != "darwin":
# Availability: FreeBSD >= 14.0
- AF_DIVERT: int
- PF_DIVERT: int
+ AF_DIVERT: Final[int]
+ PF_DIVERT: Final[int]
if sys.platform == "linux":
# Availability: Linux >= 2.2
- AF_PACKET: int
- PF_PACKET: int
- PACKET_BROADCAST: int
- PACKET_FASTROUTE: int
- PACKET_HOST: int
- PACKET_LOOPBACK: int
- PACKET_MULTICAST: int
- PACKET_OTHERHOST: int
- PACKET_OUTGOING: int
+ AF_PACKET: Final[int]
+ PF_PACKET: Final[int]
+ PACKET_BROADCAST: Final[int]
+ PACKET_FASTROUTE: Final[int]
+ PACKET_HOST: Final[int]
+ PACKET_LOOPBACK: Final[int]
+ PACKET_MULTICAST: Final[int]
+ PACKET_OTHERHOST: Final[int]
+ PACKET_OUTGOING: Final[int]
if sys.version_info >= (3, 12) and sys.platform == "linux":
- ETH_P_ALL: int
+ ETH_P_ALL: Final[int]
if sys.platform == "linux":
# Availability: Linux >= 2.6.30
- AF_RDS: int
- PF_RDS: int
- SOL_RDS: int
+ AF_RDS: Final[int]
+ PF_RDS: Final[int]
+ SOL_RDS: Final[int]
# These are present in include/linux/rds.h but don't always show up
# here.
- RDS_CANCEL_SENT_TO: int
- RDS_CMSG_RDMA_ARGS: int
- RDS_CMSG_RDMA_DEST: int
- RDS_CMSG_RDMA_MAP: int
- RDS_CMSG_RDMA_STATUS: int
- RDS_CONG_MONITOR: int
- RDS_FREE_MR: int
- RDS_GET_MR: int
- RDS_GET_MR_FOR_DEST: int
- RDS_RDMA_DONTWAIT: int
- RDS_RDMA_FENCE: int
- RDS_RDMA_INVALIDATE: int
- RDS_RDMA_NOTIFY_ME: int
- RDS_RDMA_READWRITE: int
- RDS_RDMA_SILENT: int
- RDS_RDMA_USE_ONCE: int
- RDS_RECVERR: int
+ RDS_CANCEL_SENT_TO: Final[int]
+ RDS_CMSG_RDMA_ARGS: Final[int]
+ RDS_CMSG_RDMA_DEST: Final[int]
+ RDS_CMSG_RDMA_MAP: Final[int]
+ RDS_CMSG_RDMA_STATUS: Final[int]
+ RDS_CONG_MONITOR: Final[int]
+ RDS_FREE_MR: Final[int]
+ RDS_GET_MR: Final[int]
+ RDS_GET_MR_FOR_DEST: Final[int]
+ RDS_RDMA_DONTWAIT: Final[int]
+ RDS_RDMA_FENCE: Final[int]
+ RDS_RDMA_INVALIDATE: Final[int]
+ RDS_RDMA_NOTIFY_ME: Final[int]
+ RDS_RDMA_READWRITE: Final[int]
+ RDS_RDMA_SILENT: Final[int]
+ RDS_RDMA_USE_ONCE: Final[int]
+ RDS_RECVERR: Final[int]
# This is supported by CPython but doesn't seem to be a real thing.
# The closest existing constant in rds.h is RDS_CMSG_CONG_UPDATE
- # RDS_CMSG_RDMA_UPDATE: int
+ # RDS_CMSG_RDMA_UPDATE: Final[int]
if sys.platform == "win32":
- SIO_RCVALL: int
- SIO_KEEPALIVE_VALS: int
- SIO_LOOPBACK_FAST_PATH: int
- RCVALL_MAX: int
- RCVALL_OFF: int
- RCVALL_ON: int
- RCVALL_SOCKETLEVELONLY: int
+ SIO_RCVALL: Final[int]
+ SIO_KEEPALIVE_VALS: Final[int]
+ SIO_LOOPBACK_FAST_PATH: Final[int]
+ RCVALL_MAX: Final[int]
+ RCVALL_OFF: Final[int]
+ RCVALL_ON: Final[int]
+ RCVALL_SOCKETLEVELONLY: Final[int]
if sys.platform == "linux":
- AF_TIPC: int
- SOL_TIPC: int
- TIPC_ADDR_ID: int
- TIPC_ADDR_NAME: int
- TIPC_ADDR_NAMESEQ: int
- TIPC_CFG_SRV: int
- TIPC_CLUSTER_SCOPE: int
- TIPC_CONN_TIMEOUT: int
- TIPC_CRITICAL_IMPORTANCE: int
- TIPC_DEST_DROPPABLE: int
- TIPC_HIGH_IMPORTANCE: int
- TIPC_IMPORTANCE: int
- TIPC_LOW_IMPORTANCE: int
- TIPC_MEDIUM_IMPORTANCE: int
- TIPC_NODE_SCOPE: int
- TIPC_PUBLISHED: int
- TIPC_SRC_DROPPABLE: int
- TIPC_SUBSCR_TIMEOUT: int
- TIPC_SUB_CANCEL: int
- TIPC_SUB_PORTS: int
- TIPC_SUB_SERVICE: int
- TIPC_TOP_SRV: int
- TIPC_WAIT_FOREVER: int
- TIPC_WITHDRAWN: int
- TIPC_ZONE_SCOPE: int
+ AF_TIPC: Final[int]
+ SOL_TIPC: Final[int]
+ TIPC_ADDR_ID: Final[int]
+ TIPC_ADDR_NAME: Final[int]
+ TIPC_ADDR_NAMESEQ: Final[int]
+ TIPC_CFG_SRV: Final[int]
+ TIPC_CLUSTER_SCOPE: Final[int]
+ TIPC_CONN_TIMEOUT: Final[int]
+ TIPC_CRITICAL_IMPORTANCE: Final[int]
+ TIPC_DEST_DROPPABLE: Final[int]
+ TIPC_HIGH_IMPORTANCE: Final[int]
+ TIPC_IMPORTANCE: Final[int]
+ TIPC_LOW_IMPORTANCE: Final[int]
+ TIPC_MEDIUM_IMPORTANCE: Final[int]
+ TIPC_NODE_SCOPE: Final[int]
+ TIPC_PUBLISHED: Final[int]
+ TIPC_SRC_DROPPABLE: Final[int]
+ TIPC_SUBSCR_TIMEOUT: Final[int]
+ TIPC_SUB_CANCEL: Final[int]
+ TIPC_SUB_PORTS: Final[int]
+ TIPC_SUB_SERVICE: Final[int]
+ TIPC_TOP_SRV: Final[int]
+ TIPC_WAIT_FOREVER: Final[int]
+ TIPC_WITHDRAWN: Final[int]
+ TIPC_ZONE_SCOPE: Final[int]
if sys.platform == "linux":
# Availability: Linux >= 2.6.38
- AF_ALG: int
- SOL_ALG: int
- ALG_OP_DECRYPT: int
- ALG_OP_ENCRYPT: int
- ALG_OP_SIGN: int
- ALG_OP_VERIFY: int
- ALG_SET_AEAD_ASSOCLEN: int
- ALG_SET_AEAD_AUTHSIZE: int
- ALG_SET_IV: int
- ALG_SET_KEY: int
- ALG_SET_OP: int
- ALG_SET_PUBKEY: int
+ AF_ALG: Final[int]
+ SOL_ALG: Final[int]
+ ALG_OP_DECRYPT: Final[int]
+ ALG_OP_ENCRYPT: Final[int]
+ ALG_OP_SIGN: Final[int]
+ ALG_OP_VERIFY: Final[int]
+ ALG_SET_AEAD_ASSOCLEN: Final[int]
+ ALG_SET_AEAD_AUTHSIZE: Final[int]
+ ALG_SET_IV: Final[int]
+ ALG_SET_KEY: Final[int]
+ ALG_SET_OP: Final[int]
+ ALG_SET_PUBKEY: Final[int]
if sys.platform == "linux":
# Availability: Linux >= 4.8 (or maybe 3.9, CPython docs are confusing)
- AF_VSOCK: int
- IOCTL_VM_SOCKETS_GET_LOCAL_CID: int
- VMADDR_CID_ANY: int
- VMADDR_CID_HOST: int
- VMADDR_PORT_ANY: int
- SO_VM_SOCKETS_BUFFER_MAX_SIZE: int
- SO_VM_SOCKETS_BUFFER_SIZE: int
- SO_VM_SOCKETS_BUFFER_MIN_SIZE: int
- VM_SOCKETS_INVALID_VERSION: int # undocumented
+ AF_VSOCK: Final[int]
+ IOCTL_VM_SOCKETS_GET_LOCAL_CID: Final = 0x7B9
+ VMADDR_CID_ANY: Final = 0xFFFFFFFF
+ VMADDR_CID_HOST: Final = 2
+ VMADDR_PORT_ANY: Final = 0xFFFFFFFF
+ SO_VM_SOCKETS_BUFFER_MAX_SIZE: Final = 2
+ SO_VM_SOCKETS_BUFFER_SIZE: Final = 0
+ SO_VM_SOCKETS_BUFFER_MIN_SIZE: Final = 1
+ VM_SOCKETS_INVALID_VERSION: Final = 0xFFFFFFFF # undocumented
# Documented as only available on BSD, macOS, but empirically sometimes
# available on Windows
if sys.platform != "linux":
- AF_LINK: int
+ AF_LINK: Final[int]
has_ipv6: bool
if sys.platform != "darwin" and sys.platform != "linux":
- BDADDR_ANY: str
- BDADDR_LOCAL: str
+ BDADDR_ANY: Final = "00:00:00:00:00:00"
+ BDADDR_LOCAL: Final = "00:00:00:FF:FF:FF"
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
- HCI_FILTER: int # not in NetBSD or DragonFlyBSD
- HCI_TIME_STAMP: int # not in FreeBSD, NetBSD, or DragonFlyBSD
- HCI_DATA_DIR: int # not in FreeBSD, NetBSD, or DragonFlyBSD
+ HCI_FILTER: Final[int] # not in NetBSD or DragonFlyBSD
+ HCI_TIME_STAMP: Final[int] # not in FreeBSD, NetBSD, or DragonFlyBSD
+ HCI_DATA_DIR: Final[int] # not in FreeBSD, NetBSD, or DragonFlyBSD
if sys.platform == "linux":
- AF_QIPCRTR: int # Availability: Linux >= 4.7
+ AF_QIPCRTR: Final[int] # Availability: Linux >= 4.7
if sys.version_info >= (3, 11) and sys.platform != "linux" and sys.platform != "win32" and sys.platform != "darwin":
# FreeBSD
- SCM_CREDS2: int
- LOCAL_CREDS: int
- LOCAL_CREDS_PERSISTENT: int
+ SCM_CREDS2: Final[int]
+ LOCAL_CREDS: Final[int]
+ LOCAL_CREDS_PERSISTENT: Final[int]
if sys.version_info >= (3, 11) and sys.platform == "linux":
- SO_INCOMING_CPU: int # Availability: Linux >= 3.9
+ SO_INCOMING_CPU: Final[int] # Availability: Linux >= 3.9
if sys.version_info >= (3, 12) and sys.platform == "win32":
# Availability: Windows
- AF_HYPERV: int
- HV_PROTOCOL_RAW: int
- HVSOCKET_CONNECT_TIMEOUT: int
- HVSOCKET_CONNECT_TIMEOUT_MAX: int
- HVSOCKET_CONNECTED_SUSPEND: int
- HVSOCKET_ADDRESS_FLAG_PASSTHRU: int
- HV_GUID_ZERO: str
- HV_GUID_WILDCARD: str
- HV_GUID_BROADCAST: str
- HV_GUID_CHILDREN: str
- HV_GUID_LOOPBACK: str
- HV_GUID_PARENT: str
+ AF_HYPERV: Final[int]
+ HV_PROTOCOL_RAW: Final[int]
+ HVSOCKET_CONNECT_TIMEOUT: Final[int]
+ HVSOCKET_CONNECT_TIMEOUT_MAX: Final[int]
+ HVSOCKET_CONNECTED_SUSPEND: Final[int]
+ HVSOCKET_ADDRESS_FLAG_PASSTHRU: Final[int]
+ HV_GUID_ZERO: Final = "00000000-0000-0000-0000-000000000000"
+ HV_GUID_WILDCARD: Final = "00000000-0000-0000-0000-000000000000"
+ HV_GUID_BROADCAST: Final = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"
+ HV_GUID_CHILDREN: Final = "90DB8B89-0D35-4F79-8CE9-49EA0AC8B7CD"
+ HV_GUID_LOOPBACK: Final = "E0E16197-DD56-4A10-9195-5EE7A155A838"
+ HV_GUID_PARENT: Final = "A42E7CDA-D03F-480C-9CC2-A4DE20ABB878"
if sys.version_info >= (3, 12):
if sys.platform != "win32":
# Availability: Linux, FreeBSD, macOS
- ETHERTYPE_ARP: int
- ETHERTYPE_IP: int
- ETHERTYPE_IPV6: int
- ETHERTYPE_VLAN: int
+ ETHERTYPE_ARP: Final[int]
+ ETHERTYPE_IP: Final[int]
+ ETHERTYPE_IPV6: Final[int]
+ ETHERTYPE_VLAN: Final[int]
# --------------------
# Semi-documented constants
@@ -644,95 +644,95 @@ if sys.version_info >= (3, 12):
if sys.platform == "linux":
# Netlink is defined by Linux
- AF_NETLINK: int
- NETLINK_CRYPTO: int
- NETLINK_DNRTMSG: int
- NETLINK_FIREWALL: int
- NETLINK_IP6_FW: int
- NETLINK_NFLOG: int
- NETLINK_ROUTE: int
- NETLINK_USERSOCK: int
- NETLINK_XFRM: int
+ AF_NETLINK: Final[int]
+ NETLINK_CRYPTO: Final[int]
+ NETLINK_DNRTMSG: Final[int]
+ NETLINK_FIREWALL: Final[int]
+ NETLINK_IP6_FW: Final[int]
+ NETLINK_NFLOG: Final[int]
+ NETLINK_ROUTE: Final[int]
+ NETLINK_USERSOCK: Final[int]
+ NETLINK_XFRM: Final[int]
# Technically still supported by CPython
- # NETLINK_ARPD: int # linux 2.0 to 2.6.12 (EOL August 2005)
- # NETLINK_ROUTE6: int # linux 2.2 to 2.6.12 (EOL August 2005)
- # NETLINK_SKIP: int # linux 2.0 to 2.6.12 (EOL August 2005)
- # NETLINK_TAPBASE: int # linux 2.2 to 2.6.12 (EOL August 2005)
- # NETLINK_TCPDIAG: int # linux 2.6.0 to 2.6.13 (EOL December 2005)
- # NETLINK_W1: int # linux 2.6.13 to 2.6.17 (EOL October 2006)
+ # NETLINK_ARPD: Final[int] # linux 2.0 to 2.6.12 (EOL August 2005)
+ # NETLINK_ROUTE6: Final[int] # linux 2.2 to 2.6.12 (EOL August 2005)
+ # NETLINK_SKIP: Final[int] # linux 2.0 to 2.6.12 (EOL August 2005)
+ # NETLINK_TAPBASE: Final[int] # linux 2.2 to 2.6.12 (EOL August 2005)
+ # NETLINK_TCPDIAG: Final[int] # linux 2.6.0 to 2.6.13 (EOL December 2005)
+ # NETLINK_W1: Final[int] # linux 2.6.13 to 2.6.17 (EOL October 2006)
if sys.platform == "darwin":
- PF_SYSTEM: int
- SYSPROTO_CONTROL: int
+ PF_SYSTEM: Final[int]
+ SYSPROTO_CONTROL: Final[int]
if sys.platform != "darwin" and sys.platform != "linux":
- AF_BLUETOOTH: int
+ AF_BLUETOOTH: Final[int]
if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux":
# Linux and some BSD support is explicit in the docs
# Windows and macOS do not support in practice
- BTPROTO_HCI: int
- BTPROTO_L2CAP: int
- BTPROTO_SCO: int # not in FreeBSD
+ BTPROTO_HCI: Final[int]
+ BTPROTO_L2CAP: Final[int]
+ BTPROTO_SCO: Final[int] # not in FreeBSD
if sys.platform != "darwin" and sys.platform != "linux":
- BTPROTO_RFCOMM: int
+ BTPROTO_RFCOMM: Final[int]
if sys.platform == "linux":
- UDPLITE_RECV_CSCOV: int
- UDPLITE_SEND_CSCOV: int
+ UDPLITE_RECV_CSCOV: Final[int]
+ UDPLITE_SEND_CSCOV: Final[int]
# --------------------
# Documented under socket.shutdown
# --------------------
-SHUT_RD: int
-SHUT_RDWR: int
-SHUT_WR: int
+SHUT_RD: Final[int]
+SHUT_RDWR: Final[int]
+SHUT_WR: Final[int]
# --------------------
# Undocumented constants
# --------------------
# Undocumented address families
-AF_APPLETALK: int
-AF_DECnet: int
-AF_IPX: int
-AF_SNA: int
+AF_APPLETALK: Final[int]
+AF_DECnet: Final[int]
+AF_IPX: Final[int]
+AF_SNA: Final[int]
if sys.platform != "win32":
- AF_ROUTE: int
+ AF_ROUTE: Final[int]
if sys.platform == "darwin":
- AF_SYSTEM: int
+ AF_SYSTEM: Final[int]
if sys.platform != "darwin":
- AF_IRDA: int
+ AF_IRDA: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
- AF_ASH: int
- AF_ATMPVC: int
- AF_ATMSVC: int
- AF_AX25: int
- AF_BRIDGE: int
- AF_ECONET: int
- AF_KEY: int
- AF_LLC: int
- AF_NETBEUI: int
- AF_NETROM: int
- AF_PPPOX: int
- AF_ROSE: int
- AF_SECURITY: int
- AF_WANPIPE: int
- AF_X25: int
+ AF_ASH: Final[int]
+ AF_ATMPVC: Final[int]
+ AF_ATMSVC: Final[int]
+ AF_AX25: Final[int]
+ AF_BRIDGE: Final[int]
+ AF_ECONET: Final[int]
+ AF_KEY: Final[int]
+ AF_LLC: Final[int]
+ AF_NETBEUI: Final[int]
+ AF_NETROM: Final[int]
+ AF_PPPOX: Final[int]
+ AF_ROSE: Final[int]
+ AF_SECURITY: Final[int]
+ AF_WANPIPE: Final[int]
+ AF_X25: Final[int]
# Miscellaneous undocumented
if sys.platform != "win32" and sys.platform != "linux":
- LOCAL_PEERCRED: int
+ LOCAL_PEERCRED: Final[int]
if sys.platform != "win32" and sys.platform != "darwin":
# Defined in linux socket.h, but this isn't always present for
# some reason.
- IPX_TYPE: int
+ IPX_TYPE: Final[int]
# ===== Classes =====
@@ -800,10 +800,10 @@ class socket:
"""the socket timeout"""
if sys.platform == "win32":
def __init__(
- self, family: int = ..., type: int = ..., proto: int = ..., fileno: SupportsIndex | bytes | None = ...
+ self, family: int = ..., type: int = ..., proto: int = ..., fileno: SupportsIndex | bytes | None = None
) -> None: ...
else:
- def __init__(self, family: int = ..., type: int = ..., proto: int = ..., fileno: SupportsIndex | None = ...) -> None: ...
+ def __init__(self, family: int = ..., type: int = ..., proto: int = ..., fileno: SupportsIndex | None = None) -> None: ...
def bind(self, address: _Address, /) -> None:
"""bind(address)
@@ -907,7 +907,7 @@ class socket:
connections. If not specified, a default reasonable value is chosen.
"""
- def recv(self, bufsize: int, flags: int = ..., /) -> bytes:
+ def recv(self, bufsize: int, flags: int = 0, /) -> bytes:
"""recv(buffersize[, flags]) -> data
Receive up to buffersize bytes from the socket. For the optional flags
@@ -916,13 +916,13 @@ class socket:
the remote end is closed and all data is read, return the empty string.
"""
- def recvfrom(self, bufsize: int, flags: int = ..., /) -> tuple[bytes, _RetAddress]:
+ def recvfrom(self, bufsize: int, flags: int = 0, /) -> tuple[bytes, _RetAddress]:
"""recvfrom(buffersize[, flags]) -> (data, address info)
Like recv(buffersize, flags) but also return the sender's address info.
"""
if sys.platform != "win32":
- def recvmsg(self, bufsize: int, ancbufsize: int = ..., flags: int = ..., /) -> tuple[bytes, list[_CMSG], int, Any]:
+ def recvmsg(self, bufsize: int, ancbufsize: int = 0, flags: int = 0, /) -> tuple[bytes, list[_CMSG], int, Any]:
"""recvmsg(bufsize[, ancbufsize[, flags]]) -> (data, ancdata, msg_flags, address)
Receive normal data (up to bufsize bytes) and ancillary data from the
@@ -953,7 +953,7 @@ class socket:
"""
def recvmsg_into(
- self, buffers: Iterable[WriteableBuffer], ancbufsize: int = ..., flags: int = ..., /
+ self, buffers: Iterable[WriteableBuffer], ancbufsize: int = 0, flags: int = 0, /
) -> tuple[int, list[_CMSG], int, Any]:
"""recvmsg_into(buffers[, ancbufsize[, flags]]) -> (nbytes, ancdata, msg_flags, address)
@@ -988,13 +988,13 @@ class socket:
SCM_RIGHTS mechanism.
"""
- def recvfrom_into(self, buffer: WriteableBuffer, nbytes: int = ..., flags: int = ...) -> tuple[int, _RetAddress]:
+ def recvfrom_into(self, buffer: WriteableBuffer, nbytes: int = 0, flags: int = 0) -> tuple[int, _RetAddress]:
"""recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)
Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.
"""
- def recv_into(self, buffer: WriteableBuffer, nbytes: int = ..., flags: int = ...) -> int:
+ def recv_into(self, buffer: WriteableBuffer, nbytes: int = 0, flags: int = 0) -> int:
"""recv_into(buffer, [nbytes[, flags]]) -> nbytes_read
A version of recv() that stores its data into a buffer rather than creating
@@ -1004,7 +1004,7 @@ class socket:
See recv() for documentation about the flags.
"""
- def send(self, data: ReadableBuffer, flags: int = ..., /) -> int:
+ def send(self, data: ReadableBuffer, flags: int = 0, /) -> int:
"""send(data[, flags]) -> count
Send a data string to the socket. For the optional flags
@@ -1012,7 +1012,7 @@ class socket:
sent; this may be less than len(data) if the network is busy.
"""
- def sendall(self, data: ReadableBuffer, flags: int = ..., /) -> None:
+ def sendall(self, data: ReadableBuffer, flags: int = 0, /) -> None:
"""sendall(data[, flags])
Send a data string to the socket. For the optional flags
@@ -1036,8 +1036,8 @@ class socket:
self,
buffers: Iterable[ReadableBuffer],
ancdata: Iterable[_CMSGArg] = ...,
- flags: int = ...,
- address: _Address | None = ...,
+ flags: int = 0,
+ address: _Address | None = None,
/,
) -> int:
"""sendmsg(buffers[, ancdata[, flags[, address]]]) -> count
@@ -1058,7 +1058,7 @@ class socket:
"""
if sys.platform == "linux":
def sendmsg_afalg(
- self, msg: Iterable[ReadableBuffer] = ..., *, op: int, iv: Any = ..., assoclen: int = ..., flags: int = ...
+ self, msg: Iterable[ReadableBuffer] = ..., *, op: int, iv: Any = ..., assoclen: int = ..., flags: int = 0
) -> int:
"""sendmsg_afalg([msg], *, op[, iv[, assoclen[, flags=MSG_MORE]]])
@@ -1133,12 +1133,7 @@ def dup(fd: SupportsIndex, /) -> int:
# the 5th tuple item is an address
def getaddrinfo(
- host: bytes | str | None,
- port: bytes | str | int | None,
- family: int = ...,
- type: int = ...,
- proto: int = ...,
- flags: int = ...,
+ host: bytes | str | None, port: bytes | str | int | None, family: int = ..., type: int = 0, proto: int = 0, flags: int = 0
) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes]]]:
"""getaddrinfo(host, port [, family, type, proto, flags])
-> list of (family, type, proto, canonname, sockaddr)
@@ -1278,7 +1273,7 @@ if sys.platform != "win32":
range of values.
"""
- def socketpair(family: int = ..., type: int = ..., proto: int = ..., /) -> tuple[socket, socket]:
+ def socketpair(family: int = ..., type: int = ..., proto: int = 0, /) -> tuple[socket, socket]:
"""socketpair([family[, type [, proto]]]) -> (socket object, socket object)
Create a pair of socket objects from the sockets returned by the platform
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_ssl.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_ssl.pyi
index 179dc961b2c09..d700e8f8c55b3 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_ssl.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_ssl.pyi
@@ -16,14 +16,15 @@ from ssl import (
SSLWantWriteError as SSLWantWriteError,
SSLZeroReturnError as SSLZeroReturnError,
)
-from typing import Any, ClassVar, Literal, TypedDict, final, overload
-from typing_extensions import NotRequired, Self, TypeAlias
+from typing import Any, ClassVar, Final, Literal, TypedDict, final, overload, type_check_only
+from typing_extensions import NotRequired, Self, TypeAlias, deprecated
_PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray
_PCTRTT: TypeAlias = tuple[tuple[str, str], ...]
_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...]
_PeerCertRetDictType: TypeAlias = dict[str, str | _PCTRTTT | _PCTRTT]
+@type_check_only
class _Cipher(TypedDict):
aead: bool
alg_bits: int
@@ -37,6 +38,7 @@ class _Cipher(TypedDict):
strength_bits: int
symmetric: str
+@type_check_only
class _CertInfo(TypedDict):
subject: tuple[tuple[tuple[str, str], ...], ...]
issuer: tuple[tuple[tuple[str, str], ...], ...]
@@ -60,6 +62,7 @@ def RAND_bytes(n: int, /) -> bytes:
"""Generate n cryptographically strong pseudo-random bytes."""
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.6; removed in Python 3.12. Use `ssl.RAND_bytes()` instead.")
def RAND_pseudo_bytes(n: int, /) -> tuple[bytes, bool]:
"""Generate n pseudo-random bytes.
@@ -252,135 +255,134 @@ if sys.version_info < (3, 12):
err_names_to_codes: dict[str, tuple[int, int]]
lib_codes_to_names: dict[int, str]
-_DEFAULT_CIPHERS: str
+_DEFAULT_CIPHERS: Final[str]
# SSL error numbers
-SSL_ERROR_ZERO_RETURN: int
-SSL_ERROR_WANT_READ: int
-SSL_ERROR_WANT_WRITE: int
-SSL_ERROR_WANT_X509_LOOKUP: int
-SSL_ERROR_SYSCALL: int
-SSL_ERROR_SSL: int
-SSL_ERROR_WANT_CONNECT: int
-SSL_ERROR_EOF: int
-SSL_ERROR_INVALID_ERROR_CODE: int
+SSL_ERROR_ZERO_RETURN: Final = 6
+SSL_ERROR_WANT_READ: Final = 2
+SSL_ERROR_WANT_WRITE: Final = 3
+SSL_ERROR_WANT_X509_LOOKUP: Final = 4
+SSL_ERROR_SYSCALL: Final = 5
+SSL_ERROR_SSL: Final = 1
+SSL_ERROR_WANT_CONNECT: Final = 7
+SSL_ERROR_EOF: Final = 8
+SSL_ERROR_INVALID_ERROR_CODE: Final = 10
# verify modes
-CERT_NONE: int
-CERT_OPTIONAL: int
-CERT_REQUIRED: int
+CERT_NONE: Final = 0
+CERT_OPTIONAL: Final = 1
+CERT_REQUIRED: Final = 2
# verify flags
-VERIFY_DEFAULT: int
-VERIFY_CRL_CHECK_LEAF: int
-VERIFY_CRL_CHECK_CHAIN: int
-VERIFY_X509_STRICT: int
-VERIFY_X509_TRUSTED_FIRST: int
+VERIFY_DEFAULT: Final = 0
+VERIFY_CRL_CHECK_LEAF: Final = 0x4
+VERIFY_CRL_CHECK_CHAIN: Final = 0x8
+VERIFY_X509_STRICT: Final = 0x20
+VERIFY_X509_TRUSTED_FIRST: Final = 0x8000
if sys.version_info >= (3, 10):
- VERIFY_ALLOW_PROXY_CERTS: int
- VERIFY_X509_PARTIAL_CHAIN: int
+ VERIFY_ALLOW_PROXY_CERTS: Final = 0x40
+ VERIFY_X509_PARTIAL_CHAIN: Final = 0x80000
# alert descriptions
-ALERT_DESCRIPTION_CLOSE_NOTIFY: int
-ALERT_DESCRIPTION_UNEXPECTED_MESSAGE: int
-ALERT_DESCRIPTION_BAD_RECORD_MAC: int
-ALERT_DESCRIPTION_RECORD_OVERFLOW: int
-ALERT_DESCRIPTION_DECOMPRESSION_FAILURE: int
-ALERT_DESCRIPTION_HANDSHAKE_FAILURE: int
-ALERT_DESCRIPTION_BAD_CERTIFICATE: int
-ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: int
-ALERT_DESCRIPTION_CERTIFICATE_REVOKED: int
-ALERT_DESCRIPTION_CERTIFICATE_EXPIRED: int
-ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN: int
-ALERT_DESCRIPTION_ILLEGAL_PARAMETER: int
-ALERT_DESCRIPTION_UNKNOWN_CA: int
-ALERT_DESCRIPTION_ACCESS_DENIED: int
-ALERT_DESCRIPTION_DECODE_ERROR: int
-ALERT_DESCRIPTION_DECRYPT_ERROR: int
-ALERT_DESCRIPTION_PROTOCOL_VERSION: int
-ALERT_DESCRIPTION_INSUFFICIENT_SECURITY: int
-ALERT_DESCRIPTION_INTERNAL_ERROR: int
-ALERT_DESCRIPTION_USER_CANCELLED: int
-ALERT_DESCRIPTION_NO_RENEGOTIATION: int
-ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: int
-ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE: int
-ALERT_DESCRIPTION_UNRECOGNIZED_NAME: int
-ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE: int
-ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE: int
-ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY: int
+ALERT_DESCRIPTION_CLOSE_NOTIFY: Final = 0
+ALERT_DESCRIPTION_UNEXPECTED_MESSAGE: Final = 10
+ALERT_DESCRIPTION_BAD_RECORD_MAC: Final = 20
+ALERT_DESCRIPTION_RECORD_OVERFLOW: Final = 22
+ALERT_DESCRIPTION_DECOMPRESSION_FAILURE: Final = 30
+ALERT_DESCRIPTION_HANDSHAKE_FAILURE: Final = 40
+ALERT_DESCRIPTION_BAD_CERTIFICATE: Final = 42
+ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: Final = 43
+ALERT_DESCRIPTION_CERTIFICATE_REVOKED: Final = 44
+ALERT_DESCRIPTION_CERTIFICATE_EXPIRED: Final = 45
+ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN: Final = 46
+ALERT_DESCRIPTION_ILLEGAL_PARAMETER: Final = 47
+ALERT_DESCRIPTION_UNKNOWN_CA: Final = 48
+ALERT_DESCRIPTION_ACCESS_DENIED: Final = 49
+ALERT_DESCRIPTION_DECODE_ERROR: Final = 50
+ALERT_DESCRIPTION_DECRYPT_ERROR: Final = 51
+ALERT_DESCRIPTION_PROTOCOL_VERSION: Final = 70
+ALERT_DESCRIPTION_INSUFFICIENT_SECURITY: Final = 71
+ALERT_DESCRIPTION_INTERNAL_ERROR: Final = 80
+ALERT_DESCRIPTION_USER_CANCELLED: Final = 90
+ALERT_DESCRIPTION_NO_RENEGOTIATION: Final = 100
+ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: Final = 110
+ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE: Final = 111
+ALERT_DESCRIPTION_UNRECOGNIZED_NAME: Final = 112
+ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE: Final = 113
+ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE: Final = 114
+ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY: Final = 115
# protocol versions
-PROTOCOL_SSLv23: int
-PROTOCOL_TLS: int
-PROTOCOL_TLS_CLIENT: int
-PROTOCOL_TLS_SERVER: int
-PROTOCOL_TLSv1: int
-PROTOCOL_TLSv1_1: int
-PROTOCOL_TLSv1_2: int
+PROTOCOL_SSLv23: Final = 2
+PROTOCOL_TLS: Final = 2
+PROTOCOL_TLS_CLIENT: Final = 16
+PROTOCOL_TLS_SERVER: Final = 17
+PROTOCOL_TLSv1: Final = 3
+PROTOCOL_TLSv1_1: Final = 4
+PROTOCOL_TLSv1_2: Final = 5
# protocol options
-OP_ALL: int
-OP_NO_SSLv2: int
-OP_NO_SSLv3: int
-OP_NO_TLSv1: int
-OP_NO_TLSv1_1: int
-OP_NO_TLSv1_2: int
-OP_NO_TLSv1_3: int
-OP_CIPHER_SERVER_PREFERENCE: int
-OP_SINGLE_DH_USE: int
-OP_NO_TICKET: int
-OP_SINGLE_ECDH_USE: int
-OP_NO_COMPRESSION: int
-OP_ENABLE_MIDDLEBOX_COMPAT: int
-OP_NO_RENEGOTIATION: int
+OP_ALL: Final = 0x80000050
+OP_NO_SSLv2: Final = 0x0
+OP_NO_SSLv3: Final = 0x2000000
+OP_NO_TLSv1: Final = 0x4000000
+OP_NO_TLSv1_1: Final = 0x10000000
+OP_NO_TLSv1_2: Final = 0x8000000
+OP_NO_TLSv1_3: Final = 0x20000000
+OP_CIPHER_SERVER_PREFERENCE: Final = 0x400000
+OP_SINGLE_DH_USE: Final = 0x0
+OP_NO_TICKET: Final = 0x4000
+OP_SINGLE_ECDH_USE: Final = 0x0
+OP_NO_COMPRESSION: Final = 0x20000
+OP_ENABLE_MIDDLEBOX_COMPAT: Final = 0x100000
+OP_NO_RENEGOTIATION: Final = 0x40000000
if sys.version_info >= (3, 11) or sys.platform == "linux":
- OP_IGNORE_UNEXPECTED_EOF: int
+ OP_IGNORE_UNEXPECTED_EOF: Final = 0x80
if sys.version_info >= (3, 12):
- OP_LEGACY_SERVER_CONNECT: int
- OP_ENABLE_KTLS: int
+ OP_LEGACY_SERVER_CONNECT: Final = 0x4
+ OP_ENABLE_KTLS: Final = 0x8
# host flags
-HOSTFLAG_ALWAYS_CHECK_SUBJECT: int
-HOSTFLAG_NEVER_CHECK_SUBJECT: int
-HOSTFLAG_NO_WILDCARDS: int
-HOSTFLAG_NO_PARTIAL_WILDCARDS: int
-HOSTFLAG_MULTI_LABEL_WILDCARDS: int
-HOSTFLAG_SINGLE_LABEL_SUBDOMAINS: int
+HOSTFLAG_ALWAYS_CHECK_SUBJECT: Final = 0x1
+HOSTFLAG_NEVER_CHECK_SUBJECT: Final = 0x20
+HOSTFLAG_NO_WILDCARDS: Final = 0x2
+HOSTFLAG_NO_PARTIAL_WILDCARDS: Final = 0x4
+HOSTFLAG_MULTI_LABEL_WILDCARDS: Final = 0x8
+HOSTFLAG_SINGLE_LABEL_SUBDOMAINS: Final = 0x10
if sys.version_info >= (3, 10):
# certificate file types
- # Typed as Literal so the overload on Certificate.public_bytes can work properly.
- ENCODING_PEM: Literal[1]
- ENCODING_DER: Literal[2]
+ ENCODING_PEM: Final = 1
+ ENCODING_DER: Final = 2
# protocol versions
-PROTO_MINIMUM_SUPPORTED: int
-PROTO_MAXIMUM_SUPPORTED: int
-PROTO_SSLv3: int
-PROTO_TLSv1: int
-PROTO_TLSv1_1: int
-PROTO_TLSv1_2: int
-PROTO_TLSv1_3: int
+PROTO_MINIMUM_SUPPORTED: Final = -2
+PROTO_MAXIMUM_SUPPORTED: Final = -1
+PROTO_SSLv3: Final[int]
+PROTO_TLSv1: Final[int]
+PROTO_TLSv1_1: Final[int]
+PROTO_TLSv1_2: Final[int]
+PROTO_TLSv1_3: Final[int]
# feature support
-HAS_SNI: bool
-HAS_TLS_UNIQUE: bool
-HAS_ECDH: bool
-HAS_NPN: bool
+HAS_SNI: Final[bool]
+HAS_TLS_UNIQUE: Final[bool]
+HAS_ECDH: Final[bool]
+HAS_NPN: Final[bool]
if sys.version_info >= (3, 13):
- HAS_PSK: bool
-HAS_ALPN: bool
-HAS_SSLv2: bool
-HAS_SSLv3: bool
-HAS_TLSv1: bool
-HAS_TLSv1_1: bool
-HAS_TLSv1_2: bool
-HAS_TLSv1_3: bool
+ HAS_PSK: Final[bool]
+HAS_ALPN: Final[bool]
+HAS_SSLv2: Final[bool]
+HAS_SSLv3: Final[bool]
+HAS_TLSv1: Final[bool]
+HAS_TLSv1_1: Final[bool]
+HAS_TLSv1_2: Final[bool]
+HAS_TLSv1_3: Final[bool]
if sys.version_info >= (3, 14):
- HAS_PHA: bool
+ HAS_PHA: Final[bool]
# version info
-OPENSSL_VERSION_NUMBER: int
-OPENSSL_VERSION_INFO: tuple[int, int, int, int, int]
-OPENSSL_VERSION: str
-_OPENSSL_API_VERSION: tuple[int, int, int, int, int]
+OPENSSL_VERSION_NUMBER: Final[int]
+OPENSSL_VERSION_INFO: Final[tuple[int, int, int, int, int]]
+OPENSSL_VERSION: Final[str]
+_OPENSSL_API_VERSION: Final[tuple[int, int, int, int, int]]
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_tkinter.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_tkinter.pyi
index 2663e7552c0c3..c0683e900c142 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_tkinter.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_tkinter.pyi
@@ -1,7 +1,7 @@
import sys
from collections.abc import Callable
from typing import Any, ClassVar, Final, final
-from typing_extensions import TypeAlias
+from typing_extensions import TypeAlias, deprecated
# _tkinter is meant to be only used internally by tkinter, but some tkinter
# functions e.g. return _tkinter.Tcl_Obj objects. Tcl_Obj represents a Tcl
@@ -87,6 +87,7 @@ class TkappType:
def record(self, script, /): ...
def setvar(self, *ags, **kwargs): ...
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.9; removed in Python 3.11. Use `splitlist()` instead.")
def split(self, arg, /): ...
def splitlist(self, arg, /): ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_winapi.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_winapi.pyi
index 29c121859d6ce..14140f58a76d6 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_winapi.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_winapi.pyi
@@ -172,6 +172,9 @@ if sys.platform == "win32":
ERROR_ACCESS_DENIED: Final = 5
ERROR_PRIVILEGE_NOT_HELD: Final = 1314
+ if sys.version_info >= (3, 14):
+ COPY_FILE_DIRECTORY: Final = 0x00000080
+
def CloseHandle(handle: int, /) -> None:
"""Close handle."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/_zstd.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/_zstd.pyi
index 99cbb8e83fb5f..2bfc6b6337bcf 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/_zstd.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/_zstd.pyi
@@ -217,7 +217,7 @@ class ZstdDict:
1. Prefix is compatible with long distance matching, while dictionary is not.
2. It only works for the first frame, then the compressor/decompressor will
return to no prefix state.
- 3. When decompressing, must use the same prefix as when compressing."
+ 3. When decompressing, must use the same prefix as when compressing.
"""
@property
@@ -239,11 +239,13 @@ class ZstdDict:
@property
def dict_id(self) -> int:
- """the Zstandard dictionary, an int between 0 and 2**32.
+ """The Zstandard dictionary, an int between 0 and 2**32.
- A non-zero value represents an ordinary Zstandard dictionary, conforming to the standardised format.
+ A non-zero value represents an ordinary Zstandard dictionary,
+ conforming to the standardised format.
- The special value '0' means a 'raw content' dictionary,without any restrictions on format or content.
+ A value of zero indicates a 'raw content' dictionary,
+ without any restrictions on format or content.
"""
class ZstdError(Exception):
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/array.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/array.pyi
index fe537bfe46621..947cc6a1ccb12 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/array.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/array.pyi
@@ -9,11 +9,14 @@ from _typeshed import ReadableBuffer, SupportsRead, SupportsWrite
from collections.abc import Iterable, MutableSequence
from types import GenericAlias
from typing import Any, ClassVar, Literal, SupportsIndex, TypeVar, overload
-from typing_extensions import Self, TypeAlias
+from typing_extensions import Self, TypeAlias, deprecated
_IntTypeCode: TypeAlias = Literal["b", "B", "h", "H", "i", "I", "l", "L", "q", "Q"]
_FloatTypeCode: TypeAlias = Literal["f", "d"]
-_UnicodeTypeCode: TypeAlias = Literal["u"]
+if sys.version_info >= (3, 13):
+ _UnicodeTypeCode: TypeAlias = Literal["u", "w"]
+else:
+ _UnicodeTypeCode: TypeAlias = Literal["u"]
_TypeCode: TypeAlias = _IntTypeCode | _FloatTypeCode | _UnicodeTypeCode
_T = TypeVar("_T", int, float, str)
@@ -95,10 +98,23 @@ class array(MutableSequence[_T]):
def __new__(
cls: type[array[float]], typecode: _FloatTypeCode, initializer: bytes | bytearray | Iterable[float] = ..., /
) -> array[float]: ...
- @overload
- def __new__(
- cls: type[array[str]], typecode: _UnicodeTypeCode, initializer: bytes | bytearray | Iterable[str] = ..., /
- ) -> array[str]: ...
+ if sys.version_info >= (3, 13):
+ @overload
+ def __new__(
+ cls: type[array[str]], typecode: Literal["w"], initializer: bytes | bytearray | Iterable[str] = ..., /
+ ) -> array[str]: ...
+ @overload
+ @deprecated("Deprecated since Python 3.3; will be removed in Python 3.16. Use 'w' typecode instead.")
+ def __new__(
+ cls: type[array[str]], typecode: Literal["u"], initializer: bytes | bytearray | Iterable[str] = ..., /
+ ) -> array[str]: ...
+ else:
+ @overload
+ @deprecated("Deprecated since Python 3.3; will be removed in Python 3.16.")
+ def __new__(
+ cls: type[array[str]], typecode: Literal["u"], initializer: bytes | bytearray | Iterable[str] = ..., /
+ ) -> array[str]: ...
+
@overload
def __new__(cls, typecode: str, initializer: Iterable[_T], /) -> Self: ...
@overload
@@ -181,6 +197,9 @@ class array(MutableSequence[_T]):
unicode string from an array of some other type.
"""
__hash__: ClassVar[None] # type: ignore[assignment]
+ def __contains__(self, value: object, /) -> bool:
+ """Return bool(key in self)."""
+
def __len__(self) -> int:
"""Return len(self)."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/ast.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/ast.pyi
index 262ea22b9d8e2..0f66829027d90 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/ast.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/ast.pyi
@@ -33,7 +33,7 @@ from _ast import (
)
from _typeshed import ReadableBuffer, Unused
from collections.abc import Iterable, Iterator, Sequence
-from typing import Any, ClassVar, Generic, Literal, TypedDict, TypeVar as _TypeVar, overload
+from typing import Any, ClassVar, Generic, Literal, TypedDict, TypeVar as _TypeVar, overload, type_check_only
from typing_extensions import Self, Unpack, deprecated
if sys.version_info >= (3, 13):
@@ -43,6 +43,7 @@ if sys.version_info >= (3, 13):
_EndPositionT = typing_extensions.TypeVar("_EndPositionT", int, int | None, default=int | None)
# Corresponds to the names in the `_attributes` class variable which is non-empty in certain AST nodes
+@type_check_only
class _Attributes(TypedDict, Generic[_EndPositionT], total=False):
lineno: int
col_offset: int
@@ -1330,19 +1331,21 @@ class Constant(expr):
kind: str | None
if sys.version_info < (3, 14):
# Aliases for value, for backwards compatibility
- @deprecated("Will be removed in Python 3.14; use value instead")
@property
+ @deprecated("Will be removed in Python 3.14. Use `value` instead.")
def n(self) -> _ConstantValue:
"""Deprecated. Use value instead."""
@n.setter
+ @deprecated("Will be removed in Python 3.14. Use `value` instead.")
def n(self, value: _ConstantValue) -> None: ...
- @deprecated("Will be removed in Python 3.14; use value instead")
@property
+ @deprecated("Will be removed in Python 3.14. Use `value` instead.")
def s(self) -> _ConstantValue:
"""Deprecated. Use value instead."""
@s.setter
+ @deprecated("Will be removed in Python 3.14. Use `value` instead.")
def s(self, value: _ConstantValue) -> None: ...
def __init__(self, value: _ConstantValue, kind: str | None = None, **kwargs: Unpack[_Attributes]) -> None: ...
@@ -2121,8 +2124,14 @@ if sys.version_info >= (3, 12):
) -> Self:
"""Return a copy of the AST node with new values for the specified fields."""
-class _ABC(type):
- def __init__(cls, *args: Unused) -> None: ...
+if sys.version_info >= (3, 14):
+ @type_check_only
+ class _ABC(type):
+ def __init__(cls, *args: Unused) -> None: ...
+
+else:
+ class _ABC(type):
+ def __init__(cls, *args: Unused) -> None: ...
if sys.version_info < (3, 14):
@deprecated("Replaced by ast.Constant; removed in Python 3.14")
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/coroutines.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/coroutines.pyi
index 2908051fdd397..d1db48fb9cfad 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/coroutines.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/coroutines.pyi
@@ -1,7 +1,7 @@
import sys
from collections.abc import Awaitable, Callable, Coroutine
from typing import Any, TypeVar, overload
-from typing_extensions import ParamSpec, TypeGuard, TypeIs
+from typing_extensions import ParamSpec, TypeGuard, TypeIs, deprecated
# Keep asyncio.__all__ updated with any changes to __all__ here
if sys.version_info >= (3, 11):
@@ -14,6 +14,7 @@ _FunctionT = TypeVar("_FunctionT", bound=Callable[..., Any])
_P = ParamSpec("_P")
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `async def` instead.")
def coroutine(func: _FunctionT) -> _FunctionT:
"""Decorator to mark coroutines.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/events.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/events.pyi
index 789923832dc7e..de3e1dec92d2e 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/events.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/events.pyi
@@ -14,7 +14,7 @@ from collections.abc import Callable, Sequence
from concurrent.futures import Executor
from contextvars import Context
from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket
-from typing import IO, Any, Literal, Protocol, TypeVar, overload
+from typing import IO, Any, Literal, Protocol, TypeVar, overload, type_check_only
from typing_extensions import Self, TypeAlias, TypeVarTuple, Unpack, deprecated
from . import _AwaitableLike, _CoroutineLike
@@ -70,6 +70,7 @@ _ExceptionHandler: TypeAlias = Callable[[AbstractEventLoop, _Context], object]
_ProtocolFactory: TypeAlias = Callable[[], BaseProtocol]
_SSLContext: TypeAlias = bool | None | ssl.SSLContext
+@type_check_only
class _TaskFactory(Protocol):
def __call__(self, loop: AbstractEventLoop, factory: _CoroutineLike[_T], /) -> Future[_T]: ...
@@ -936,6 +937,9 @@ class AbstractEventLoop:
async def shutdown_default_executor(self) -> None:
"""Schedule the shutdown of the default executor."""
+# This class does not exist at runtime, but stubtest complains if it's marked as
+# @type_check_only because it has an alias that does exist at runtime. See mypy#19568.
+# @type_check_only
class _AbstractEventLoopPolicy:
"""Abstract policy for accessing the event loop."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/format_helpers.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/format_helpers.pyi
index d9550f113420c..9213dcbd43196 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/format_helpers.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/format_helpers.pyi
@@ -3,9 +3,10 @@ import sys
import traceback
from collections.abc import Iterable
from types import FrameType, FunctionType
-from typing import Any, overload
+from typing import Any, overload, type_check_only
from typing_extensions import TypeAlias
+@type_check_only
class _HasWrapper:
__wrapper__: _HasWrapper | FunctionType
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/streams.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/streams.pyi
index d889ff09605fc..7c145f01cbb7a 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/streams.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/streams.pyi
@@ -3,7 +3,7 @@ import sys
from _typeshed import ReadableBuffer, StrPath
from collections.abc import Awaitable, Callable, Iterable, Sequence, Sized
from types import ModuleType
-from typing import Any, Protocol, SupportsIndex
+from typing import Any, Protocol, SupportsIndex, type_check_only
from typing_extensions import Self, TypeAlias
from . import events, protocols, transports
@@ -25,6 +25,7 @@ else:
_ClientConnectedCallback: TypeAlias = Callable[[StreamReader, StreamWriter], Awaitable[None] | None]
+@type_check_only
class _ReaduntilBuffer(ReadableBuffer, Sized, Protocol): ...
if sys.version_info >= (3, 10):
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/tasks.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/tasks.pyi
index 292d0f759610c..ebe927041ae0a 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/tasks.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/tasks.pyi
@@ -10,7 +10,7 @@ from _asyncio import (
_unregister_task as _unregister_task,
)
from collections.abc import AsyncIterator, Awaitable, Coroutine, Generator, Iterable, Iterator
-from typing import Any, Literal, Protocol, TypeVar, overload
+from typing import Any, Literal, Protocol, TypeVar, overload, type_check_only
from typing_extensions import TypeAlias
from . import _CoroutineLike
@@ -89,6 +89,7 @@ FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION
ALL_COMPLETED = concurrent.futures.ALL_COMPLETED
if sys.version_info >= (3, 13):
+ @type_check_only
class _SyncAndAsyncIterator(Iterator[_T_co], AsyncIterator[_T_co], Protocol[_T_co]): ...
def as_completed(fs: Iterable[_FutureLike[_T]], *, timeout: float | None = None) -> _SyncAndAsyncIterator[Future[_T]]:
@@ -741,6 +742,7 @@ elif sys.version_info >= (3, 12):
if sys.version_info >= (3, 12):
_TaskT_co = TypeVar("_TaskT_co", bound=Task[Any], covariant=True)
+ @type_check_only
class _CustomTaskConstructor(Protocol[_TaskT_co]):
def __call__(
self,
@@ -753,6 +755,7 @@ if sys.version_info >= (3, 12):
eager_start: bool,
) -> _TaskT_co: ...
+ @type_check_only
class _EagerTaskFactoryType(Protocol[_TaskT_co]):
def __call__(
self,
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/trsock.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/trsock.pyi
index 0832062a9a824..c78f931c8555e 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/trsock.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/asyncio/trsock.pyi
@@ -5,7 +5,7 @@ from builtins import type as Type # alias to avoid name clashes with property n
from collections.abc import Iterable
from types import TracebackType
from typing import Any, BinaryIO, NoReturn, overload
-from typing_extensions import TypeAlias
+from typing_extensions import TypeAlias, deprecated
# These are based in socket, maybe move them out into _typeshed.pyi or such
_Address: TypeAlias = socket._Address
@@ -49,53 +49,82 @@ class TransportSocket:
def setblocking(self, flag: bool) -> None: ...
if sys.version_info < (3, 11):
def _na(self, what: str) -> None: ...
+ @deprecated("Removed in Python 3.11")
def accept(self) -> tuple[socket.socket, _RetAddress]: ...
+ @deprecated("Removed in Python 3.11")
def connect(self, address: _Address) -> None: ...
+ @deprecated("Removed in Python 3.11")
def connect_ex(self, address: _Address) -> int: ...
+ @deprecated("Removed in Python 3.11")
def bind(self, address: _Address) -> None: ...
if sys.platform == "win32":
+ @deprecated("Removed in Python 3.11")
def ioctl(self, control: int, option: int | tuple[int, int, int] | bool) -> None: ...
else:
+ @deprecated("Removed in Python 3.11")
def ioctl(self, control: int, option: int | tuple[int, int, int] | bool) -> NoReturn: ...
+ @deprecated("Removed in Python 3.11")
def listen(self, backlog: int = ..., /) -> None: ...
+ @deprecated("Removed in Python 3.11")
def makefile(self) -> BinaryIO: ...
+ @deprecated("Rmoved in Python 3.11")
def sendfile(self, file: BinaryIO, offset: int = ..., count: int | None = ...) -> int: ...
+ @deprecated("Removed in Python 3.11")
def close(self) -> None: ...
+ @deprecated("Removed in Python 3.11")
def detach(self) -> int: ...
if sys.platform == "linux":
+ @deprecated("Removed in Python 3.11")
def sendmsg_afalg(
self, msg: Iterable[ReadableBuffer] = ..., *, op: int, iv: Any = ..., assoclen: int = ..., flags: int = ...
) -> int: ...
else:
+ @deprecated("Removed in Python 3.11.")
def sendmsg_afalg(
self, msg: Iterable[ReadableBuffer] = ..., *, op: int, iv: Any = ..., assoclen: int = ..., flags: int = ...
) -> NoReturn: ...
+ @deprecated("Removed in Python 3.11.")
def sendmsg(
self, buffers: Iterable[ReadableBuffer], ancdata: Iterable[_CMSG] = ..., flags: int = ..., address: _Address = ..., /
) -> int: ...
@overload
+ @deprecated("Removed in Python 3.11.")
def sendto(self, data: ReadableBuffer, address: _Address) -> int: ...
@overload
+ @deprecated("Removed in Python 3.11.")
def sendto(self, data: ReadableBuffer, flags: int, address: _Address) -> int: ...
+ @deprecated("Removed in Python 3.11.")
def send(self, data: ReadableBuffer, flags: int = ...) -> int: ...
+ @deprecated("Removed in Python 3.11.")
def sendall(self, data: ReadableBuffer, flags: int = ...) -> None: ...
+ @deprecated("Removed in Python 3.11.")
def set_inheritable(self, inheritable: bool) -> None: ...
if sys.platform == "win32":
+ @deprecated("Removed in Python 3.11.")
def share(self, process_id: int) -> bytes: ...
else:
+ @deprecated("Removed in Python 3.11.")
def share(self, process_id: int) -> NoReturn: ...
+ @deprecated("Removed in Python 3.11.")
def recv_into(self, buffer: _WriteBuffer, nbytes: int = ..., flags: int = ...) -> int: ...
+ @deprecated("Removed in Python 3.11.")
def recvfrom_into(self, buffer: _WriteBuffer, nbytes: int = ..., flags: int = ...) -> tuple[int, _RetAddress]: ...
+ @deprecated("Removed in Python 3.11.")
def recvmsg_into(
self, buffers: Iterable[_WriteBuffer], ancbufsize: int = ..., flags: int = ..., /
) -> tuple[int, list[_CMSG], int, Any]: ...
+ @deprecated("Removed in Python 3.11.")
def recvmsg(self, bufsize: int, ancbufsize: int = ..., flags: int = ..., /) -> tuple[bytes, list[_CMSG], int, Any]: ...
+ @deprecated("Removed in Python 3.11.")
def recvfrom(self, bufsize: int, flags: int = ...) -> tuple[bytes, _RetAddress]: ...
+ @deprecated("Removed in Python 3.11.")
def recv(self, bufsize: int, flags: int = ...) -> bytes: ...
+ @deprecated("Removed in Python 3.11.")
def __enter__(self) -> socket.socket: ...
+ @deprecated("Removed in Python 3.11.")
def __exit__(
self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/bdb.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/bdb.pyi
index 2857aff0f6f0e..e9ff8da0e462d 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/bdb.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/bdb.pyi
@@ -255,13 +255,13 @@ class Bdb:
If no breakpoints are set, return an empty list.
"""
- def get_file_breaks(self, filename: str) -> list[Breakpoint]:
+ def get_file_breaks(self, filename: str) -> list[int]:
"""Return all lines with breakpoints for filename.
If no breakpoints are set, return an empty list.
"""
- def get_all_breaks(self) -> list[Breakpoint]:
+ def get_all_breaks(self) -> dict[str, list[int]]:
"""Return all breakpoints that are set."""
def get_stack(self, f: FrameType | None, t: TracebackType | None) -> tuple[list[tuple[FrameType, int]], int]:
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/binascii.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/binascii.pyi
index 9ccfc7ecc74c0..136c245253a89 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/binascii.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/binascii.pyi
@@ -2,7 +2,7 @@
import sys
from _typeshed import ReadableBuffer
-from typing_extensions import TypeAlias
+from typing_extensions import TypeAlias, deprecated
# Many functions in binascii accept buffer objects
# or ASCII-only strings.
@@ -42,15 +42,19 @@ def b2a_qp(data: ReadableBuffer, quotetabs: bool = False, istext: bool = True, h
"""
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.9; removed in Python 3.11.")
def a2b_hqx(data: _AsciiBuffer, /) -> bytes:
"""Decode .hqx coding."""
+ @deprecated("Deprecated since Python 3.9; removed in Python 3.11.")
def rledecode_hqx(data: ReadableBuffer, /) -> bytes:
"""Decode hexbin RLE-coded string."""
+ @deprecated("Deprecated since Python 3.9; removed in Python 3.11.")
def rlecode_hqx(data: ReadableBuffer, /) -> bytes:
"""Binhex RLE-code binary data."""
+ @deprecated("Deprecated since Python 3.9; removed in Python 3.11.")
def b2a_hqx(data: ReadableBuffer, /) -> bytes:
"""Encode .hqx data."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/builtins.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/builtins.pyi
index 5df63f805dfe7..5226fadaf6b93 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/builtins.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/builtins.pyi
@@ -643,6 +643,9 @@ class int:
def __index__(self) -> int:
"""Return self converted to an integer, if self is suitable for use as an index into a list."""
+ def __format__(self, format_spec: str, /) -> str:
+ """Convert to a string according to format_spec."""
+
class float:
"""Convert a string or number to a floating-point number, if possible."""
@@ -795,6 +798,9 @@ class float:
def __hash__(self) -> int: ...
def __bool__(self) -> bool:
"""True if self else False"""
+
+ def __format__(self, format_spec: str, /) -> str:
+ """Formats the float according to format_spec."""
if sys.version_info >= (3, 14):
@classmethod
def from_number(cls, number: float | SupportsIndex | SupportsFloat, /) -> Self:
@@ -873,6 +879,9 @@ class complex:
def __hash__(self) -> int: ...
def __bool__(self) -> bool:
"""True if self else False"""
+
+ def __format__(self, format_spec: str, /) -> str:
+ """Convert to a string according to format_spec."""
if sys.version_info >= (3, 11):
def __complex__(self) -> complex:
"""Convert this value to exact type complex."""
@@ -1418,6 +1427,8 @@ class str(Sequence[str]):
@overload
def __rmul__(self, value: SupportsIndex, /) -> str: ... # type: ignore[misc]
def __getnewargs__(self) -> tuple[str]: ...
+ def __format__(self, format_spec: str, /) -> str:
+ """Return a formatted version of the string as described by format_spec."""
class bytes(Sequence[int]):
"""bytes(iterable_of_ints) -> bytes
@@ -3324,6 +3335,9 @@ class property:
def __delete__(self, instance: Any, /) -> None:
"""Delete an attribute of instance."""
+# This class does not exist at runtime, but stubtest complains if it's marked as
+# @type_check_only because it has an alias that does exist at runtime. See mypy#19568.
+# @type_check_only
@final
class _NotImplementedType(Any):
__call__: None
@@ -3683,6 +3697,7 @@ def input(prompt: object = "", /) -> str:
On *nix systems, readline is used if available.
"""
+@type_check_only
class _GetItemIterable(Protocol[_T_co]):
def __getitem__(self, i: int, /) -> _T_co: ...
@@ -4121,6 +4136,7 @@ def open(
def ord(c: str | bytes | bytearray, /) -> int:
"""Return the Unicode code point for a one-character string."""
+@type_check_only
class _SupportsWriteAndFlush(SupportsWrite[_T_contra], SupportsFlush, Protocol[_T_contra]): ...
@overload
@@ -4151,12 +4167,15 @@ def print(
_E_contra = TypeVar("_E_contra", contravariant=True)
_M_contra = TypeVar("_M_contra", contravariant=True)
+@type_check_only
class _SupportsPow2(Protocol[_E_contra, _T_co]):
def __pow__(self, other: _E_contra, /) -> _T_co: ...
+@type_check_only
class _SupportsPow3NoneOnly(Protocol[_E_contra, _T_co]):
def __pow__(self, other: _E_contra, modulo: None = None, /) -> _T_co: ...
+@type_check_only
class _SupportsPow3(Protocol[_E_contra, _M_contra, _T_co]):
def __pow__(self, other: _E_contra, modulo: _M_contra, /) -> _T_co: ...
@@ -4238,9 +4257,11 @@ def repr(obj: object, /) -> str:
# and https://github.com/python/typeshed/pull/9151
# on why we don't use `SupportsRound` from `typing.pyi`
+@type_check_only
class _SupportsRound1(Protocol[_T_co]):
def __round__(self) -> _T_co: ...
+@type_check_only
class _SupportsRound2(Protocol[_T_co]):
def __round__(self, ndigits: int, /) -> _T_co: ...
@@ -4279,6 +4300,7 @@ def sorted(iterable: Iterable[_T], /, *, key: Callable[[_T], SupportsRichCompari
_AddableT1 = TypeVar("_AddableT1", bound=SupportsAdd[Any, Any])
_AddableT2 = TypeVar("_AddableT2", bound=SupportsAdd[Any, Any])
+@type_check_only
class _SupportsSumWithNoDefaultGiven(SupportsAdd[Any, Any], SupportsRAdd[int, Any], Protocol): ...
_SupportsSumNoDefaultT = TypeVar("_SupportsSumNoDefaultT", bound=_SupportsSumWithNoDefaultGiven)
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/bz2.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/bz2.pyi
index ad86b66dc1f71..84b3b4e30ec8b 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/bz2.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/bz2.pyi
@@ -9,7 +9,7 @@ from _bz2 import BZ2Compressor as BZ2Compressor, BZ2Decompressor as BZ2Decompres
from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer
from collections.abc import Iterable
from io import TextIOWrapper
-from typing import IO, Literal, Protocol, SupportsIndex, overload
+from typing import IO, Literal, Protocol, SupportsIndex, overload, type_check_only
from typing_extensions import Self, TypeAlias
if sys.version_info >= (3, 14):
@@ -22,8 +22,10 @@ __all__ = ["BZ2File", "BZ2Compressor", "BZ2Decompressor", "open", "compress", "d
# The following attributes and methods are optional:
# def fileno(self) -> int: ...
# def close(self) -> object: ...
+@type_check_only
class _ReadableFileobj(_Reader, Protocol): ...
+@type_check_only
class _WritableFileobj(Protocol):
def write(self, b: bytes, /) -> object: ...
# The following attributes and methods are optional:
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/codecs.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/codecs.pyi
index eb90d7c5f19b6..e6ae5d53ac326 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/codecs.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/codecs.pyi
@@ -12,7 +12,7 @@ from _codecs import *
from _typeshed import ReadableBuffer
from abc import abstractmethod
from collections.abc import Callable, Generator, Iterable
-from typing import Any, BinaryIO, ClassVar, Final, Literal, Protocol, TextIO, overload
+from typing import Any, BinaryIO, ClassVar, Final, Literal, Protocol, TextIO, overload, type_check_only
from typing_extensions import Self, TypeAlias
__all__ = [
@@ -82,16 +82,19 @@ _BufferedEncoding: TypeAlias = Literal[
"utf-8-sig",
]
+@type_check_only
class _WritableStream(Protocol):
def write(self, data: bytes, /) -> object: ...
def seek(self, offset: int, whence: int, /) -> object: ...
def close(self) -> object: ...
+@type_check_only
class _ReadableStream(Protocol):
def read(self, size: int = ..., /) -> bytes: ...
def seek(self, offset: int, whence: int, /) -> object: ...
def close(self) -> object: ...
+@type_check_only
class _Stream(_WritableStream, _ReadableStream, Protocol): ...
# TODO: this only satisfies the most common interface, where
@@ -100,24 +103,31 @@ class _Stream(_WritableStream, _ReadableStream, Protocol): ...
# There *are* bytes->bytes and str->str encodings in the standard library.
# They were much more common in Python 2 than in Python 3.
+@type_check_only
class _Encoder(Protocol):
def __call__(self, input: str, errors: str = ..., /) -> tuple[bytes, int]: ... # signature of Codec().encode
+@type_check_only
class _Decoder(Protocol):
def __call__(self, input: ReadableBuffer, errors: str = ..., /) -> tuple[str, int]: ... # signature of Codec().decode
+@type_check_only
class _StreamReader(Protocol):
def __call__(self, stream: _ReadableStream, errors: str = ..., /) -> StreamReader: ...
+@type_check_only
class _StreamWriter(Protocol):
def __call__(self, stream: _WritableStream, errors: str = ..., /) -> StreamWriter: ...
+@type_check_only
class _IncrementalEncoder(Protocol):
def __call__(self, errors: str = ...) -> IncrementalEncoder: ...
+@type_check_only
class _IncrementalDecoder(Protocol):
def __call__(self, errors: str = ...) -> IncrementalDecoder: ...
+@type_check_only
class _BufferedIncrementalDecoder(Protocol):
def __call__(self, errors: str = ...) -> BufferedIncrementalDecoder: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/collections/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/collections/__init__.pyi
index 6e35e647709b7..c6b3b2a15c699 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/collections/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/collections/__init__.pyi
@@ -18,7 +18,7 @@ import sys
from _collections_abc import dict_items, dict_keys, dict_values
from _typeshed import SupportsItems, SupportsKeysAndGetItem, SupportsRichComparison, SupportsRichComparisonT
from types import GenericAlias
-from typing import Any, ClassVar, Generic, NoReturn, SupportsIndex, TypeVar, final, overload
+from typing import Any, ClassVar, Generic, NoReturn, SupportsIndex, TypeVar, final, overload, type_check_only
from typing_extensions import Self
if sys.version_info >= (3, 10):
@@ -631,14 +631,17 @@ class _OrderedDictValuesView(ValuesView[_VT_co]):
# but they are not exposed anywhere)
# pyright doesn't have a specific error code for subclassing error!
@final
+@type_check_only
class _odict_keys(dict_keys[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __reversed__(self) -> Iterator[_KT_co]: ...
@final
+@type_check_only
class _odict_items(dict_items[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ...
@final
+@type_check_only
class _odict_values(dict_values[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]
def __reversed__(self) -> Iterator[_VT_co]: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/_base.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/_base.pyi
index 15c15f414011e..40a0525266eee 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/_base.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/_base.pyi
@@ -4,7 +4,7 @@ from _typeshed import Unused
from collections.abc import Callable, Iterable, Iterator
from logging import Logger
from types import GenericAlias, TracebackType
-from typing import Any, Final, Generic, NamedTuple, Protocol, TypeVar
+from typing import Any, Final, Generic, NamedTuple, Protocol, TypeVar, type_check_only
from typing_extensions import ParamSpec, Self
FIRST_COMPLETED: Final = "FIRST_COMPLETED"
@@ -249,6 +249,7 @@ class Executor:
self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
) -> bool | None: ...
+@type_check_only
class _AsCompletedFuture(Protocol[_T_co]):
# as_completed only mutates non-generic aspects of passed Futures and does not do any nominal
# checks. Therefore, we can use a Protocol here to allow as_completed to act covariantly.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/interpreter.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/interpreter.pyi
index 636147c979000..20ff4dd679c37 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/interpreter.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/concurrent/futures/interpreter.pyi
@@ -1,12 +1,15 @@
"""Implements InterpreterPoolExecutor."""
import sys
-from collections.abc import Callable, Mapping
+from collections.abc import Callable
from concurrent.futures import ThreadPoolExecutor
-from typing import Literal, Protocol, overload, type_check_only
+from typing import Any, Literal, Protocol, overload, type_check_only
from typing_extensions import ParamSpec, Self, TypeAlias, TypeVar, TypeVarTuple, Unpack
_Task: TypeAlias = tuple[bytes, Literal["function", "script"]]
+_Ts = TypeVarTuple("_Ts")
+_P = ParamSpec("_P")
+_R = TypeVar("_R")
@type_check_only
class _TaskFunc(Protocol):
@@ -15,47 +18,26 @@ class _TaskFunc(Protocol):
@overload
def __call__(self, fn: str) -> tuple[bytes, Literal["script"]]: ...
-_Ts = TypeVarTuple("_Ts")
-_P = ParamSpec("_P")
-_R = TypeVar("_R")
-
-# A `type.simplenamespace` with `__name__` attribute.
-@type_check_only
-class _HasName(Protocol):
- __name__: str
-
-# `_interpreters.exec` technically gives us a simple namespace.
-@type_check_only
-class _ExcInfo(Protocol):
- formatted: str
- msg: str
- type: _HasName
-
if sys.version_info >= (3, 14):
from concurrent.futures.thread import BrokenThreadPool, WorkerContext as ThreadWorkerContext
+ from concurrent.interpreters import Interpreter, Queue
- from _interpreters import InterpreterError
-
- class ExecutionFailed(InterpreterError):
- def __init__(self, excinfo: _ExcInfo) -> None: ... # type: ignore[override]
+ def do_call(results: Queue, func: Callable[..., _R], args: tuple[Any, ...], kwargs: dict[str, Any]) -> _R: ...
class WorkerContext(ThreadWorkerContext):
- # Parent class doesn't have `shared` argument,
- @overload # type: ignore[override]
+ interp: Interpreter | None
+ results: Queue | None
+ @overload # type: ignore[override]
@classmethod
def prepare(
- cls, initializer: Callable[[Unpack[_Ts]], object], initargs: tuple[Unpack[_Ts]], shared: Mapping[str, object]
+ cls, initializer: Callable[[Unpack[_Ts]], object], initargs: tuple[Unpack[_Ts]]
) -> tuple[Callable[[], Self], _TaskFunc]: ...
- @overload # type: ignore[override]
+ @overload
@classmethod
- def prepare(
- cls, initializer: Callable[[], object], initargs: tuple[()], shared: Mapping[str, object]
- ) -> tuple[Callable[[], Self], _TaskFunc]: ...
- def __init__(
- self, initdata: tuple[bytes, Literal["function", "script"]], shared: Mapping[str, object] | None = None
- ) -> None: ... # type: ignore[override]
+ def prepare(cls, initializer: Callable[[], object], initargs: tuple[()]) -> tuple[Callable[[], Self], _TaskFunc]: ...
+ def __init__(self, initdata: _Task) -> None: ...
def __del__(self) -> None: ...
- def run(self, task: _Task) -> None: ... # type: ignore[override]
+ def run(self, task: _Task) -> None: ... # type: ignore[override]
class BrokenInterpreterPool(BrokenThreadPool):
"""
@@ -65,15 +47,15 @@ if sys.version_info >= (3, 14):
class InterpreterPoolExecutor(ThreadPoolExecutor):
BROKEN: type[BrokenInterpreterPool]
- @overload # type: ignore[override]
+ @overload # type: ignore[override]
@classmethod
def prepare_context(
- cls, initializer: Callable[[], object], initargs: tuple[()], shared: Mapping[str, object]
+ cls, initializer: Callable[[], object], initargs: tuple[()]
) -> tuple[Callable[[], WorkerContext], _TaskFunc]: ...
- @overload # type: ignore[override]
+ @overload
@classmethod
def prepare_context(
- cls, initializer: Callable[[Unpack[_Ts]], object], initargs: tuple[Unpack[_Ts]], shared: Mapping[str, object]
+ cls, initializer: Callable[[Unpack[_Ts]], object], initargs: tuple[Unpack[_Ts]]
) -> tuple[Callable[[], WorkerContext], _TaskFunc]: ...
@overload
def __init__(
@@ -82,7 +64,6 @@ if sys.version_info >= (3, 14):
thread_name_prefix: str = "",
initializer: Callable[[], object] | None = None,
initargs: tuple[()] = (),
- shared: Mapping[str, object] | None = None,
) -> None:
"""Initializes a new InterpreterPoolExecutor instance.
@@ -103,7 +84,6 @@ if sys.version_info >= (3, 14):
*,
initializer: Callable[[Unpack[_Ts]], object],
initargs: tuple[Unpack[_Ts]],
- shared: Mapping[str, object] | None = None,
) -> None: ...
@overload
def __init__(
@@ -112,5 +92,4 @@ if sys.version_info >= (3, 14):
thread_name_prefix: str,
initializer: Callable[[Unpack[_Ts]], object],
initargs: tuple[Unpack[_Ts]],
- shared: Mapping[str, object] | None = None,
) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/configparser.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/configparser.pyi
index 7df1e3d361b89..979c97359ecad 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/configparser.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/configparser.pyi
@@ -147,8 +147,8 @@ import sys
from _typeshed import MaybeNone, StrOrBytesPath, SupportsWrite
from collections.abc import Callable, ItemsView, Iterable, Iterator, Mapping, MutableMapping, Sequence
from re import Pattern
-from typing import Any, ClassVar, Final, Literal, TypeVar, overload
-from typing_extensions import TypeAlias
+from typing import Any, ClassVar, Final, Literal, TypeVar, overload, type_check_only
+from typing_extensions import TypeAlias, deprecated
if sys.version_info >= (3, 14):
__all__ = (
@@ -249,7 +249,9 @@ else:
]
if sys.version_info >= (3, 13):
+ @type_check_only
class _UNNAMED_SECTION: ...
+
UNNAMED_SECTION: _UNNAMED_SECTION
_SectionName: TypeAlias = str | _UNNAMED_SECTION
@@ -300,6 +302,9 @@ class ExtendedInterpolation(Interpolation):
"""
if sys.version_info < (3, 13):
+ @deprecated(
+ "Deprecated since Python 3.2; removed in Python 3.13. Use `BasicInterpolation` or `ExtendedInterpolation` instead."
+ )
class LegacyInterpolation(Interpolation):
"""Deprecated interpolation used in old versions of ConfigParser.
Use BasicInterpolation or ExtendedInterpolation instead.
@@ -494,6 +499,7 @@ class RawConfigParser(_Parser):
dictionary being read.
"""
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.2; removed in Python 3.12. Use `parser.read_file()` instead.")
def readfp(self, fp: Iterable[str], filename: str | None = None) -> None:
"""Deprecated, use read_file instead."""
# These get* methods are partially applied (with the same names) in
@@ -613,7 +619,8 @@ class ConfigParser(RawConfigParser):
) -> str | _T: ...
if sys.version_info < (3, 12):
- class SafeConfigParser(ConfigParser): # deprecated alias
+ @deprecated("Deprecated since Python 3.2; removed in Python 3.12. Use `ConfigParser` instead.")
+ class SafeConfigParser(ConfigParser):
"""ConfigParser alias for backwards compatibility purposes."""
class SectionProxy(MutableMapping[str, str]):
@@ -776,10 +783,24 @@ class ParsingError(Error):
elif sys.version_info >= (3, 12):
def __init__(self, source: str) -> None: ...
else:
- def __init__(self, source: str | None = None, filename: str | None = None) -> None: ...
+ @overload
+ def __init__(self, source: str, filename: None = None) -> None: ...
+ @overload
+ @deprecated("The `filename` parameter removed in Python 3.12. Use `source` instead.")
+ def __init__(self, source: None = None, filename: str = ...) -> None: ...
def append(self, lineno: int, line: str) -> None: ...
+ if sys.version_info < (3, 12):
+ @property
+ @deprecated("Deprecated since Python 3.2; removed in Python 3.12. Use `source` instead.")
+ def filename(self) -> str:
+ """Deprecated, use `source'."""
+
+ @filename.setter
+ @deprecated("Deprecated since Python 3.2; removed in Python 3.12. Use `source` instead.")
+ def filename(self, value: str) -> None: ...
+
class MissingSectionHeaderError(ParsingError):
"""Raised when a key-value pair is found before any section header."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/dataclasses.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/dataclasses.pyi
index 6a749a73a8c4e..3728c9d6d1bef 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/dataclasses.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/dataclasses.pyi
@@ -243,6 +243,7 @@ else:
) -> Callable[[type[_T]], type[_T]]: ...
# See https://github.com/python/mypy/issues/10750
+@type_check_only
class _DefaultFactory(Protocol[_T_co]):
def __call__(self) -> _T_co: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/dbm/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/dbm/__init__.pyi
index 698c231519e01..3c41015fcd043 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/dbm/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/dbm/__init__.pyi
@@ -105,6 +105,7 @@ _TFlags: TypeAlias = Literal[
"nusf",
]
+@type_check_only
class _Database(MutableMapping[_KeyType, bytes]):
def close(self) -> None: ...
def __getitem__(self, key: _KeyType) -> bytes: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/email/headerregistry.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/email/headerregistry.pyi
index 2b1e0d615fbe2..801bf612dba00 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/email/headerregistry.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/email/headerregistry.pyi
@@ -19,7 +19,7 @@ from email._header_value_parser import (
)
from email.errors import MessageDefect
from email.policy import Policy
-from typing import Any, ClassVar, Literal, Protocol
+from typing import Any, ClassVar, Literal, Protocol, type_check_only
from typing_extensions import Self
class BaseHeader(str):
@@ -248,6 +248,7 @@ class MessageIDHeader:
def value_parser(value: str) -> MessageID:
"""message-id = "Message-ID:" msg-id CRLF"""
+@type_check_only
class _HeaderParser(Protocol):
max_count: ClassVar[Literal[1] | None]
@staticmethod
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/email/message.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/email/message.pyi
index a67f17fd64541..308c21ad163c9 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/email/message.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/email/message.pyi
@@ -7,7 +7,7 @@ from email.charset import Charset
from email.contentmanager import ContentManager
from email.errors import MessageDefect
from email.policy import Policy
-from typing import Any, Generic, Literal, Protocol, TypeVar, overload
+from typing import Any, Generic, Literal, Protocol, TypeVar, overload, type_check_only
from typing_extensions import Self, TypeAlias
__all__ = ["Message", "EmailMessage"]
@@ -26,9 +26,11 @@ _EncodedPayloadType: TypeAlias = Message | bytes
_MultipartPayloadType: TypeAlias = list[_PayloadType]
_CharsetType: TypeAlias = Charset | str | None
+@type_check_only
class _SupportsEncodeToPayload(Protocol):
def encode(self, encoding: str, /) -> _PayloadType | _MultipartPayloadType | _SupportsDecodeToPayload: ...
+@type_check_only
class _SupportsDecodeToPayload(Protocol):
def decode(self, encoding: str, errors: str, /) -> _PayloadType | _MultipartPayloadType: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/encodings/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/encodings/__init__.pyi
index c45ae99601796..7d26d92022bf7 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/encodings/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/encodings/__init__.pyi
@@ -28,6 +28,7 @@ Written by Marc-Andre Lemburg (mal@lemburg.com).
"""
+import sys
from codecs import CodecInfo
class CodecRegistryError(LookupError, SystemError): ...
@@ -46,5 +47,8 @@ def normalize_encoding(encoding: str | bytes) -> str:
def search_function(encoding: str) -> CodecInfo | None: ...
+if sys.version_info >= (3, 14) and sys.platform == "win32":
+ def win32_code_page_search_function(encoding: str) -> CodecInfo | None: ...
+
# Needed for submodules
def __getattr__(name: str): ... # incomplete module
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/fcntl.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/fcntl.pyi
index 279f7a99e8d58..561e6585c8975 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/fcntl.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/fcntl.pyi
@@ -10,107 +10,107 @@ from typing import Any, Final, Literal, overload
from typing_extensions import Buffer
if sys.platform != "win32":
- FASYNC: int
- FD_CLOEXEC: int
- F_DUPFD: int
- F_DUPFD_CLOEXEC: int
- F_GETFD: int
- F_GETFL: int
- F_GETLK: int
- F_GETOWN: int
- F_RDLCK: int
- F_SETFD: int
- F_SETFL: int
- F_SETLK: int
- F_SETLKW: int
- F_SETOWN: int
- F_UNLCK: int
- F_WRLCK: int
-
- F_GETLEASE: int
- F_SETLEASE: int
+ FASYNC: Final[int]
+ FD_CLOEXEC: Final[int]
+ F_DUPFD: Final[int]
+ F_DUPFD_CLOEXEC: Final[int]
+ F_GETFD: Final[int]
+ F_GETFL: Final[int]
+ F_GETLK: Final[int]
+ F_GETOWN: Final[int]
+ F_RDLCK: Final[int]
+ F_SETFD: Final[int]
+ F_SETFL: Final[int]
+ F_SETLK: Final[int]
+ F_SETLKW: Final[int]
+ F_SETOWN: Final[int]
+ F_UNLCK: Final[int]
+ F_WRLCK: Final[int]
+
+ F_GETLEASE: Final[int]
+ F_SETLEASE: Final[int]
if sys.platform == "darwin":
- F_FULLFSYNC: int
- F_NOCACHE: int
- F_GETPATH: int
+ F_FULLFSYNC: Final[int]
+ F_NOCACHE: Final[int]
+ F_GETPATH: Final[int]
if sys.platform == "linux":
- F_SETLKW64: int
- F_SETSIG: int
- F_SHLCK: int
- F_SETLK64: int
- F_GETSIG: int
- F_NOTIFY: int
- F_EXLCK: int
- F_GETLK64: int
- F_ADD_SEALS: int
- F_GET_SEALS: int
- F_SEAL_GROW: int
- F_SEAL_SEAL: int
- F_SEAL_SHRINK: int
- F_SEAL_WRITE: int
+ F_SETLKW64: Final[int]
+ F_SETSIG: Final[int]
+ F_SHLCK: Final[int]
+ F_SETLK64: Final[int]
+ F_GETSIG: Final[int]
+ F_NOTIFY: Final[int]
+ F_EXLCK: Final[int]
+ F_GETLK64: Final[int]
+ F_ADD_SEALS: Final[int]
+ F_GET_SEALS: Final[int]
+ F_SEAL_GROW: Final[int]
+ F_SEAL_SEAL: Final[int]
+ F_SEAL_SHRINK: Final[int]
+ F_SEAL_WRITE: Final[int]
F_OFD_GETLK: Final[int]
F_OFD_SETLK: Final[int]
F_OFD_SETLKW: Final[int]
if sys.version_info >= (3, 10):
- F_GETPIPE_SZ: int
- F_SETPIPE_SZ: int
-
- DN_ACCESS: int
- DN_ATTRIB: int
- DN_CREATE: int
- DN_DELETE: int
- DN_MODIFY: int
- DN_MULTISHOT: int
- DN_RENAME: int
-
- LOCK_EX: int
- LOCK_NB: int
- LOCK_SH: int
- LOCK_UN: int
+ F_GETPIPE_SZ: Final[int]
+ F_SETPIPE_SZ: Final[int]
+
+ DN_ACCESS: Final[int]
+ DN_ATTRIB: Final[int]
+ DN_CREATE: Final[int]
+ DN_DELETE: Final[int]
+ DN_MODIFY: Final[int]
+ DN_MULTISHOT: Final[int]
+ DN_RENAME: Final[int]
+
+ LOCK_EX: Final[int]
+ LOCK_NB: Final[int]
+ LOCK_SH: Final[int]
+ LOCK_UN: Final[int]
if sys.platform == "linux":
- LOCK_MAND: int
- LOCK_READ: int
- LOCK_RW: int
- LOCK_WRITE: int
+ LOCK_MAND: Final[int]
+ LOCK_READ: Final[int]
+ LOCK_RW: Final[int]
+ LOCK_WRITE: Final[int]
if sys.platform == "linux":
# Constants for the POSIX STREAMS interface. Present in glibc until 2.29 (released February 2019).
# Never implemented on BSD, and considered "obsolescent" starting in POSIX 2008.
# Probably still used on Solaris.
- I_ATMARK: int
- I_CANPUT: int
- I_CKBAND: int
- I_FDINSERT: int
- I_FIND: int
- I_FLUSH: int
- I_FLUSHBAND: int
- I_GETBAND: int
- I_GETCLTIME: int
- I_GETSIG: int
- I_GRDOPT: int
- I_GWROPT: int
- I_LINK: int
- I_LIST: int
- I_LOOK: int
- I_NREAD: int
- I_PEEK: int
- I_PLINK: int
- I_POP: int
- I_PUNLINK: int
- I_PUSH: int
- I_RECVFD: int
- I_SENDFD: int
- I_SETCLTIME: int
- I_SETSIG: int
- I_SRDOPT: int
- I_STR: int
- I_SWROPT: int
- I_UNLINK: int
+ I_ATMARK: Final[int]
+ I_CANPUT: Final[int]
+ I_CKBAND: Final[int]
+ I_FDINSERT: Final[int]
+ I_FIND: Final[int]
+ I_FLUSH: Final[int]
+ I_FLUSHBAND: Final[int]
+ I_GETBAND: Final[int]
+ I_GETCLTIME: Final[int]
+ I_GETSIG: Final[int]
+ I_GRDOPT: Final[int]
+ I_GWROPT: Final[int]
+ I_LINK: Final[int]
+ I_LIST: Final[int]
+ I_LOOK: Final[int]
+ I_NREAD: Final[int]
+ I_PEEK: Final[int]
+ I_PLINK: Final[int]
+ I_POP: Final[int]
+ I_PUNLINK: Final[int]
+ I_PUSH: Final[int]
+ I_RECVFD: Final[int]
+ I_SENDFD: Final[int]
+ I_SETCLTIME: Final[int]
+ I_SETSIG: Final[int]
+ I_SRDOPT: Final[int]
+ I_STR: Final[int]
+ I_SWROPT: Final[int]
+ I_UNLINK: Final[int]
if sys.version_info >= (3, 12) and sys.platform == "linux":
- FICLONE: int
- FICLONERANGE: int
+ FICLONE: Final[int]
+ FICLONERANGE: Final[int]
if sys.version_info >= (3, 13) and sys.platform == "linux":
F_OWNER_TID: Final = 0
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/functools.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/functools.pyi
index 5f5d58288b816..171c5d6fc3368 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/functools.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/functools.pyi
@@ -5,7 +5,7 @@ import types
from _typeshed import SupportsAllComparisons, SupportsItems
from collections.abc import Callable, Hashable, Iterable, Sized
from types import GenericAlias
-from typing import Any, Final, Generic, Literal, NamedTuple, TypedDict, TypeVar, final, overload
+from typing import Any, Final, Generic, Literal, NamedTuple, TypedDict, TypeVar, final, overload, type_check_only
from typing_extensions import ParamSpec, Self, TypeAlias
__all__ = [
@@ -81,6 +81,7 @@ class _CacheInfo(NamedTuple):
maxsize: int | None
currsize: int
+@type_check_only
class _CacheParameters(TypedDict):
maxsize: int
typed: bool
@@ -170,6 +171,7 @@ else:
WRAPPER_UPDATES: tuple[Literal["__dict__"]]
+@type_check_only
class _Wrapped(Generic[_PWrapped, _RWrapped, _PWrapper, _RWrapper]):
__wrapped__: Callable[_PWrapped, _RWrapped]
def __call__(self, *args: _PWrapper.args, **kwargs: _PWrapper.kwargs) -> _RWrapper: ...
@@ -177,6 +179,7 @@ class _Wrapped(Generic[_PWrapped, _RWrapped, _PWrapper, _RWrapper]):
__name__: str
__qualname__: str
+@type_check_only
class _Wrapper(Generic[_PWrapped, _RWrapped]):
def __call__(self, f: Callable[_PWrapper, _RWrapper]) -> _Wrapped[_PWrapped, _RWrapped, _PWrapper, _RWrapper]: ...
@@ -345,6 +348,7 @@ if sys.version_info >= (3, 11):
else:
_RegType: TypeAlias = type[Any]
+@type_check_only
class _SingleDispatchCallable(Generic[_T]):
registry: types.MappingProxyType[Any, Callable[..., _T]]
def dispatch(self, cls: Any) -> Callable[..., _T]: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/gettext.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/gettext.pyi
index e103513790211..c5db318457879 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/gettext.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/gettext.pyi
@@ -15,6 +15,7 @@ import sys
from _typeshed import StrPath
from collections.abc import Callable, Container, Iterable, Sequence
from typing import Any, Final, Literal, Protocol, TypeVar, overload, type_check_only
+from typing_extensions import deprecated
__all__ = [
"NullTranslations",
@@ -55,9 +56,13 @@ class NullTranslations:
def info(self) -> dict[str, str]: ...
def charset(self) -> str | None: ...
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11.")
def output_charset(self) -> str | None: ...
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11.")
def set_output_charset(self, charset: str) -> None: ...
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `gettext()` instead.")
def lgettext(self, message: str) -> str: ...
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `ngettext()` instead.")
def lngettext(self, msgid1: str, msgid2: str, n: int) -> str: ...
def install(self, names: Container[str] | None = None) -> None: ...
@@ -157,9 +162,16 @@ else:
fallback: bool = False,
codeset: str | None = None,
) -> NullTranslations: ...
+ @overload
def install(
- domain: str, localedir: StrPath | None = None, codeset: str | None = None, names: Container[str] | None = None
+ domain: str, localedir: StrPath | None = None, codeset: None = None, names: Container[str] | None = None
) -> None: ...
+ @overload
+ @deprecated("The `codeset` parameter is deprecated since Python 3.8; removed in Python 3.11.")
+ def install(domain: str, localedir: StrPath | None, codeset: str, /, names: Container[str] | None = None) -> None: ...
+ @overload
+ @deprecated("The `codeset` parameter is deprecated since Python 3.8; removed in Python 3.11.")
+ def install(domain: str, localedir: StrPath | None = None, *, codeset: str, names: Container[str] | None = None) -> None: ...
def textdomain(domain: str | None = None) -> str: ...
def bindtextdomain(domain: str, localedir: StrPath | None = None) -> str: ...
@@ -173,10 +185,15 @@ def npgettext(context: str, msgid1: str, msgid2: str, n: int) -> str: ...
def dnpgettext(domain: str, context: str, msgid1: str, msgid2: str, n: int) -> str: ...
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `gettext()` instead.")
def lgettext(message: str) -> str: ...
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `dgettext()` instead.")
def ldgettext(domain: str, message: str) -> str: ...
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `ngettext()` instead.")
def lngettext(msgid1: str, msgid2: str, n: int) -> str: ...
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `dngettext()` instead.")
def ldngettext(domain: str, msgid1: str, msgid2: str, n: int) -> str: ...
+ @deprecated("Deprecated since Python 3.8; removed in Python 3.11. Use `bindtextdomain()` instead.")
def bind_textdomain_codeset(domain: str, codeset: str | None = None) -> str: ...
Catalog = translation
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/glob.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/glob.pyi
index a1ca7a6de6338..d9863ba3b284f 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/glob.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/glob.pyi
@@ -4,14 +4,22 @@ import sys
from _typeshed import StrOrBytesPath
from collections.abc import Iterator, Sequence
from typing import AnyStr
+from typing_extensions import deprecated
__all__ = ["escape", "glob", "iglob"]
if sys.version_info >= (3, 13):
__all__ += ["translate"]
-def glob0(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
-def glob1(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
+if sys.version_info >= (3, 10):
+ @deprecated("Will be removed in Python 3.15; Use `glob.glob` and pass *root_dir* argument instead.")
+ def glob0(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
+ @deprecated("Will be removed in Python 3.15; Use `glob.glob` and pass *root_dir* argument instead.")
+ def glob1(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
+
+else:
+ def glob0(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
+ def glob1(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
if sys.version_info >= (3, 11):
def glob(
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/gzip.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/gzip.pyi
index 90bdf80f8926b..ac3fe1a3c0908 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/gzip.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/gzip.pyi
@@ -9,7 +9,7 @@ import zlib
from _typeshed import ReadableBuffer, SizedBuffer, StrOrBytesPath, WriteableBuffer
from io import FileIO, TextIOWrapper
from typing import Final, Literal, Protocol, overload, type_check_only
-from typing_extensions import TypeAlias
+from typing_extensions import TypeAlias, deprecated
if sys.version_info >= (3, 14):
from compression._common._streams import BaseStream, DecompressReader
@@ -216,6 +216,7 @@ class GzipFile(BaseStream):
) -> None: ...
if sys.version_info < (3, 12):
@property
+ @deprecated("Deprecated since Python 2.6; removed in Python 3.12. Use `name` attribute instead.")
def filename(self) -> str: ...
@property
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/hashlib.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/hashlib.pyi
index 9f68beea56ac0..faeafece16a43 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/hashlib.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/hashlib.pyi
@@ -71,7 +71,7 @@ from _hashlib import (
)
from _typeshed import ReadableBuffer
from collections.abc import Callable, Set as AbstractSet
-from typing import Protocol
+from typing import Protocol, type_check_only
if sys.version_info >= (3, 11):
__all__ = (
@@ -126,9 +126,11 @@ algorithms_guaranteed: AbstractSet[str]
algorithms_available: AbstractSet[str]
if sys.version_info >= (3, 11):
+ @type_check_only
class _BytesIOLike(Protocol):
def getbuffer(self) -> ReadableBuffer: ...
+ @type_check_only
class _FileDigestFileObj(Protocol):
def readinto(self, buf: bytearray, /) -> int: ...
def readable(self) -> bool: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/html/parser.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/html/parser.pyi
index 45805ddf1f3b5..cc71c2cb41f4c 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/html/parser.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/html/parser.pyi
@@ -30,7 +30,8 @@ class HTMLParser(ParserBase):
"""
CDATA_CONTENT_ELEMENTS: Final[tuple[str, ...]]
- if sys.version_info >= (3, 14):
+ if sys.version_info >= (3, 13):
+ # Added in 3.13.6
RCDATA_CONTENT_ELEMENTS: Final[tuple[str, ...]]
def __init__(self, *, convert_charrefs: bool = True) -> None:
@@ -70,7 +71,8 @@ class HTMLParser(ParserBase):
def parse_html_declaration(self, i: int) -> int: ... # undocumented
def parse_pi(self, i: int) -> int: ... # undocumented
def parse_starttag(self, i: int) -> int: ... # undocumented
- if sys.version_info >= (3, 14):
+ if sys.version_info >= (3, 13):
+ # `escapable` parameter added in 3.13.6
def set_cdata_mode(self, elem: str, *, escapable: bool = False) -> None: ... # undocumented
else:
def set_cdata_mode(self, elem: str) -> None: ... # undocumented
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/imp.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/imp.pyi
index 64fe67d765e52..0131b6ae8af65 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/imp.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/imp.pyi
@@ -21,7 +21,7 @@ from _imp import (
from _typeshed import StrPath
from os import PathLike
from types import TracebackType
-from typing import IO, Any, Protocol
+from typing import IO, Any, Protocol, type_check_only
SEARCH_ERROR: int
PY_SOURCE: int
@@ -95,6 +95,7 @@ class NullImporter:
# Technically, a text file has to support a slightly different set of operations than a binary file,
# but we ignore that here.
+@type_check_only
class _FileLike(Protocol):
closed: bool
mode: str
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/__init__.pyi
index abd6e4348f305..11d7bf3c480fc 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/__init__.pyi
@@ -4,6 +4,7 @@ import sys
from importlib._bootstrap import __import__ as __import__
from importlib.abc import Loader
from types import ModuleType
+from typing_extensions import deprecated
__all__ = ["__import__", "import_module", "invalidate_caches", "reload"]
@@ -18,6 +19,7 @@ def import_module(name: str, package: str | None = None) -> ModuleType:
"""
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `importlib.util.find_spec()` instead.")
def find_loader(name: str, path: str | None = None) -> Loader | None:
"""Return the loader for the specified module.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/_abc.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/_abc.pyi
index a6c01e6b90b11..c85e8004cd37c 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/_abc.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/_abc.pyi
@@ -4,6 +4,7 @@ import sys
import types
from abc import ABCMeta
from importlib.machinery import ModuleSpec
+from typing_extensions import deprecated
if sys.version_info >= (3, 10):
class Loader(metaclass=ABCMeta):
@@ -23,6 +24,10 @@ if sys.version_info >= (3, 10):
"""
if sys.version_info < (3, 12):
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "The module spec is now used by the import machinery to generate a module repr."
+ )
def module_repr(self, module: types.ModuleType) -> str:
"""Return a module's repr.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/abc.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/abc.pyi
index 14f15176135ad..5dfe7c7272c05 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/abc.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/abc.pyi
@@ -69,6 +69,7 @@ else:
def exec_module(self, module: types.ModuleType) -> None: ...
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.3; removed in Python 3.12. Use `MetaPathFinder` or `PathEntryFinder` instead.")
class Finder(metaclass=ABCMeta):
"""Legacy abstract base class for import finders.
@@ -83,10 +84,13 @@ if sys.version_info < (3, 12):
@deprecated("Deprecated as of Python 3.7: Use importlib.resources.abc.TraversableResources instead.")
class ResourceLoader(Loader):
"""Abstract base class for loaders which can return data from their
- back-end storage.
+ back-end storage to facilitate reading data to perform an import.
This ABC represents one of the optional protocols specified by PEP 302.
+ For directly loading resources, use TraversableResources instead. This class
+ primarily exists for backwards compatibility with other ABCs in this module.
+
"""
@abstractmethod
@@ -204,6 +208,7 @@ if sys.version_info >= (3, 10):
"""Abstract base class for import finders on sys.meta_path."""
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `MetaPathFinder.find_spec()` instead.")
def find_module(self, fullname: str, path: Sequence[str] | None) -> Loader | None:
"""Return a loader for the module.
@@ -229,6 +234,7 @@ if sys.version_info >= (3, 10):
"""Abstract base class for path entry finders used by PathFinder."""
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `PathEntryFinder.find_spec()` instead.")
def find_module(self, fullname: str) -> Loader | None:
"""Try to find a loader for the specified module by delegating to
self.find_loader().
@@ -237,6 +243,7 @@ if sys.version_info >= (3, 10):
"""
+ @deprecated("Deprecated since Python 3.4; removed in Python 3.12. Use `find_spec()` instead.")
def find_loader(self, fullname: str) -> tuple[Loader | None, Sequence[str]]:
"""Return (loader, namespace portion) for the path entry.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/metadata/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/metadata/__init__.pyi
index 2c6f68cd49ce7..478aa35139f61 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/metadata/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/metadata/__init__.pyi
@@ -11,7 +11,7 @@ from os import PathLike
from pathlib import Path
from re import Pattern
from typing import Any, ClassVar, Generic, NamedTuple, TypeVar, overload
-from typing_extensions import Self, TypeAlias
+from typing_extensions import Self, TypeAlias, deprecated
_T = TypeVar("_T")
_KT = TypeVar("_KT")
@@ -153,8 +153,8 @@ class EntryPoint(_EntryPointBase):
"""
def __hash__(self) -> int: ...
- def __eq__(self, other: object) -> bool: ...
if sys.version_info >= (3, 11):
+ def __eq__(self, other: object) -> bool: ...
def __lt__(self, other: object) -> bool: ...
if sys.version_info < (3, 12):
def __iter__(self) -> Iterator[Any]: # result of iter((str, Self)), really
@@ -311,6 +311,7 @@ if sys.version_info >= (3, 10) and sys.version_info < (3, 12):
def keys(self) -> dict_keys[_KT, _VT]: ...
def values(self) -> dict_values[_KT, _VT]: ...
+ @deprecated("Deprecated since Python 3.10; removed in Python 3.12. Use `select` instead.")
class SelectableGroups(Deprecated[str, EntryPoints], dict[str, EntryPoints]): # use as dict is deprecated since 3.10
"""
A backward- and forward-compatible result from
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/util.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/util.pyi
index 3b4f835210454..73acc3a83a030 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/importlib/util.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/importlib/util.pyi
@@ -14,11 +14,15 @@ from importlib._bootstrap_external import (
spec_from_file_location as spec_from_file_location,
)
from importlib.abc import Loader
-from typing_extensions import ParamSpec
+from typing_extensions import ParamSpec, deprecated
_P = ParamSpec("_P")
if sys.version_info < (3, 12):
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "`__name__`, `__package__` and `__loader__` are now set automatically."
+ )
def module_for_loader(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]:
"""Decorator to handle selecting the proper module for loaders.
@@ -38,6 +42,10 @@ if sys.version_info < (3, 12):
"""
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "`__name__`, `__package__` and `__loader__` are now set automatically."
+ )
def set_loader(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]:
"""Set __loader__ on the returned module.
@@ -45,6 +53,10 @@ if sys.version_info < (3, 12):
"""
+ @deprecated(
+ "Deprecated since Python 3.4; removed in Python 3.12. "
+ "`__name__`, `__package__` and `__loader__` are now set automatically."
+ )
def set_package(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]:
"""Set __package__ on the returned module.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/inspect.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/inspect.pyi
index 508470d1bdd6a..bfa55f2f72642 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/inspect.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/inspect.pyi
@@ -54,7 +54,7 @@ from types import (
WrapperDescriptorType,
)
from typing import Any, ClassVar, Final, Literal, NamedTuple, Protocol, TypeVar, overload, type_check_only
-from typing_extensions import ParamSpec, Self, TypeAlias, TypeGuard, TypeIs
+from typing_extensions import ParamSpec, Self, TypeAlias, TypeGuard, TypeIs, deprecated
if sys.version_info >= (3, 14):
from annotationlib import Format
@@ -948,6 +948,7 @@ def getargs(co: CodeType) -> Arguments:
"""
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.0; removed in Python 3.11.")
class ArgSpec(NamedTuple):
"""ArgSpec(args, varargs, keywords, defaults)"""
@@ -956,6 +957,7 @@ if sys.version_info < (3, 11):
keywords: str | None
defaults: tuple[Any, ...]
+ @deprecated("Deprecated since Python 3.0; removed in Python 3.11. Use `inspect.signature()` instead.")
def getargspec(func: object) -> ArgSpec:
"""Get the names and default values of a function's parameters.
@@ -1031,6 +1033,9 @@ else:
def formatannotationrelativeto(object: object) -> Callable[[object], str]: ...
if sys.version_info < (3, 11):
+ @deprecated(
+ "Deprecated since Python 3.5; removed in Python 3.11. Use `inspect.signature()` and the `Signature` class instead."
+ )
def formatargspec(
args: list[str],
varargs: str | None = None,
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/locale.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/locale.pyi
index c121dabe86963..ed836048f435e 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/locale.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/locale.pyi
@@ -30,6 +30,7 @@ from builtins import str as _str
from collections.abc import Callable, Iterable
from decimal import Decimal
from typing import Any
+from typing_extensions import deprecated
if sys.version_info >= (3, 11):
from _locale import getencoding as getencoding
@@ -210,15 +211,26 @@ def normalize(localename: _str) -> _str:
"""
if sys.version_info < (3, 13):
- def resetlocale(category: int = ...) -> None:
- """Sets the locale for category to the default setting.
+ if sys.version_info >= (3, 11):
+ @deprecated("Deprecated since Python 3.11; removed in Python 3.13. Use `locale.setlocale(locale.LC_ALL, '')` instead.")
+ def resetlocale(category: int = ...) -> None:
+ """Sets the locale for category to the default setting.
- The default setting is determined by calling
- getdefaultlocale(). category defaults to LC_ALL.
+ The default setting is determined by calling
+ getdefaultlocale(). category defaults to LC_ALL.
- """
+ """
+ else:
+ def resetlocale(category: int = ...) -> None:
+ """Sets the locale for category to the default setting.
+
+ The default setting is determined by calling
+ getdefaultlocale(). category defaults to LC_ALL.
+
+ """
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.7; removed in Python 3.12. Use `locale.format_string()` instead.")
def format(percent: _str, value: float | Decimal, grouping: bool = False, monetary: bool = False, *additional: Any) -> _str:
"""Deprecated, use format_string instead."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/logging/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/logging/__init__.pyi
index 2edd351345ba2..0c47d8bd6540e 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/logging/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/logging/__init__.pyi
@@ -16,7 +16,7 @@ from re import Pattern
from string import Template
from time import struct_time
from types import FrameType, GenericAlias, TracebackType
-from typing import Any, ClassVar, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload
+from typing import Any, ClassVar, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only
from typing_extensions import Self, TypeAlias, deprecated
__all__ = [
@@ -76,11 +76,13 @@ _Level: TypeAlias = int | str
_FormatStyle: TypeAlias = Literal["%", "{", "$"]
if sys.version_info >= (3, 12):
+ @type_check_only
class _SupportsFilter(Protocol):
def filter(self, record: LogRecord, /) -> bool | LogRecord: ...
_FilterType: TypeAlias = Filter | Callable[[LogRecord], bool | LogRecord] | _SupportsFilter
else:
+ @type_check_only
class _SupportsFilter(Protocol):
def filter(self, record: LogRecord, /) -> bool: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/logging/handlers.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/logging/handlers.pyi
index ce2ef4bfa6fe7..26d811b3ce8b6 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/logging/handlers.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/logging/handlers.pyi
@@ -18,7 +18,7 @@ from re import Pattern
from socket import SocketKind, socket
from threading import Thread
from types import TracebackType
-from typing import Any, ClassVar, Final, Protocol, TypeVar
+from typing import Any, ClassVar, Final, Protocol, TypeVar, type_check_only
from typing_extensions import Self
_T = TypeVar("_T")
@@ -594,6 +594,7 @@ class HTTPHandler(Handler):
there is a proxy.
"""
+@type_check_only
class _QueueLike(Protocol[_T]):
def get(self) -> _T: ...
def put_nowait(self, item: _T, /) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/mailbox.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/mailbox.pyi
index ef31fcf83da65..01570c1c2ed67 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/mailbox.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/mailbox.pyi
@@ -8,7 +8,7 @@ from abc import ABCMeta, abstractmethod
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
from email._policybase import _MessageT
from types import GenericAlias, TracebackType
-from typing import IO, Any, AnyStr, Generic, Literal, Protocol, TypeVar, overload
+from typing import IO, Any, AnyStr, Generic, Literal, Protocol, TypeVar, overload, type_check_only
from typing_extensions import Self, TypeAlias
__all__ = [
@@ -33,13 +33,16 @@ __all__ = [
_T = TypeVar("_T")
+@type_check_only
class _SupportsReadAndReadline(SupportsRead[bytes], SupportsNoArgReadline[bytes], Protocol): ...
_MessageData: TypeAlias = email.message.Message | bytes | str | io.StringIO | _SupportsReadAndReadline
+@type_check_only
class _HasIteritems(Protocol):
def iteritems(self) -> Iterator[tuple[str, _MessageData]]: ...
+@type_check_only
class _HasItems(Protocol):
def items(self) -> Iterator[tuple[str, _MessageData]]: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/heap.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/heap.pyi
index dc1da4d251501..894d2dfc622b3 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/heap.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/heap.pyi
@@ -2,7 +2,7 @@ import sys
from _typeshed import Incomplete
from collections.abc import Callable
from mmap import mmap
-from typing import Protocol
+from typing import Protocol, type_check_only
from typing_extensions import TypeAlias
__all__ = ["BufferWrapper"]
@@ -24,6 +24,7 @@ class Arena:
_Block: TypeAlias = tuple[Arena, int, int]
if sys.platform != "win32":
+ @type_check_only
class _SupportsDetach(Protocol):
def detach(self) -> int: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/sharedctypes.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/sharedctypes.pyi
index 9ebd2de2f9368..7349cb2711eb6 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/sharedctypes.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/multiprocessing/sharedctypes.pyi
@@ -5,7 +5,7 @@ from ctypes import _SimpleCData, c_char
from multiprocessing.context import BaseContext
from multiprocessing.synchronize import _LockLike
from types import TracebackType
-from typing import Any, Generic, Literal, Protocol, TypeVar, overload
+from typing import Any, Generic, Literal, Protocol, TypeVar, overload, type_check_only
__all__ = ["RawValue", "RawArray", "Value", "Array", "copy", "synchronized"]
@@ -97,7 +97,7 @@ def synchronized(
) -> SynchronizedArray[_T]: ...
@overload
def synchronized(obj: _CT, lock: _LockLike | None = None, ctx: Any | None = None) -> SynchronizedBase[_CT]: ...
-
+@type_check_only
class _AcquireFunc(Protocol):
def __call__(self, block: bool = ..., timeout: float | None = ..., /) -> bool: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/nt.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/nt.pyi
index 8d2eee0183486..c10b791bd4683 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/nt.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/nt.pyi
@@ -116,4 +116,7 @@ if sys.platform == "win32":
if sys.version_info >= (3, 13):
from os import fchmod as fchmod, lchmod as lchmod
+ if sys.version_info >= (3, 14):
+ from os import readinto as readinto
+
environ: dict[str, str]
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/numbers.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/numbers.pyi
index 3b68484ed731a..9565050b2bdbb 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/numbers.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/numbers.pyi
@@ -13,7 +13,7 @@ TODO: Fill out more detailed documentation on the operators.
# nor `float` as a subtype of `numbers.Real`, etc.)
from abc import ABCMeta, abstractmethod
-from typing import ClassVar, Literal, Protocol, overload
+from typing import ClassVar, Literal, Protocol, overload, type_check_only
__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
@@ -27,6 +27,7 @@ __all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
# NOTE: We can't include `__complex__` here,
# as we want `int` to be seen as a subtype of `_ComplexLike`,
# and `int.__complex__` does not exist :(
+@type_check_only
class _ComplexLike(Protocol):
def __neg__(self) -> _ComplexLike: ...
def __pos__(self) -> _ComplexLike: ...
@@ -34,6 +35,7 @@ class _ComplexLike(Protocol):
# _RealLike is a structural-typing approximation
# of the `Real` ABC, which is not (and cannot be) a protocol
+@type_check_only
class _RealLike(_ComplexLike, Protocol):
def __trunc__(self) -> _IntegralLike: ...
def __floor__(self) -> _IntegralLike: ...
@@ -46,6 +48,7 @@ class _RealLike(_ComplexLike, Protocol):
# _IntegralLike is a structural-typing approximation
# of the `Integral` ABC, which is not (and cannot be) a protocol
+@type_check_only
class _IntegralLike(_RealLike, Protocol):
def __invert__(self) -> _IntegralLike: ...
def __int__(self) -> int: ...
@@ -289,10 +292,17 @@ class Rational(Real):
@property
@abstractmethod
- def numerator(self) -> _IntegralLike: ...
+ def numerator(self) -> _IntegralLike:
+ """The numerator of a rational number in lowest terms."""
+
@property
@abstractmethod
- def denominator(self) -> _IntegralLike: ...
+ def denominator(self) -> _IntegralLike:
+ """The denominator of a rational number in lowest terms.
+
+ This denominator should be positive.
+ """
+
def __float__(self) -> float:
"""float(self) = self.numerator / self.denominator
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/os/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/os/__init__.pyi
index a5ffaab3484ca..187f60d7974f8 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/os/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/os/__init__.pyi
@@ -62,6 +62,7 @@ from typing import (
final,
overload,
runtime_checkable,
+ type_check_only,
)
from typing_extensions import Self, TypeAlias, Unpack, deprecated
@@ -2000,6 +2001,7 @@ def rmdir(path: StrOrBytesPath, *, dir_fd: int | None = None) -> None:
"""
@final
+@type_check_only
class _ScandirIterator(Generic[AnyStr]):
def __del__(self) -> None: ...
def __iter__(self) -> Self: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/pathlib/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/pathlib/__init__.pyi
index b55211baf718b..6d9b4eccee3c1 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/pathlib/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/pathlib/__init__.pyi
@@ -136,11 +136,20 @@ class PurePath(PathLike[str]):
"""True if the path is absolute (has both a root and, if applicable,
a drive).
"""
-
- def is_reserved(self) -> bool:
- """Return True if the path contains one of the special names reserved
- by the system, if any.
- """
+ if sys.version_info >= (3, 13):
+ @deprecated(
+ "Deprecated since Python 3.13; will be removed in Python 3.15. "
+ "Use `os.path.isreserved()` to detect reserved paths on Windows."
+ )
+ def is_reserved(self) -> bool:
+ """Return True if the path contains one of the special names reserved
+ by the system, if any.
+ """
+ else:
+ def is_reserved(self) -> bool:
+ """Return True if the path contains one of the special names reserved
+ by the system, if any.
+ """
if sys.version_info >= (3, 14):
def is_relative_to(self, other: StrPath) -> bool:
"""Return True if the path is relative to another path or False."""
@@ -417,7 +426,6 @@ class Path(PurePath):
Create a new directory at this given path.
"""
if sys.version_info >= (3, 14):
-
@property
def info(self) -> PathInfo:
"""
@@ -518,9 +526,20 @@ class Path(PurePath):
self, mode: str, buffering: int = -1, encoding: str | None = None, errors: str | None = None, newline: str | None = None
) -> IO[Any]: ...
- # These methods do "exist" on Windows on <3.13, but they always raise NotImplementedError.
+ # These methods do "exist" on Windows, but they always raise NotImplementedError.
if sys.platform == "win32":
- if sys.version_info < (3, 13):
+ if sys.version_info >= (3, 13):
+ # raises UnsupportedOperation:
+ def owner(self: Never, *, follow_symlinks: bool = True) -> str: # type: ignore[misc]
+ """
+ Return the login name of the file owner.
+ """
+
+ def group(self: Never, *, follow_symlinks: bool = True) -> str: # type: ignore[misc]
+ """
+ Return the group name of the file gid.
+ """
+ else:
def owner(self: Never) -> str: # type: ignore[misc]
"""
Return the login name of the file owner.
@@ -692,7 +711,7 @@ class Path(PurePath):
"""
if sys.version_info < (3, 12):
if sys.version_info >= (3, 10):
- @deprecated("Deprecated as of Python 3.10 and removed in Python 3.12. Use hardlink_to() instead.")
+ @deprecated("Deprecated since Python 3.10; removed in Python 3.12. Use `hardlink_to()` instead.")
def link_to(self, target: StrOrBytesPath) -> None:
"""
Make the target path a hard link pointing to this path.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/pkgutil.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/pkgutil.pyi
index 3aef575b3b278..955d0862fa4ea 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/pkgutil.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/pkgutil.pyi
@@ -65,6 +65,7 @@ def extend_path(path: _PathT, name: str) -> _PathT:
"""
if sys.version_info < (3, 12):
+ @deprecated("Deprecated since Python 3.3; removed in Python 3.12. Use the `importlib` module instead.")
class ImpImporter:
"""PEP 302 Finder that wraps Python's "classic" import algorithm
@@ -78,29 +79,47 @@ if sys.version_info < (3, 12):
def __init__(self, path: StrOrBytesPath | None = None) -> None: ...
+ @deprecated("Deprecated since Python 3.3; removed in Python 3.12. Use the `importlib` module instead.")
class ImpLoader:
"""PEP 302 Loader that wraps Python's "classic" import algorithm"""
def __init__(self, fullname: str, file: IO[str], filename: StrOrBytesPath, etc: tuple[str, str, int]) -> None: ...
if sys.version_info < (3, 14):
- @deprecated("Use importlib.util.find_spec() instead. Will be removed in Python 3.14.")
- def find_loader(fullname: str) -> LoaderProtocol | None:
- """Find a "loader" object for fullname
-
- This is a backwards compatibility wrapper around
- importlib.util.find_spec that converts most failures to ImportError
- and only returns the loader rather than the full spec
- """
-
- @deprecated("Use importlib.util.find_spec() instead. Will be removed in Python 3.14.")
- def get_loader(module_or_name: str) -> LoaderProtocol | None:
- """Get a "loader" object for module_or_name
-
- Returns None if the module cannot be found or imported.
- If the named module is not already imported, its containing package
- (if any) is imported, in order to establish the package __path__.
- """
+ if sys.version_info >= (3, 12):
+ @deprecated("Deprecated since Python 3.12; removed in Python 3.14. Use `importlib.util.find_spec()` instead.")
+ def find_loader(fullname: str) -> LoaderProtocol | None:
+ """Find a "loader" object for fullname
+
+ This is a backwards compatibility wrapper around
+ importlib.util.find_spec that converts most failures to ImportError
+ and only returns the loader rather than the full spec
+ """
+
+ @deprecated("Deprecated since Python 3.12; removed in Python 3.14. Use `importlib.util.find_spec()` instead.")
+ def get_loader(module_or_name: str) -> LoaderProtocol | None:
+ """Get a "loader" object for module_or_name
+
+ Returns None if the module cannot be found or imported.
+ If the named module is not already imported, its containing package
+ (if any) is imported, in order to establish the package __path__.
+ """
+ else:
+ def find_loader(fullname: str) -> LoaderProtocol | None:
+ """Find a "loader" object for fullname
+
+ This is a backwards compatibility wrapper around
+ importlib.util.find_spec that converts most failures to ImportError
+ and only returns the loader rather than the full spec
+ """
+
+ def get_loader(module_or_name: str) -> LoaderProtocol | None:
+ """Get a "loader" object for module_or_name
+
+ Returns None if the module cannot be found or imported.
+ If the named module is not already imported, its containing package
+ (if any) is imported, in order to establish the package __path__.
+ """
def get_importer(path_item: StrOrBytesPath) -> PathEntryFinderProtocol | None:
"""Retrieve a finder for the given path item
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/platform.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/platform.pyi
index f4646f70ec2e5..bb9cd3d717b7c 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/platform.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/platform.pyi
@@ -9,7 +9,7 @@ format is usable as part of a filename.
import sys
from typing import NamedTuple, type_check_only
-from typing_extensions import Self
+from typing_extensions import Self, deprecated
def libc_ver(executable: str | None = None, lib: str = "", version: str = "", chunksize: int = 16384) -> tuple[str, str]:
"""Tries to determine the libc version that the file executable
@@ -40,19 +40,42 @@ def mac_ver(
which default to ''. All tuple entries are strings.
"""
-def java_ver(
- release: str = "", vendor: str = "", vminfo: tuple[str, str, str] = ("", "", ""), osinfo: tuple[str, str, str] = ("", "", "")
-) -> tuple[str, str, tuple[str, str, str], tuple[str, str, str]]:
- """Version interface for Jython.
+if sys.version_info >= (3, 13):
+ @deprecated("Deprecated since Python 3.13; will be removed in Python 3.15.")
+ def java_ver(
+ release: str = "",
+ vendor: str = "",
+ vminfo: tuple[str, str, str] = ("", "", ""),
+ osinfo: tuple[str, str, str] = ("", "", ""),
+ ) -> tuple[str, str, tuple[str, str, str], tuple[str, str, str]]:
+ """Version interface for Jython.
- Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
- a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
- tuple (os_name, os_version, os_arch).
+ Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
+ a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
+ tuple (os_name, os_version, os_arch).
- Values which cannot be determined are set to the defaults
- given as parameters (which all default to '').
+ Values which cannot be determined are set to the defaults
+ given as parameters (which all default to '').
- """
+ """
+
+else:
+ def java_ver(
+ release: str = "",
+ vendor: str = "",
+ vminfo: tuple[str, str, str] = ("", "", ""),
+ osinfo: tuple[str, str, str] = ("", "", ""),
+ ) -> tuple[str, str, tuple[str, str, str], tuple[str, str, str]]:
+ """Version interface for Jython.
+
+ Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
+ a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
+ tuple (os_name, os_version, os_arch).
+
+ Values which cannot be determined are set to the defaults
+ given as parameters (which all default to '').
+
+ """
def system_alias(system: str, release: str, version: str) -> tuple[str, str, str]:
"""Returns (system, release, version) aliased to common
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/pty.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/pty.pyi
index 0038f4a77ebda..28d5ae4280124 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/pty.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/pty.pyi
@@ -19,20 +19,34 @@ if sys.platform != "win32":
Open a pty master/slave pair, using os.openpty() if possible.
"""
if sys.version_info < (3, 14):
- @deprecated("Deprecated in 3.12, to be removed in 3.14; use openpty() instead")
- def master_open() -> tuple[int, str]:
- """master_open() -> (master_fd, slave_name)
- Open a pty master and return the fd, and the filename of the slave end.
- Deprecated, use openpty() instead.
- """
-
- @deprecated("Deprecated in 3.12, to be removed in 3.14; use openpty() instead")
- def slave_open(tty_name: str) -> int:
- """slave_open(tty_name) -> slave_fd
- Open the pty slave and acquire the controlling terminal, returning
- opened filedescriptor.
- Deprecated, use openpty() instead.
- """
+ if sys.version_info >= (3, 12):
+ @deprecated("Deprecated since Python 3.12; removed in Python 3.14. Use `openpty()` instead.")
+ def master_open() -> tuple[int, str]:
+ """master_open() -> (master_fd, slave_name)
+ Open a pty master and return the fd, and the filename of the slave end.
+ Deprecated, use openpty() instead.
+ """
+
+ @deprecated("Deprecated since Python 3.12; removed in Python 3.14. Use `openpty()` instead.")
+ def slave_open(tty_name: str) -> int:
+ """slave_open(tty_name) -> slave_fd
+ Open the pty slave and acquire the controlling terminal, returning
+ opened filedescriptor.
+ Deprecated, use openpty() instead.
+ """
+ else:
+ def master_open() -> tuple[int, str]:
+ """master_open() -> (master_fd, slave_name)
+ Open a pty master and return the fd, and the filename of the slave end.
+ Deprecated, use openpty() instead.
+ """
+
+ def slave_open(tty_name: str) -> int:
+ """slave_open(tty_name) -> slave_fd
+ Open the pty slave and acquire the controlling terminal, returning
+ opened filedescriptor.
+ Deprecated, use openpty() instead.
+ """
def fork() -> tuple[int, int]:
"""fork() -> (pid, master_fd)
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/pydoc.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/pydoc.pyi
index 8a57f8289f728..0a056f84f9a1d 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/pydoc.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/pydoc.pyi
@@ -44,7 +44,7 @@ from builtins import list as _list # "list" conflicts with method name
from collections.abc import Callable, Container, Mapping, MutableMapping
from reprlib import Repr
from types import MethodType, ModuleType, TracebackType
-from typing import IO, Any, AnyStr, Final, NoReturn, Protocol, TypeVar
+from typing import IO, Any, AnyStr, Final, NoReturn, Protocol, TypeVar, type_check_only
from typing_extensions import TypeGuard, deprecated
__all__ = ["help"]
@@ -56,6 +56,7 @@ __date__: Final[str]
__version__: Final[str]
__credits__: Final[str]
+@type_check_only
class _Pager(Protocol):
def __call__(self, text: str, title: str = "") -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/quopri.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/quopri.pyi
index 68b18731771c3..4594503f76e3c 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/quopri.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/quopri.pyi
@@ -1,10 +1,11 @@
"""Conversions to/from quoted-printable transport encoding as per RFC 1521."""
from _typeshed import ReadableBuffer, SupportsNoArgReadline, SupportsRead, SupportsWrite
-from typing import Protocol
+from typing import Protocol, type_check_only
__all__ = ["encode", "decode", "encodestring", "decodestring"]
+@type_check_only
class _Input(SupportsRead[bytes], SupportsNoArgReadline[bytes], Protocol): ...
def encode(input: _Input, output: SupportsWrite[bytes], quotetabs: int, header: bool = False) -> None:
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/re.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/re.pyi
index 19d5fdade7e56..af6be98d28d49 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/re.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/re.pyi
@@ -114,7 +114,7 @@ from _typeshed import MaybeNone, ReadableBuffer
from collections.abc import Callable, Iterator, Mapping
from types import GenericAlias
from typing import Any, AnyStr, Final, Generic, Literal, TypeVar, final, overload
-from typing_extensions import TypeAlias
+from typing_extensions import TypeAlias, deprecated
__all__ = [
"match",
@@ -564,5 +564,10 @@ def purge() -> None:
"""Clear the regular expression caches"""
if sys.version_info < (3, 13):
- def template(pattern: AnyStr | Pattern[AnyStr], flags: _FlagsType = 0) -> Pattern[AnyStr]:
- """Compile a template pattern, returning a Pattern object, deprecated"""
+ if sys.version_info >= (3, 11):
+ @deprecated("Deprecated since Python 3.11; removed in Python 3.13. Use `re.compile()` instead.")
+ def template(pattern: AnyStr | Pattern[AnyStr], flags: _FlagsType = 0) -> Pattern[AnyStr]: # undocumented
+ """Compile a template pattern, returning a Pattern object, deprecated"""
+ else:
+ def template(pattern: AnyStr | Pattern[AnyStr], flags: _FlagsType = 0) -> Pattern[AnyStr]: # undocumented
+ """Compile a template pattern, returning a Pattern object"""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/shutil.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/shutil.pyi
index 81fb8d861675c..8a79660dff987 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/shutil.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/shutil.pyi
@@ -9,7 +9,7 @@ import sys
from _typeshed import BytesPath, ExcInfo, FileDescriptorOrPath, MaybeNone, StrOrBytesPath, StrPath, SupportsRead, SupportsWrite
from collections.abc import Callable, Iterable, Sequence
from tarfile import _TarfileFilter
-from typing import Any, AnyStr, NamedTuple, NoReturn, Protocol, TypeVar, overload
+from typing import Any, AnyStr, NamedTuple, NoReturn, Protocol, TypeVar, overload, type_check_only
from typing_extensions import TypeAlias, deprecated
__all__ = [
@@ -193,6 +193,7 @@ def copytree(
_OnErrorCallback: TypeAlias = Callable[[Callable[..., Any], str, ExcInfo], object]
_OnExcCallback: TypeAlias = Callable[[Callable[..., Any], str, BaseException], object]
+@type_check_only
class _RmtreeType(Protocol):
avoids_symlink_attacks: bool
if sys.version_info >= (3, 12):
@@ -393,7 +394,7 @@ def make_archive(
'base_name' is the name of the file to create, minus any format-specific
extension; 'format' is the archive format: one of "zip", "tar", "gztar",
- "bztar", "zstdtar", or "xztar". Or any other registered format.
+ "bztar", "xztar", or "zstdtar". Or any other registered format.
'root_dir' is a directory that will be the root directory of the
archive; ie. we typically chdir into 'root_dir' before creating the
@@ -441,7 +442,7 @@ def unpack_archive(
is unpacked. If not provided, the current working directory is used.
`format` is the archive format: one of "zip", "tar", "gztar", "bztar",
- or "xztar". Or any other registered format. If not provided,
+ "xztar", or "zstdtar". Or any other registered format. If not provided,
unpack_archive will use the filename extension and see if an unpacker
was registered for that extension.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/smtpd.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/smtpd.pyi
index 242544fb72a1b..b201659d1b2fe 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/smtpd.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/smtpd.pyi
@@ -49,7 +49,7 @@ import socket
import sys
from collections import defaultdict
from typing import Any
-from typing_extensions import TypeAlias
+from typing_extensions import TypeAlias, deprecated
if sys.version_info >= (3, 11):
__all__ = ["SMTPChannel", "SMTPServer", "DebuggingServer", "PureProxy"]
@@ -160,5 +160,6 @@ class PureProxy(SMTPServer):
def process_message(self, peer: _Address, mailfrom: str, rcpttos: list[str], data: bytes | str) -> str | None: ... # type: ignore[override]
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.9; removed in Python 3.11.")
class MailmanProxy(PureProxy):
def process_message(self, peer: _Address, mailfrom: str, rcpttos: list[str], data: bytes | str) -> str | None: ... # type: ignore[override]
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/smtplib.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/smtplib.pyi
index b134010a9b115..9c5dc852c248a 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/smtplib.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/smtplib.pyi
@@ -39,7 +39,7 @@ from re import Pattern
from socket import socket
from ssl import SSLContext
from types import TracebackType
-from typing import Any, Protocol, overload
+from typing import Any, Protocol, overload, type_check_only
from typing_extensions import Self, TypeAlias
__all__ = [
@@ -154,6 +154,7 @@ def quotedata(data: str) -> str:
internet CRLF end-of-line.
"""
+@type_check_only
class _AuthObject(Protocol):
@overload
def __call__(self, challenge: None = None, /) -> str | None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/socket.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/socket.pyi
index 7bed33aec346a..95551819860b7 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/socket.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/socket.pyi
@@ -1098,14 +1098,12 @@ if sys.version_info >= (3, 14):
if sys.platform == "linux":
from _socket import (
- CAN_RAW_ERR_FILTER as CAN_RAW_ERR_FILTER,
IP_FREEBIND as IP_FREEBIND,
IP_RECVORIGDSTADDR as IP_RECVORIGDSTADDR,
- SO_ORIGINAL_DST as SO_ORIGINAL_DST,
VMADDR_CID_LOCAL as VMADDR_CID_LOCAL,
)
- __all__ += ["CAN_RAW_ERR_FILTER", "IP_FREEBIND", "IP_RECVORIGDSTADDR", "VMADDR_CID_LOCAL"]
+ __all__ += ["IP_FREEBIND", "IP_RECVORIGDSTADDR", "VMADDR_CID_LOCAL"]
# Re-exported from errno
EBADF: int
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/sqlite3/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/sqlite3/__init__.pyi
index ff9fec4735db2..ae46b544a5dec 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/sqlite3/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/sqlite3/__init__.pyi
@@ -257,22 +257,26 @@ _Parameters: TypeAlias = SupportsLenAndGetItem[_AdaptedInputData] | Mapping[str,
# Controls the legacy transaction handling mode of sqlite3.
_IsolationLevel: TypeAlias = Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None
+@type_check_only
class _AnyParamWindowAggregateClass(Protocol):
def step(self, *args: Any) -> object: ...
def inverse(self, *args: Any) -> object: ...
def value(self) -> _SqliteData: ...
def finalize(self) -> _SqliteData: ...
+@type_check_only
class _WindowAggregateClass(Protocol):
step: Callable[..., object]
inverse: Callable[..., object]
def value(self) -> _SqliteData: ...
def finalize(self) -> _SqliteData: ...
+@type_check_only
class _AggregateProtocol(Protocol):
def step(self, value: int, /) -> object: ...
def finalize(self) -> int: ...
+@type_check_only
class _SingleParamWindowAggregateClass(Protocol):
def step(self, param: Any, /) -> object: ...
def inverse(self, param: Any, /) -> object: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/ssl.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/ssl.pyi
index bb22a067e37e3..f81f51970a1ad 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/ssl.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/ssl.pyi
@@ -117,7 +117,7 @@ from _ssl import (
)
from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer
from collections.abc import Callable, Iterable
-from typing import Any, Literal, NamedTuple, TypedDict, overload, type_check_only
+from typing import Any, Final, Literal, NamedTuple, TypedDict, overload, type_check_only
from typing_extensions import Never, Self, TypeAlias, deprecated
if sys.version_info >= (3, 13):
@@ -140,6 +140,7 @@ _SrvnmeCbType: TypeAlias = Callable[[SSLSocket | SSLObject, str | None, SSLSocke
socket_error = OSError
+@type_check_only
class _Cipher(TypedDict):
aead: bool
alg_bits: int
@@ -275,9 +276,9 @@ class VerifyMode(enum.IntEnum):
CERT_OPTIONAL = 1
CERT_REQUIRED = 2
-CERT_NONE: VerifyMode
-CERT_OPTIONAL: VerifyMode
-CERT_REQUIRED: VerifyMode
+CERT_NONE: Final = VerifyMode.CERT_NONE
+CERT_OPTIONAL: Final = VerifyMode.CERT_OPTIONAL
+CERT_REQUIRED: Final = VerifyMode.CERT_REQUIRED
class VerifyFlags(enum.IntFlag):
"""An enumeration."""
@@ -291,15 +292,15 @@ class VerifyFlags(enum.IntFlag):
VERIFY_ALLOW_PROXY_CERTS = 64
VERIFY_X509_PARTIAL_CHAIN = 524288
-VERIFY_DEFAULT: VerifyFlags
-VERIFY_CRL_CHECK_LEAF: VerifyFlags
-VERIFY_CRL_CHECK_CHAIN: VerifyFlags
-VERIFY_X509_STRICT: VerifyFlags
-VERIFY_X509_TRUSTED_FIRST: VerifyFlags
+VERIFY_DEFAULT: Final = VerifyFlags.VERIFY_DEFAULT
+VERIFY_CRL_CHECK_LEAF: Final = VerifyFlags.VERIFY_CRL_CHECK_LEAF
+VERIFY_CRL_CHECK_CHAIN: Final = VerifyFlags.VERIFY_CRL_CHECK_CHAIN
+VERIFY_X509_STRICT: Final = VerifyFlags.VERIFY_X509_STRICT
+VERIFY_X509_TRUSTED_FIRST: Final = VerifyFlags.VERIFY_X509_TRUSTED_FIRST
if sys.version_info >= (3, 10):
- VERIFY_ALLOW_PROXY_CERTS: VerifyFlags
- VERIFY_X509_PARTIAL_CHAIN: VerifyFlags
+ VERIFY_ALLOW_PROXY_CERTS: Final = VerifyFlags.VERIFY_ALLOW_PROXY_CERTS
+ VERIFY_X509_PARTIAL_CHAIN: Final = VerifyFlags.VERIFY_X509_PARTIAL_CHAIN
class _SSLMethod(enum.IntEnum):
"""An enumeration."""
@@ -314,15 +315,15 @@ class _SSLMethod(enum.IntEnum):
PROTOCOL_TLS_CLIENT = 16
PROTOCOL_TLS_SERVER = 17
-PROTOCOL_SSLv23: _SSLMethod
-PROTOCOL_SSLv2: _SSLMethod
-PROTOCOL_SSLv3: _SSLMethod
-PROTOCOL_TLSv1: _SSLMethod
-PROTOCOL_TLSv1_1: _SSLMethod
-PROTOCOL_TLSv1_2: _SSLMethod
-PROTOCOL_TLS: _SSLMethod
-PROTOCOL_TLS_CLIENT: _SSLMethod
-PROTOCOL_TLS_SERVER: _SSLMethod
+PROTOCOL_SSLv23: Final = _SSLMethod.PROTOCOL_SSLv23
+PROTOCOL_SSLv2: Final = _SSLMethod.PROTOCOL_SSLv2
+PROTOCOL_SSLv3: Final = _SSLMethod.PROTOCOL_SSLv3
+PROTOCOL_TLSv1: Final = _SSLMethod.PROTOCOL_TLSv1
+PROTOCOL_TLSv1_1: Final = _SSLMethod.PROTOCOL_TLSv1_1
+PROTOCOL_TLSv1_2: Final = _SSLMethod.PROTOCOL_TLSv1_2
+PROTOCOL_TLS: Final = _SSLMethod.PROTOCOL_TLS
+PROTOCOL_TLS_CLIENT: Final = _SSLMethod.PROTOCOL_TLS_CLIENT
+PROTOCOL_TLS_SERVER: Final = _SSLMethod.PROTOCOL_TLS_SERVER
class Options(enum.IntFlag):
"""An enumeration."""
@@ -347,29 +348,29 @@ class Options(enum.IntFlag):
if sys.version_info >= (3, 11) or sys.platform == "linux":
OP_IGNORE_UNEXPECTED_EOF = 128
-OP_ALL: Options
-OP_NO_SSLv2: Options
-OP_NO_SSLv3: Options
-OP_NO_TLSv1: Options
-OP_NO_TLSv1_1: Options
-OP_NO_TLSv1_2: Options
-OP_NO_TLSv1_3: Options
-OP_CIPHER_SERVER_PREFERENCE: Options
-OP_SINGLE_DH_USE: Options
-OP_SINGLE_ECDH_USE: Options
-OP_NO_COMPRESSION: Options
-OP_NO_TICKET: Options
-OP_NO_RENEGOTIATION: Options
-OP_ENABLE_MIDDLEBOX_COMPAT: Options
+OP_ALL: Final = Options.OP_ALL
+OP_NO_SSLv2: Final = Options.OP_NO_SSLv2
+OP_NO_SSLv3: Final = Options.OP_NO_SSLv3
+OP_NO_TLSv1: Final = Options.OP_NO_TLSv1
+OP_NO_TLSv1_1: Final = Options.OP_NO_TLSv1_1
+OP_NO_TLSv1_2: Final = Options.OP_NO_TLSv1_2
+OP_NO_TLSv1_3: Final = Options.OP_NO_TLSv1_3
+OP_CIPHER_SERVER_PREFERENCE: Final = Options.OP_CIPHER_SERVER_PREFERENCE
+OP_SINGLE_DH_USE: Final = Options.OP_SINGLE_DH_USE
+OP_SINGLE_ECDH_USE: Final = Options.OP_SINGLE_ECDH_USE
+OP_NO_COMPRESSION: Final = Options.OP_NO_COMPRESSION
+OP_NO_TICKET: Final = Options.OP_NO_TICKET
+OP_NO_RENEGOTIATION: Final = Options.OP_NO_RENEGOTIATION
+OP_ENABLE_MIDDLEBOX_COMPAT: Final = Options.OP_ENABLE_MIDDLEBOX_COMPAT
if sys.version_info >= (3, 12):
- OP_LEGACY_SERVER_CONNECT: Options
- OP_ENABLE_KTLS: Options
+ OP_LEGACY_SERVER_CONNECT: Final = Options.OP_LEGACY_SERVER_CONNECT
+ OP_ENABLE_KTLS: Final = Options.OP_ENABLE_KTLS
if sys.version_info >= (3, 11) or sys.platform == "linux":
- OP_IGNORE_UNEXPECTED_EOF: Options
+ OP_IGNORE_UNEXPECTED_EOF: Final = Options.OP_IGNORE_UNEXPECTED_EOF
-HAS_NEVER_CHECK_COMMON_NAME: bool
+HAS_NEVER_CHECK_COMMON_NAME: Final[bool]
-CHANNEL_BINDING_TYPES: list[str]
+CHANNEL_BINDING_TYPES: Final[list[str]]
class AlertDescription(enum.IntEnum):
"""An enumeration."""
@@ -402,33 +403,33 @@ class AlertDescription(enum.IntEnum):
ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION = 110
ALERT_DESCRIPTION_USER_CANCELLED = 90
-ALERT_DESCRIPTION_HANDSHAKE_FAILURE: AlertDescription
-ALERT_DESCRIPTION_INTERNAL_ERROR: AlertDescription
-ALERT_DESCRIPTION_ACCESS_DENIED: AlertDescription
-ALERT_DESCRIPTION_BAD_CERTIFICATE: AlertDescription
-ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE: AlertDescription
-ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE: AlertDescription
-ALERT_DESCRIPTION_BAD_RECORD_MAC: AlertDescription
-ALERT_DESCRIPTION_CERTIFICATE_EXPIRED: AlertDescription
-ALERT_DESCRIPTION_CERTIFICATE_REVOKED: AlertDescription
-ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN: AlertDescription
-ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE: AlertDescription
-ALERT_DESCRIPTION_CLOSE_NOTIFY: AlertDescription
-ALERT_DESCRIPTION_DECODE_ERROR: AlertDescription
-ALERT_DESCRIPTION_DECOMPRESSION_FAILURE: AlertDescription
-ALERT_DESCRIPTION_DECRYPT_ERROR: AlertDescription
-ALERT_DESCRIPTION_ILLEGAL_PARAMETER: AlertDescription
-ALERT_DESCRIPTION_INSUFFICIENT_SECURITY: AlertDescription
-ALERT_DESCRIPTION_NO_RENEGOTIATION: AlertDescription
-ALERT_DESCRIPTION_PROTOCOL_VERSION: AlertDescription
-ALERT_DESCRIPTION_RECORD_OVERFLOW: AlertDescription
-ALERT_DESCRIPTION_UNEXPECTED_MESSAGE: AlertDescription
-ALERT_DESCRIPTION_UNKNOWN_CA: AlertDescription
-ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY: AlertDescription
-ALERT_DESCRIPTION_UNRECOGNIZED_NAME: AlertDescription
-ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: AlertDescription
-ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: AlertDescription
-ALERT_DESCRIPTION_USER_CANCELLED: AlertDescription
+ALERT_DESCRIPTION_HANDSHAKE_FAILURE: Final = AlertDescription.ALERT_DESCRIPTION_HANDSHAKE_FAILURE
+ALERT_DESCRIPTION_INTERNAL_ERROR: Final = AlertDescription.ALERT_DESCRIPTION_INTERNAL_ERROR
+ALERT_DESCRIPTION_ACCESS_DENIED: Final = AlertDescription.ALERT_DESCRIPTION_ACCESS_DENIED
+ALERT_DESCRIPTION_BAD_CERTIFICATE: Final = AlertDescription.ALERT_DESCRIPTION_BAD_CERTIFICATE
+ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE: Final = AlertDescription.ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE
+ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE: Final = AlertDescription.ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE
+ALERT_DESCRIPTION_BAD_RECORD_MAC: Final = AlertDescription.ALERT_DESCRIPTION_BAD_RECORD_MAC
+ALERT_DESCRIPTION_CERTIFICATE_EXPIRED: Final = AlertDescription.ALERT_DESCRIPTION_CERTIFICATE_EXPIRED
+ALERT_DESCRIPTION_CERTIFICATE_REVOKED: Final = AlertDescription.ALERT_DESCRIPTION_CERTIFICATE_REVOKED
+ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN: Final = AlertDescription.ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN
+ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE: Final = AlertDescription.ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE
+ALERT_DESCRIPTION_CLOSE_NOTIFY: Final = AlertDescription.ALERT_DESCRIPTION_CLOSE_NOTIFY
+ALERT_DESCRIPTION_DECODE_ERROR: Final = AlertDescription.ALERT_DESCRIPTION_DECODE_ERROR
+ALERT_DESCRIPTION_DECOMPRESSION_FAILURE: Final = AlertDescription.ALERT_DESCRIPTION_DECOMPRESSION_FAILURE
+ALERT_DESCRIPTION_DECRYPT_ERROR: Final = AlertDescription.ALERT_DESCRIPTION_DECRYPT_ERROR
+ALERT_DESCRIPTION_ILLEGAL_PARAMETER: Final = AlertDescription.ALERT_DESCRIPTION_ILLEGAL_PARAMETER
+ALERT_DESCRIPTION_INSUFFICIENT_SECURITY: Final = AlertDescription.ALERT_DESCRIPTION_INSUFFICIENT_SECURITY
+ALERT_DESCRIPTION_NO_RENEGOTIATION: Final = AlertDescription.ALERT_DESCRIPTION_NO_RENEGOTIATION
+ALERT_DESCRIPTION_PROTOCOL_VERSION: Final = AlertDescription.ALERT_DESCRIPTION_PROTOCOL_VERSION
+ALERT_DESCRIPTION_RECORD_OVERFLOW: Final = AlertDescription.ALERT_DESCRIPTION_RECORD_OVERFLOW
+ALERT_DESCRIPTION_UNEXPECTED_MESSAGE: Final = AlertDescription.ALERT_DESCRIPTION_UNEXPECTED_MESSAGE
+ALERT_DESCRIPTION_UNKNOWN_CA: Final = AlertDescription.ALERT_DESCRIPTION_UNKNOWN_CA
+ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY: Final = AlertDescription.ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY
+ALERT_DESCRIPTION_UNRECOGNIZED_NAME: Final = AlertDescription.ALERT_DESCRIPTION_UNRECOGNIZED_NAME
+ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: Final = AlertDescription.ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE
+ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: Final = AlertDescription.ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION
+ALERT_DESCRIPTION_USER_CANCELLED: Final = AlertDescription.ALERT_DESCRIPTION_USER_CANCELLED
# This class is not exposed. It calls itself ssl._ASN1Object.
@type_check_only
@@ -894,20 +895,20 @@ class SSLErrorNumber(enum.IntEnum):
SSL_ERROR_WANT_X509_LOOKUP = 4
SSL_ERROR_ZERO_RETURN = 6
-SSL_ERROR_EOF: SSLErrorNumber # undocumented
-SSL_ERROR_INVALID_ERROR_CODE: SSLErrorNumber # undocumented
-SSL_ERROR_SSL: SSLErrorNumber # undocumented
-SSL_ERROR_SYSCALL: SSLErrorNumber # undocumented
-SSL_ERROR_WANT_CONNECT: SSLErrorNumber # undocumented
-SSL_ERROR_WANT_READ: SSLErrorNumber # undocumented
-SSL_ERROR_WANT_WRITE: SSLErrorNumber # undocumented
-SSL_ERROR_WANT_X509_LOOKUP: SSLErrorNumber # undocumented
-SSL_ERROR_ZERO_RETURN: SSLErrorNumber # undocumented
+SSL_ERROR_EOF: Final = SSLErrorNumber.SSL_ERROR_EOF # undocumented
+SSL_ERROR_INVALID_ERROR_CODE: Final = SSLErrorNumber.SSL_ERROR_INVALID_ERROR_CODE # undocumented
+SSL_ERROR_SSL: Final = SSLErrorNumber.SSL_ERROR_SSL # undocumented
+SSL_ERROR_SYSCALL: Final = SSLErrorNumber.SSL_ERROR_SYSCALL # undocumented
+SSL_ERROR_WANT_CONNECT: Final = SSLErrorNumber.SSL_ERROR_WANT_CONNECT # undocumented
+SSL_ERROR_WANT_READ: Final = SSLErrorNumber.SSL_ERROR_WANT_READ # undocumented
+SSL_ERROR_WANT_WRITE: Final = SSLErrorNumber.SSL_ERROR_WANT_WRITE # undocumented
+SSL_ERROR_WANT_X509_LOOKUP: Final = SSLErrorNumber.SSL_ERROR_WANT_X509_LOOKUP # undocumented
+SSL_ERROR_ZERO_RETURN: Final = SSLErrorNumber.SSL_ERROR_ZERO_RETURN # undocumented
def get_protocol_name(protocol_code: int) -> str: ...
-PEM_FOOTER: str
-PEM_HEADER: str
-SOCK_STREAM: int
-SOL_SOCKET: int
-SO_TYPE: int
+PEM_FOOTER: Final[str]
+PEM_HEADER: Final[str]
+SOCK_STREAM: Final = socket.SOCK_STREAM
+SOL_SOCKET: Final = socket.SOL_SOCKET
+SO_TYPE: Final = socket.SO_TYPE
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/sys/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/sys/__init__.pyi
index 4a61b2efbd3c2..6f8783c351dd7 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/sys/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/sys/__init__.pyi
@@ -289,6 +289,18 @@ class _flags(_UninstantiableStructseq, tuple[int, ...]):
@property
def safe_path(self) -> bool:
"""-P"""
+ if sys.version_info >= (3, 13):
+ @property
+ def gil(self) -> Literal[0, 1]:
+ """-X gil"""
+ if sys.version_info >= (3, 14):
+ @property
+ def thread_inherit_context(self) -> Literal[0, 1]:
+ """-X thread_inherit_context"""
+
+ @property
+ def context_aware_warnings(self) -> Literal[0, 1]:
+ """-X context_aware_warnings"""
# Whether or not this exists on lower versions of Python
# may depend on which patch release you're using
# (it was backported to all Python versions on 3.8+ as a security fix)
@@ -688,6 +700,7 @@ def settrace(function: TraceFunction | None, /) -> None:
if sys.platform == "win32":
# A tuple of length 5, even though it has more than 5 attributes.
@final
+ @type_check_only
class _WinVersion(_UninstantiableStructseq, tuple[int, int, int, int, str]):
@property
def major(self) -> int: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/termios.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/termios.pyi
index e8113ccde2266..a8c402ab07309 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/termios.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/termios.pyi
@@ -10,7 +10,7 @@ sys.stdin.fileno(), or a file object, such as sys.stdin itself.
import sys
from _typeshed import FileDescriptorLike
-from typing import Any
+from typing import Any, Final
from typing_extensions import TypeAlias
# Must be a list of length 7, containing 6 ints and a list of NCCS 1-character bytes or ints.
@@ -19,286 +19,287 @@ _Attr: TypeAlias = list[int | list[bytes | int]] | list[int | list[bytes]] | lis
_AttrReturn: TypeAlias = list[Any]
if sys.platform != "win32":
- B0: int
- B110: int
- B115200: int
- B1200: int
- B134: int
- B150: int
- B1800: int
- B19200: int
- B200: int
- B230400: int
- B2400: int
- B300: int
- B38400: int
- B4800: int
- B50: int
- B57600: int
- B600: int
- B75: int
- B9600: int
- BRKINT: int
- BS0: int
- BS1: int
- BSDLY: int
- CDSUSP: int
- CEOF: int
- CEOL: int
- CEOT: int
- CERASE: int
- CFLUSH: int
- CINTR: int
- CKILL: int
- CLNEXT: int
- CLOCAL: int
- CQUIT: int
- CR0: int
- CR1: int
- CR2: int
- CR3: int
- CRDLY: int
- CREAD: int
- CRPRNT: int
- CRTSCTS: int
- CS5: int
- CS6: int
- CS7: int
- CS8: int
- CSIZE: int
- CSTART: int
- CSTOP: int
- CSTOPB: int
- CSUSP: int
- CWERASE: int
- ECHO: int
- ECHOCTL: int
- ECHOE: int
- ECHOK: int
- ECHOKE: int
- ECHONL: int
- ECHOPRT: int
- EXTA: int
- EXTB: int
- FF0: int
- FF1: int
- FFDLY: int
- FIOASYNC: int
- FIOCLEX: int
- FIONBIO: int
- FIONCLEX: int
- FIONREAD: int
- FLUSHO: int
- HUPCL: int
- ICANON: int
- ICRNL: int
- IEXTEN: int
- IGNBRK: int
- IGNCR: int
- IGNPAR: int
- IMAXBEL: int
- INLCR: int
- INPCK: int
- ISIG: int
- ISTRIP: int
- IXANY: int
- IXOFF: int
- IXON: int
- NCCS: int
- NL0: int
- NL1: int
- NLDLY: int
- NOFLSH: int
- OCRNL: int
- OFDEL: int
- OFILL: int
- ONLCR: int
- ONLRET: int
- ONOCR: int
- OPOST: int
- PARENB: int
- PARMRK: int
- PARODD: int
- PENDIN: int
- TAB0: int
- TAB1: int
- TAB2: int
- TAB3: int
- TABDLY: int
- TCIFLUSH: int
- TCIOFF: int
- TCIOFLUSH: int
- TCION: int
- TCOFLUSH: int
- TCOOFF: int
- TCOON: int
- TCSADRAIN: int
- TCSAFLUSH: int
- TCSANOW: int
- TIOCCONS: int
- TIOCEXCL: int
- TIOCGETD: int
- TIOCGPGRP: int
- TIOCGWINSZ: int
- TIOCM_CAR: int
- TIOCM_CD: int
- TIOCM_CTS: int
- TIOCM_DSR: int
- TIOCM_DTR: int
- TIOCM_LE: int
- TIOCM_RI: int
- TIOCM_RNG: int
- TIOCM_RTS: int
- TIOCM_SR: int
- TIOCM_ST: int
- TIOCMBIC: int
- TIOCMBIS: int
- TIOCMGET: int
- TIOCMSET: int
- TIOCNOTTY: int
- TIOCNXCL: int
- TIOCOUTQ: int
- TIOCPKT_DATA: int
- TIOCPKT_DOSTOP: int
- TIOCPKT_FLUSHREAD: int
- TIOCPKT_FLUSHWRITE: int
- TIOCPKT_NOSTOP: int
- TIOCPKT_START: int
- TIOCPKT_STOP: int
- TIOCPKT: int
- TIOCSCTTY: int
- TIOCSETD: int
- TIOCSPGRP: int
- TIOCSTI: int
- TIOCSWINSZ: int
- TOSTOP: int
- VDISCARD: int
- VEOF: int
- VEOL: int
- VEOL2: int
- VERASE: int
- VINTR: int
- VKILL: int
- VLNEXT: int
- VMIN: int
- VQUIT: int
- VREPRINT: int
- VSTART: int
- VSTOP: int
- VSUSP: int
- VT0: int
- VT1: int
- VTDLY: int
- VTIME: int
- VWERASE: int
+ # Values depends on the platform
+ B0: Final[int]
+ B110: Final[int]
+ B115200: Final[int]
+ B1200: Final[int]
+ B134: Final[int]
+ B150: Final[int]
+ B1800: Final[int]
+ B19200: Final[int]
+ B200: Final[int]
+ B230400: Final[int]
+ B2400: Final[int]
+ B300: Final[int]
+ B38400: Final[int]
+ B4800: Final[int]
+ B50: Final[int]
+ B57600: Final[int]
+ B600: Final[int]
+ B75: Final[int]
+ B9600: Final[int]
+ BRKINT: Final[int]
+ BS0: Final[int]
+ BS1: Final[int]
+ BSDLY: Final[int]
+ CDSUSP: Final[int]
+ CEOF: Final[int]
+ CEOL: Final[int]
+ CEOT: Final[int]
+ CERASE: Final[int]
+ CFLUSH: Final[int]
+ CINTR: Final[int]
+ CKILL: Final[int]
+ CLNEXT: Final[int]
+ CLOCAL: Final[int]
+ CQUIT: Final[int]
+ CR0: Final[int]
+ CR1: Final[int]
+ CR2: Final[int]
+ CR3: Final[int]
+ CRDLY: Final[int]
+ CREAD: Final[int]
+ CRPRNT: Final[int]
+ CRTSCTS: Final[int]
+ CS5: Final[int]
+ CS6: Final[int]
+ CS7: Final[int]
+ CS8: Final[int]
+ CSIZE: Final[int]
+ CSTART: Final[int]
+ CSTOP: Final[int]
+ CSTOPB: Final[int]
+ CSUSP: Final[int]
+ CWERASE: Final[int]
+ ECHO: Final[int]
+ ECHOCTL: Final[int]
+ ECHOE: Final[int]
+ ECHOK: Final[int]
+ ECHOKE: Final[int]
+ ECHONL: Final[int]
+ ECHOPRT: Final[int]
+ EXTA: Final[int]
+ EXTB: Final[int]
+ FF0: Final[int]
+ FF1: Final[int]
+ FFDLY: Final[int]
+ FIOASYNC: Final[int]
+ FIOCLEX: Final[int]
+ FIONBIO: Final[int]
+ FIONCLEX: Final[int]
+ FIONREAD: Final[int]
+ FLUSHO: Final[int]
+ HUPCL: Final[int]
+ ICANON: Final[int]
+ ICRNL: Final[int]
+ IEXTEN: Final[int]
+ IGNBRK: Final[int]
+ IGNCR: Final[int]
+ IGNPAR: Final[int]
+ IMAXBEL: Final[int]
+ INLCR: Final[int]
+ INPCK: Final[int]
+ ISIG: Final[int]
+ ISTRIP: Final[int]
+ IXANY: Final[int]
+ IXOFF: Final[int]
+ IXON: Final[int]
+ NCCS: Final[int]
+ NL0: Final[int]
+ NL1: Final[int]
+ NLDLY: Final[int]
+ NOFLSH: Final[int]
+ OCRNL: Final[int]
+ OFDEL: Final[int]
+ OFILL: Final[int]
+ ONLCR: Final[int]
+ ONLRET: Final[int]
+ ONOCR: Final[int]
+ OPOST: Final[int]
+ PARENB: Final[int]
+ PARMRK: Final[int]
+ PARODD: Final[int]
+ PENDIN: Final[int]
+ TAB0: Final[int]
+ TAB1: Final[int]
+ TAB2: Final[int]
+ TAB3: Final[int]
+ TABDLY: Final[int]
+ TCIFLUSH: Final[int]
+ TCIOFF: Final[int]
+ TCIOFLUSH: Final[int]
+ TCION: Final[int]
+ TCOFLUSH: Final[int]
+ TCOOFF: Final[int]
+ TCOON: Final[int]
+ TCSADRAIN: Final[int]
+ TCSAFLUSH: Final[int]
+ TCSANOW: Final[int]
+ TIOCCONS: Final[int]
+ TIOCEXCL: Final[int]
+ TIOCGETD: Final[int]
+ TIOCGPGRP: Final[int]
+ TIOCGWINSZ: Final[int]
+ TIOCM_CAR: Final[int]
+ TIOCM_CD: Final[int]
+ TIOCM_CTS: Final[int]
+ TIOCM_DSR: Final[int]
+ TIOCM_DTR: Final[int]
+ TIOCM_LE: Final[int]
+ TIOCM_RI: Final[int]
+ TIOCM_RNG: Final[int]
+ TIOCM_RTS: Final[int]
+ TIOCM_SR: Final[int]
+ TIOCM_ST: Final[int]
+ TIOCMBIC: Final[int]
+ TIOCMBIS: Final[int]
+ TIOCMGET: Final[int]
+ TIOCMSET: Final[int]
+ TIOCNOTTY: Final[int]
+ TIOCNXCL: Final[int]
+ TIOCOUTQ: Final[int]
+ TIOCPKT_DATA: Final[int]
+ TIOCPKT_DOSTOP: Final[int]
+ TIOCPKT_FLUSHREAD: Final[int]
+ TIOCPKT_FLUSHWRITE: Final[int]
+ TIOCPKT_NOSTOP: Final[int]
+ TIOCPKT_START: Final[int]
+ TIOCPKT_STOP: Final[int]
+ TIOCPKT: Final[int]
+ TIOCSCTTY: Final[int]
+ TIOCSETD: Final[int]
+ TIOCSPGRP: Final[int]
+ TIOCSTI: Final[int]
+ TIOCSWINSZ: Final[int]
+ TOSTOP: Final[int]
+ VDISCARD: Final[int]
+ VEOF: Final[int]
+ VEOL: Final[int]
+ VEOL2: Final[int]
+ VERASE: Final[int]
+ VINTR: Final[int]
+ VKILL: Final[int]
+ VLNEXT: Final[int]
+ VMIN: Final[int]
+ VQUIT: Final[int]
+ VREPRINT: Final[int]
+ VSTART: Final[int]
+ VSTOP: Final[int]
+ VSUSP: Final[int]
+ VT0: Final[int]
+ VT1: Final[int]
+ VTDLY: Final[int]
+ VTIME: Final[int]
+ VWERASE: Final[int]
if sys.version_info >= (3, 13):
- EXTPROC: int
- IUTF8: int
+ EXTPROC: Final[int]
+ IUTF8: Final[int]
if sys.platform == "darwin" and sys.version_info >= (3, 13):
- ALTWERASE: int
- B14400: int
- B28800: int
- B7200: int
- B76800: int
- CCAR_OFLOW: int
- CCTS_OFLOW: int
- CDSR_OFLOW: int
- CDTR_IFLOW: int
- CIGNORE: int
- CRTS_IFLOW: int
- MDMBUF: int
- NL2: int
- NL3: int
- NOKERNINFO: int
- ONOEOT: int
- OXTABS: int
- VDSUSP: int
- VSTATUS: int
+ ALTWERASE: Final[int]
+ B14400: Final[int]
+ B28800: Final[int]
+ B7200: Final[int]
+ B76800: Final[int]
+ CCAR_OFLOW: Final[int]
+ CCTS_OFLOW: Final[int]
+ CDSR_OFLOW: Final[int]
+ CDTR_IFLOW: Final[int]
+ CIGNORE: Final[int]
+ CRTS_IFLOW: Final[int]
+ MDMBUF: Final[int]
+ NL2: Final[int]
+ NL3: Final[int]
+ NOKERNINFO: Final[int]
+ ONOEOT: Final[int]
+ OXTABS: Final[int]
+ VDSUSP: Final[int]
+ VSTATUS: Final[int]
if sys.platform == "darwin" and sys.version_info >= (3, 11):
- TIOCGSIZE: int
- TIOCSSIZE: int
+ TIOCGSIZE: Final[int]
+ TIOCSSIZE: Final[int]
if sys.platform == "linux":
- B1152000: int
- B576000: int
- CBAUD: int
- CBAUDEX: int
- CIBAUD: int
- IOCSIZE_MASK: int
- IOCSIZE_SHIFT: int
- IUCLC: int
- N_MOUSE: int
- N_PPP: int
- N_SLIP: int
- N_STRIP: int
- N_TTY: int
- NCC: int
- OLCUC: int
- TCFLSH: int
- TCGETA: int
- TCGETS: int
- TCSBRK: int
- TCSBRKP: int
- TCSETA: int
- TCSETAF: int
- TCSETAW: int
- TCSETS: int
- TCSETSF: int
- TCSETSW: int
- TCXONC: int
- TIOCGICOUNT: int
- TIOCGLCKTRMIOS: int
- TIOCGSERIAL: int
- TIOCGSOFTCAR: int
- TIOCINQ: int
- TIOCLINUX: int
- TIOCMIWAIT: int
- TIOCTTYGSTRUCT: int
- TIOCSER_TEMT: int
- TIOCSERCONFIG: int
- TIOCSERGETLSR: int
- TIOCSERGETMULTI: int
- TIOCSERGSTRUCT: int
- TIOCSERGWILD: int
- TIOCSERSETMULTI: int
- TIOCSERSWILD: int
- TIOCSLCKTRMIOS: int
- TIOCSSERIAL: int
- TIOCSSOFTCAR: int
- VSWTC: int
- VSWTCH: int
- XCASE: int
- XTABS: int
+ B1152000: Final[int]
+ B576000: Final[int]
+ CBAUD: Final[int]
+ CBAUDEX: Final[int]
+ CIBAUD: Final[int]
+ IOCSIZE_MASK: Final[int]
+ IOCSIZE_SHIFT: Final[int]
+ IUCLC: Final[int]
+ N_MOUSE: Final[int]
+ N_PPP: Final[int]
+ N_SLIP: Final[int]
+ N_STRIP: Final[int]
+ N_TTY: Final[int]
+ NCC: Final[int]
+ OLCUC: Final[int]
+ TCFLSH: Final[int]
+ TCGETA: Final[int]
+ TCGETS: Final[int]
+ TCSBRK: Final[int]
+ TCSBRKP: Final[int]
+ TCSETA: Final[int]
+ TCSETAF: Final[int]
+ TCSETAW: Final[int]
+ TCSETS: Final[int]
+ TCSETSF: Final[int]
+ TCSETSW: Final[int]
+ TCXONC: Final[int]
+ TIOCGICOUNT: Final[int]
+ TIOCGLCKTRMIOS: Final[int]
+ TIOCGSERIAL: Final[int]
+ TIOCGSOFTCAR: Final[int]
+ TIOCINQ: Final[int]
+ TIOCLINUX: Final[int]
+ TIOCMIWAIT: Final[int]
+ TIOCTTYGSTRUCT: Final[int]
+ TIOCSER_TEMT: Final[int]
+ TIOCSERCONFIG: Final[int]
+ TIOCSERGETLSR: Final[int]
+ TIOCSERGETMULTI: Final[int]
+ TIOCSERGSTRUCT: Final[int]
+ TIOCSERGWILD: Final[int]
+ TIOCSERSETMULTI: Final[int]
+ TIOCSERSWILD: Final[int]
+ TIOCSLCKTRMIOS: Final[int]
+ TIOCSSERIAL: Final[int]
+ TIOCSSOFTCAR: Final[int]
+ VSWTC: Final[int]
+ VSWTCH: Final[int]
+ XCASE: Final[int]
+ XTABS: Final[int]
if sys.platform != "darwin":
- B1000000: int
- B1500000: int
- B2000000: int
- B2500000: int
- B3000000: int
- B3500000: int
- B4000000: int
- B460800: int
- B500000: int
- B921600: int
+ B1000000: Final[int]
+ B1500000: Final[int]
+ B2000000: Final[int]
+ B2500000: Final[int]
+ B3000000: Final[int]
+ B3500000: Final[int]
+ B4000000: Final[int]
+ B460800: Final[int]
+ B500000: Final[int]
+ B921600: Final[int]
if sys.platform != "linux":
- TCSASOFT: int
+ TCSASOFT: Final[int]
if sys.platform != "darwin" and sys.platform != "linux":
# not available on FreeBSD either.
- CDEL: int
- CEOL2: int
- CESC: int
- CNUL: int
- COMMON: int
- CSWTCH: int
- IBSHIFT: int
- INIT_C_CC: int
- NSWTCH: int
+ CDEL: Final[int]
+ CEOL2: Final[int]
+ CESC: Final[int]
+ CNUL: Final[int]
+ COMMON: Final[int]
+ CSWTCH: Final[int]
+ IBSHIFT: Final[int]
+ INIT_C_CC: Final[int]
+ NSWTCH: Final[int]
def tcgetattr(fd: FileDescriptorLike, /) -> _AttrReturn:
"""Get the tty attributes for file descriptor fd.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/time.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/time.pyi
index 796248b6aba06..5046965453766 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/time.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/time.pyi
@@ -24,7 +24,7 @@ if it is -1, mktime() should guess based on the date and time.
import sys
from _typeshed import structseq
-from typing import Any, Final, Literal, Protocol, final
+from typing import Any, Final, Literal, Protocol, final, type_check_only
from typing_extensions import TypeAlias
_TimeTuple: TypeAlias = tuple[int, int, int, int, int, int, int, int, int]
@@ -250,6 +250,7 @@ if sys.platform != "win32":
should not be relied on.
"""
+@type_check_only
class _ClockInfo(Protocol):
adjustable: bool
implementation: str
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi
index d7e6a912ad686..5625aac9c1253 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi
@@ -589,12 +589,14 @@ def getboolean(s):
_Ts = TypeVarTuple("_Ts")
+@type_check_only
class _GridIndexInfo(TypedDict, total=False):
minsize: _ScreenUnits
pad: _ScreenUnits
uniform: str | None
weight: int
+@type_check_only
class _BusyInfo(TypedDict):
cursor: _Cursor
@@ -2286,6 +2288,7 @@ class Tk(Misc, Wm):
def loadtk(self) -> None: ...
def record(self, script, /): ...
if sys.version_info < (3, 11):
+ @deprecated("Deprecated since Python 3.9; removed in Python 3.11. Use `splitlist()` instead.")
def split(self, arg, /): ...
def splitlist(self, arg, /): ...
@@ -2298,6 +2301,7 @@ def Tcl(screenName: str | None = None, baseName: str | None = None, className: s
_InMiscTotal = TypedDict("_InMiscTotal", {"in": Misc})
_InMiscNonTotal = TypedDict("_InMiscNonTotal", {"in": Misc}, total=False)
+@type_check_only
class _PackInfo(_InMiscTotal):
# 'before' and 'after' never appear in _PackInfo
anchor: _Anchor
@@ -2365,6 +2369,7 @@ class Pack:
forget = pack_forget
propagate = Misc.pack_propagate
+@type_check_only
class _PlaceInfo(_InMiscNonTotal): # empty dict if widget hasn't been placed
anchor: _Anchor
bordermode: Literal["inside", "outside", "ignore"]
@@ -2433,6 +2438,7 @@ class Place:
place = place_configure
info = place_info
+@type_check_only
class _GridInfo(_InMiscNonTotal): # empty dict if widget hasn't been gridded
column: int
columnspan: int
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/dnd.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/dnd.pyi
index aafa9144f0aa0..18906bd604937 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/dnd.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/dnd.pyi
@@ -100,10 +100,11 @@ active; it will never call dnd_commit().
"""
from tkinter import Event, Misc, Tk, Widget
-from typing import ClassVar, Protocol
+from typing import ClassVar, Protocol, type_check_only
__all__ = ["dnd_start", "DndHandler"]
+@type_check_only
class _DndSource(Protocol):
def dnd_end(self, target: Widget | None, event: Event[Misc] | None, /) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/font.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/font.pyi
index dd9deae85d2d2..879f51b1e6e60 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/font.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/font.pyi
@@ -2,7 +2,7 @@ import _tkinter
import itertools
import sys
import tkinter
-from typing import Any, ClassVar, Final, Literal, TypedDict, overload
+from typing import Any, ClassVar, Final, Literal, TypedDict, overload, type_check_only
from typing_extensions import TypeAlias, Unpack
__all__ = ["NORMAL", "ROMAN", "BOLD", "ITALIC", "nametofont", "Font", "families", "names"]
@@ -23,6 +23,7 @@ _FontDescription: TypeAlias = (
| _tkinter.Tcl_Obj # A font object constructed in Tcl
)
+@type_check_only
class _FontDict(TypedDict):
family: str
size: int
@@ -31,6 +32,7 @@ class _FontDict(TypedDict):
underline: bool
overstrike: bool
+@type_check_only
class _MetricsDict(TypedDict):
ascent: int
descent: int
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/ttk.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/ttk.pyi
index c59ebf0969142..2a3f476235d81 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/ttk.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/tkinter/ttk.pyi
@@ -17,7 +17,7 @@ import tkinter
from _typeshed import Incomplete, MaybeNone
from collections.abc import Callable
from tkinter.font import _FontDescription
-from typing import Any, Literal, TypedDict, overload
+from typing import Any, Literal, TypedDict, overload, type_check_only
from typing_extensions import TypeAlias
__all__ = [
@@ -1679,6 +1679,7 @@ class Spinbox(Entry):
def set(self, value: Any) -> None:
"""Sets the value of the Spinbox to value."""
+@type_check_only
class _TreeviewItemDict(TypedDict):
text: str
image: list[str] | Literal[""] # no idea why it's wrapped in list
@@ -1686,6 +1687,7 @@ class _TreeviewItemDict(TypedDict):
open: bool # actually 0 or 1
tags: list[str] | Literal[""]
+@type_check_only
class _TreeviewTagDict(TypedDict):
# There is also 'text' and 'anchor', but they don't seem to do anything, using them is likely a bug
foreground: str
@@ -1693,6 +1695,7 @@ class _TreeviewTagDict(TypedDict):
font: _FontDescription
image: str # not wrapped in list :D
+@type_check_only
class _TreeviewHeaderDict(TypedDict):
text: str
image: list[str] | Literal[""]
@@ -1700,6 +1703,7 @@ class _TreeviewHeaderDict(TypedDict):
command: str
state: str # Doesn't seem to appear anywhere else than in these dicts
+@type_check_only
class _TreeviewColumnDict(TypedDict):
width: int
minwidth: int
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/tty.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/tty.pyi
index 00ef5c39dfbc4..0219428d92bba 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/tty.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/tty.pyi
@@ -17,13 +17,13 @@ if sys.platform != "win32":
_FD: TypeAlias = int | IO[str]
# XXX: Undocumented integer constants
- IFLAG: Final[int]
- OFLAG: Final[int]
- CFLAG: Final[int]
- LFLAG: Final[int]
- ISPEED: Final[int]
- OSPEED: Final[int]
- CC: Final[int]
+ IFLAG: Final = 0
+ OFLAG: Final = 1
+ CFLAG: Final = 2
+ LFLAG: Final = 3
+ ISPEED: Final = 4
+ OSPEED: Final = 5
+ CC: Final = 6
def setraw(fd: _FD, when: int = 2) -> _ModeSetterReturn:
"""Put terminal into raw mode."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/turtle.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/turtle.pyi
index 24f098d7bac76..8fbdfbc3bef03 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/turtle.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/turtle.pyi
@@ -80,8 +80,8 @@ from _typeshed import StrPath
from collections.abc import Callable, Generator, Sequence
from contextlib import contextmanager
from tkinter import Canvas, Frame, Misc, PhotoImage, Scrollbar
-from typing import Any, ClassVar, Literal, TypedDict, overload
-from typing_extensions import Self, TypeAlias
+from typing import Any, ClassVar, Literal, TypedDict, overload, type_check_only
+from typing_extensions import Self, TypeAlias, deprecated
__all__ = [
"ScrolledCanvas",
@@ -223,6 +223,7 @@ if sys.version_info < (3, 13):
_Color: TypeAlias = str | tuple[float, float, float]
_AnyColor: TypeAlias = Any
+@type_check_only
class _PenState(TypedDict):
shown: bool
pendown: bool
@@ -1725,6 +1726,7 @@ class RawTurtle(TPen, TNavigator): # type: ignore[misc] # Conflicting methods
"""
if sys.version_info < (3, 13):
+ @deprecated("Deprecated since Python 3.1; removed in Python 3.13. Use `tiltangle()` instead.")
def settiltangle(self, angle: float) -> None:
"""Rotate the turtleshape to point in the specified direction
@@ -3619,6 +3621,7 @@ def get_shapepoly() -> _PolygonCoords | None:
"""
if sys.version_info < (3, 13):
+ @deprecated("Deprecated since Python 3.1; removed in Python 3.13. Use `tiltangle()` instead.")
def settiltangle(angle: float) -> None:
"""Rotate the turtleshape to point in the specified direction
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/typing.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/typing.pyi
index f62f5a72b751b..90743a7cc371f 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/typing.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/typing.pyi
@@ -310,15 +310,15 @@ class TypeVar:
contravariant: bool = False,
) -> None: ...
if sys.version_info >= (3, 10):
- def __or__(self, right: Any) -> _SpecialForm: # AnnotationForm
+ def __or__(self, right: Any, /) -> _SpecialForm: # AnnotationForm
"""Return self|value."""
- def __ror__(self, left: Any) -> _SpecialForm: # AnnotationForm
+ def __ror__(self, left: Any, /) -> _SpecialForm: # AnnotationForm
"""Return value|self."""
if sys.version_info >= (3, 11):
- def __typing_subst__(self, arg: Any) -> Any: ...
+ def __typing_subst__(self, arg: Any, /) -> Any: ...
if sys.version_info >= (3, 13):
- def __typing_prepare_subst__(self, alias: Any, args: Any) -> tuple[Any, ...]: ...
+ def __typing_prepare_subst__(self, alias: Any, args: Any, /) -> tuple[Any, ...]: ...
def has_default(self) -> bool: ...
if sys.version_info >= (3, 14):
@property
@@ -422,8 +422,8 @@ if sys.version_info >= (3, 11):
def __iter__(self) -> Any:
"""Implement iter(self)."""
- def __typing_subst__(self, arg: Never) -> Never: ...
- def __typing_prepare_subst__(self, alias: Any, args: Any) -> tuple[Any, ...]: ...
+ def __typing_subst__(self, arg: Never, /) -> Never: ...
+ def __typing_prepare_subst__(self, alias: Any, args: Any, /) -> tuple[Any, ...]: ...
if sys.version_info >= (3, 14):
@property
def evaluate_default(self) -> EvaluateFunc | None: ...
@@ -452,7 +452,7 @@ if sys.version_info >= (3, 10):
else:
def __init__(self, origin: ParamSpec) -> None: ...
- def __eq__(self, other: object) -> bool: ...
+ def __eq__(self, other: object, /) -> bool: ...
__hash__: ClassVar[None] # type: ignore[assignment]
@final
@@ -478,7 +478,7 @@ if sys.version_info >= (3, 10):
else:
def __init__(self, origin: ParamSpec) -> None: ...
- def __eq__(self, other: object) -> bool: ...
+ def __eq__(self, other: object, /) -> bool: ...
__hash__: ClassVar[None] # type: ignore[assignment]
@final
@@ -598,13 +598,13 @@ if sys.version_info >= (3, 10):
def kwargs(self) -> ParamSpecKwargs:
"""Represents keyword arguments."""
if sys.version_info >= (3, 11):
- def __typing_subst__(self, arg: Any) -> Any: ...
- def __typing_prepare_subst__(self, alias: Any, args: Any) -> tuple[Any, ...]: ...
+ def __typing_subst__(self, arg: Any, /) -> Any: ...
+ def __typing_prepare_subst__(self, alias: Any, args: Any, /) -> tuple[Any, ...]: ...
- def __or__(self, right: Any) -> _SpecialForm:
+ def __or__(self, right: Any, /) -> _SpecialForm:
"""Return self|value."""
- def __ror__(self, left: Any) -> _SpecialForm:
+ def __ror__(self, left: Any, /) -> _SpecialForm:
"""Return value|self."""
if sys.version_info >= (3, 13):
def has_default(self) -> bool: ...
@@ -738,6 +738,7 @@ def type_check_only(func_or_cls: _FT) -> _FT: ...
# Type aliases and type constructors
+@type_check_only
class _Alias:
# Class for defining generic aliases for library types.
def __getitem__(self, typeargs: Any) -> Any: ...
@@ -1993,13 +1994,13 @@ if sys.version_info >= (3, 12):
# It's writable on types, but not on instances of TypeAliasType.
@property
def __module__(self) -> str | None: ... # type: ignore[override]
- def __getitem__(self, parameters: Any) -> GenericAlias: # AnnotationForm
+ def __getitem__(self, parameters: Any, /) -> GenericAlias: # AnnotationForm
"""Return self[key]."""
- def __or__(self, right: Any) -> _SpecialForm:
+ def __or__(self, right: Any, /) -> _SpecialForm:
"""Return self|value."""
- def __ror__(self, left: Any) -> _SpecialForm:
+ def __ror__(self, left: Any, /) -> _SpecialForm:
"""Return value|self."""
if sys.version_info >= (3, 14):
@property
@@ -2037,6 +2038,7 @@ if sys.version_info >= (3, 13):
"""
@final
+ @type_check_only
class _NoDefaultType: ...
NoDefault: _NoDefaultType
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/typing_extensions.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/typing_extensions.pyi
index 862f678795933..49a80fcd14b3c 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/typing_extensions.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/typing_extensions.pyi
@@ -901,6 +901,7 @@ else:
"""
@final
+ @type_check_only
class _NoDefaultType: ...
NoDefault: _NoDefaultType
@@ -1122,8 +1123,8 @@ else:
def __getitem__(self, parameters: Incomplete | tuple[Incomplete, ...]) -> AnnotationForm: ...
def __init_subclass__(cls, *args: Unused, **kwargs: Unused) -> NoReturn: ...
if sys.version_info >= (3, 10):
- def __or__(self, right: Any) -> _SpecialForm: ...
- def __ror__(self, left: Any) -> _SpecialForm: ...
+ def __or__(self, right: Any, /) -> _SpecialForm: ...
+ def __ror__(self, left: Any, /) -> _SpecialForm: ...
# PEP 727
class Doc:
@@ -1150,6 +1151,7 @@ class Doc:
def __eq__(self, other: object) -> bool: ...
# PEP 728
+@type_check_only
class _NoExtraItemsType: ...
NoExtraItems: _NoExtraItemsType
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/case.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/case.pyi
index 5cc1f2cf18552..9f738eb049046 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/case.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/case.pyi
@@ -9,7 +9,7 @@ from collections.abc import Callable, Container, Iterable, Mapping, Sequence, Se
from contextlib import AbstractContextManager
from re import Pattern
from types import GenericAlias, TracebackType
-from typing import Any, AnyStr, Final, Generic, NoReturn, Protocol, SupportsAbs, SupportsRound, TypeVar, overload
+from typing import Any, AnyStr, Final, Generic, NoReturn, Protocol, SupportsAbs, SupportsRound, TypeVar, overload, type_check_only
from typing_extensions import Never, ParamSpec, Self
from unittest._log import _AssertLogsContext, _LoggingWatcher
from warnings import WarningMessage
@@ -90,6 +90,7 @@ class SkipTest(Exception):
def __init__(self, reason: str) -> None: ...
+@type_check_only
class _SupportsAbsAndDunderGE(SupportsDunderGE[Any], SupportsAbs[Any], Protocol): ...
class TestCase:
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/main.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/main.pyi
index cd55eae32a32d..924967d7f294d 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/main.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/main.pyi
@@ -7,12 +7,13 @@ import unittest.result
import unittest.suite
from collections.abc import Iterable
from types import ModuleType
-from typing import Any, Final, Protocol
+from typing import Any, Final, Protocol, type_check_only
from typing_extensions import deprecated
MAIN_EXAMPLES: Final[str]
MODULE_EXAMPLES: Final[str]
+@type_check_only
class _TestRunner(Protocol):
def run(self, test: unittest.suite.TestSuite | unittest.case.TestCase, /) -> unittest.result.TestResult: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/mock.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/mock.pyi
index be34f90126ad1..ba2ba19d86427 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/mock.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/mock.pyi
@@ -3,7 +3,7 @@ from _typeshed import MaybeNone
from collections.abc import Awaitable, Callable, Coroutine, Iterable, Mapping, Sequence
from contextlib import _GeneratorContextManager
from types import TracebackType
-from typing import Any, ClassVar, Final, Generic, Literal, TypeVar, overload
+from typing import Any, ClassVar, Final, Generic, Literal, TypeVar, overload, type_check_only
from typing_extensions import ParamSpec, Self, TypeAlias
_T = TypeVar("_T")
@@ -456,6 +456,7 @@ class _patch(Generic[_T]):
# This class does not exist at runtime, it's a hack to make this work:
# @patch("foo")
# def bar(..., mock: MagicMock) -> None: ...
+@type_check_only
class _patch_pass_arg(_patch[_T]):
@overload
def __call__(self, func: _TT) -> _TT: ...
@@ -514,6 +515,7 @@ class _patch_dict:
# This class does not exist at runtime, it's a hack to add methods to the
# patch() function.
+@type_check_only
class _patcher:
TEST_PREFIX: str
dict: type[_patch_dict]
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/runner.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/runner.pyi
index e98d381cf3f4f..3f5a9406879f2 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/unittest/runner.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/unittest/runner.pyi
@@ -6,15 +6,17 @@ import unittest.result
import unittest.suite
from _typeshed import SupportsFlush, SupportsWrite
from collections.abc import Callable, Iterable
-from typing import Any, Generic, Protocol, TypeVar
+from typing import Any, Generic, Protocol, TypeVar, type_check_only
from typing_extensions import Never, TypeAlias
from warnings import _ActionKind
_ResultClassType: TypeAlias = Callable[[_TextTestStream, bool, int], TextTestResult[Any]]
+@type_check_only
class _SupportsWriteAndFlush(SupportsWrite[str], SupportsFlush, Protocol): ...
# All methods used by unittest.runner.TextTestResult's stream
+@type_check_only
class _TextTestStream(_SupportsWriteAndFlush, Protocol):
def writeln(self, arg: str | None = None, /) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/urllib/request.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/urllib/request.pyi
index 71e3273b5b960..4d9636102ed5c 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/urllib/request.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/urllib/request.pyi
@@ -75,7 +75,7 @@ from email.message import Message
from http.client import HTTPConnection, HTTPMessage, HTTPResponse
from http.cookiejar import CookieJar
from re import Pattern
-from typing import IO, Any, ClassVar, NoReturn, Protocol, TypeVar, overload
+from typing import IO, Any, ClassVar, NoReturn, Protocol, TypeVar, overload, type_check_only
from typing_extensions import TypeAlias, deprecated
from urllib.error import HTTPError as HTTPError
from urllib.response import addclosehook, addinfourl
@@ -482,6 +482,7 @@ class ProxyDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler):
auth_header: ClassVar[str] # undocumented
def http_error_407(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> _UrlopenRet | None: ...
+@type_check_only
class _HTTPConnectionProtocol(Protocol):
def __call__(
self,
@@ -594,7 +595,7 @@ def urlcleanup() -> None:
"""Clean up temporary files from urlretrieve calls."""
if sys.version_info < (3, 14):
- @deprecated("Deprecated since Python 3.3; Removed in 3.14; Use newer urlopen functions and methods.")
+ @deprecated("Deprecated since Python 3.3; removed in Python 3.14. Use newer `urlopen` functions and methods.")
class URLopener:
"""Class to open URLs.
This is a class rather than just a subroutine because we may need
@@ -667,7 +668,7 @@ if sys.version_info < (3, 14):
def __del__(self) -> None: ...
- @deprecated("Deprecated since Python 3.3; Removed in 3.14; Use newer urlopen functions and methods.")
+ @deprecated("Deprecated since Python 3.3; removed in Python 3.14. Use newer `urlopen` functions and methods.")
class FancyURLopener(URLopener):
"""Derived class with handlers for errors we can handle (perhaps)."""
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/winreg.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/winreg.pyi
index 328e1313869d4..ca9a49b033e04 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/winreg.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/winreg.pyi
@@ -550,7 +550,7 @@ if sys.platform == "win32":
def __enter__(self) -> Self: ...
def __exit__(
- self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
+ self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None, /
) -> bool | None: ...
def Close(self) -> None:
"""Closes the underlying Windows handle.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/xml/dom/minidom.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/xml/dom/minidom.pyi
index 0db4877863b83..e455f0f4b2cd1 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/xml/dom/minidom.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/xml/dom/minidom.pyi
@@ -20,7 +20,7 @@ from _collections_abc import dict_keys, dict_values
from _typeshed import Incomplete, ReadableBuffer, SupportsRead, SupportsWrite
from collections.abc import Iterable, Sequence
from types import TracebackType
-from typing import Any, ClassVar, Generic, Literal, NoReturn, Protocol, TypeVar, overload
+from typing import Any, ClassVar, Generic, Literal, NoReturn, Protocol, TypeVar, overload, type_check_only
from typing_extensions import Self, TypeAlias
from xml.dom.minicompat import EmptyNodeList, NodeList
from xml.dom.xmlbuilder import DocumentLS, DOMImplementationLS
@@ -57,9 +57,11 @@ _ImportableNodeVar = TypeVar(
| Notation,
)
+@type_check_only
class _DOMErrorHandler(Protocol):
def handleError(self, error: Exception) -> bool: ...
+@type_check_only
class _UserDataHandler(Protocol):
def handle(self, operation: int, key: str, data: Any, src: Node, dst: Node) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementInclude.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementInclude.pyi
index 8f20ee15a14e5..fd829fdaa5ffc 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementInclude.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementInclude.pyi
@@ -1,7 +1,8 @@
from _typeshed import FileDescriptorOrPath
-from typing import Final, Literal, Protocol, overload
+from typing import Final, Literal, Protocol, overload, type_check_only
from xml.etree.ElementTree import Element
+@type_check_only
class _Loader(Protocol):
@overload
def __call__(self, href: FileDescriptorOrPath, parse: Literal["xml"], encoding: str | None = None) -> Element: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementTree.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementTree.pyi
index 68576c31a3774..a92ae79cbd1ea 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementTree.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/xml/etree/ElementTree.pyi
@@ -663,6 +663,7 @@ class C14NWriterTarget:
# The target type is tricky, because the implementation doesn't
# require any particular attribute to be present. This documents the attributes
# that can be present, but uncommenting any of them would require them.
+@type_check_only
class _Target(Protocol):
# start: Callable[str, dict[str, str], Any] | None
# end: Callable[[str], Any] | None
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/xml/sax/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/xml/sax/__init__.pyi
index 720ca5c57cf15..e9f5a4de555ea 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/xml/sax/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/xml/sax/__init__.pyi
@@ -22,7 +22,7 @@ expatreader -- Driver that allows use of the Expat parser with SAX.
import sys
from _typeshed import ReadableBuffer, StrPath, SupportsRead, _T_co
from collections.abc import Iterable
-from typing import Protocol
+from typing import Protocol, type_check_only
from typing_extensions import TypeAlias
from xml.sax._exceptions import (
SAXException as SAXException,
@@ -34,6 +34,7 @@ from xml.sax._exceptions import (
from xml.sax.handler import ContentHandler as ContentHandler, ErrorHandler as ErrorHandler
from xml.sax.xmlreader import InputSource as InputSource, XMLReader
+@type_check_only
class _SupportsReadClose(SupportsRead[_T_co], Protocol[_T_co]):
def close(self) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/client.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/client.pyi
index 02c4e94bebd6f..7a00f503ef763 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/client.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/client.pyi
@@ -48,9 +48,10 @@ from collections.abc import Callable, Iterable, Mapping
from datetime import datetime
from io import BytesIO
from types import TracebackType
-from typing import Any, ClassVar, Final, Literal, Protocol, overload
+from typing import Any, ClassVar, Final, Literal, Protocol, overload, type_check_only
from typing_extensions import Self, TypeAlias
+@type_check_only
class _SupportsTimeTuple(Protocol):
def timetuple(self) -> time.struct_time: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/server.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/server.pyi
index 0f9592e53a8c6..8b0c3fc8ee8d3 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/server.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/xmlrpc/server.pyi
@@ -107,28 +107,34 @@ import socketserver
from _typeshed import ReadableBuffer
from collections.abc import Callable, Iterable, Mapping
from re import Pattern
-from typing import Any, ClassVar, Protocol
+from typing import Any, ClassVar, Protocol, type_check_only
from typing_extensions import TypeAlias
from xmlrpc.client import Fault, _Marshallable
# The dispatch accepts anywhere from 0 to N arguments, no easy way to allow this in mypy
+@type_check_only
class _DispatchArity0(Protocol):
def __call__(self) -> _Marshallable: ...
+@type_check_only
class _DispatchArity1(Protocol):
def __call__(self, arg1: _Marshallable, /) -> _Marshallable: ...
+@type_check_only
class _DispatchArity2(Protocol):
def __call__(self, arg1: _Marshallable, arg2: _Marshallable, /) -> _Marshallable: ...
+@type_check_only
class _DispatchArity3(Protocol):
def __call__(self, arg1: _Marshallable, arg2: _Marshallable, arg3: _Marshallable, /) -> _Marshallable: ...
+@type_check_only
class _DispatchArity4(Protocol):
def __call__(
self, arg1: _Marshallable, arg2: _Marshallable, arg3: _Marshallable, arg4: _Marshallable, /
) -> _Marshallable: ...
+@type_check_only
class _DispatchArityN(Protocol):
def __call__(self, *args: _Marshallable) -> _Marshallable: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/zipfile/__init__.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/zipfile/__init__.pyi
index 1e01e76c5ab29..945c3d7365a4f 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/zipfile/__init__.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/zipfile/__init__.pyi
@@ -11,7 +11,7 @@ from collections.abc import Callable, Iterable, Iterator
from io import TextIOWrapper
from os import PathLike
from types import TracebackType
-from typing import IO, Final, Literal, Protocol, overload
+from typing import IO, Final, Literal, Protocol, overload, type_check_only
from typing_extensions import Self, TypeAlias
__all__ = [
@@ -51,6 +51,7 @@ class LargeZipFile(Exception):
and those extensions are disabled.
"""
+@type_check_only
class _ZipStream(Protocol):
def read(self, n: int, /) -> bytes: ...
# The following methods are optional:
@@ -59,11 +60,13 @@ class _ZipStream(Protocol):
# def seek(self, n: int, /) -> object: ...
# Stream shape as required by _EndRecData() and _EndRecData64().
+@type_check_only
class _SupportsReadSeekTell(Protocol):
def read(self, n: int = ..., /) -> bytes: ...
def seek(self, cookie: int, whence: int, /) -> object: ...
def tell(self) -> int: ...
+@type_check_only
class _ClosableZipStream(_ZipStream, Protocol):
def close(self) -> object: ...
@@ -120,18 +123,23 @@ class ZipExtFile(io.BufferedIOBase):
def seek(self, offset: int, whence: int = 0) -> int: ...
+@type_check_only
class _Writer(Protocol):
def write(self, s: str, /) -> object: ...
+@type_check_only
class _ZipReadable(Protocol):
def seek(self, offset: int, whence: int = 0, /) -> int: ...
def read(self, n: int = -1, /) -> bytes: ...
+@type_check_only
class _ZipTellable(Protocol):
def tell(self) -> int: ...
+@type_check_only
class _ZipReadableTellable(_ZipReadable, _ZipTellable, Protocol): ...
+@type_check_only
class _ZipWritable(Protocol):
def flush(self) -> None: ...
def close(self) -> None: ...
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/zipimport.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/zipimport.pyi
index 1cd54d940bb3c..d0025b07f0521 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/zipimport.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/zipimport.pyi
@@ -53,30 +53,54 @@ class zipimporter(_LoaderBasics):
def __init__(self, path: StrOrBytesPath) -> None: ...
if sys.version_info < (3, 12):
- def find_loader(self, fullname: str, path: str | None = None) -> tuple[zipimporter | None, list[str]]: # undocumented
- """find_loader(fullname, path=None) -> self, str or None.
-
- Search for a module specified by 'fullname'. 'fullname' must be the
- fully qualified (dotted) module name. It returns the zipimporter
- instance itself if the module was found, a string containing the
- full path name if it's possibly a portion of a namespace package,
- or None otherwise. The optional 'path' argument is ignored -- it's
- there for compatibility with the importer protocol.
-
- Deprecated since Python 3.10. Use find_spec() instead.
- """
-
- def find_module(self, fullname: str, path: str | None = None) -> zipimporter | None:
- """find_module(fullname, path=None) -> self or None.
-
- Search for a module specified by 'fullname'. 'fullname' must be the
- fully qualified (dotted) module name. It returns the zipimporter
- instance itself if the module was found, or None if it wasn't.
- The optional 'path' argument is ignored -- it's there for compatibility
- with the importer protocol.
-
- Deprecated since Python 3.10. Use find_spec() instead.
- """
+ if sys.version_info >= (3, 10):
+ @deprecated("Deprecated since Python 3.10; removed in Python 3.12. Use `find_spec()` instead.")
+ def find_loader(self, fullname: str, path: str | None = None) -> tuple[zipimporter | None, list[str]]:
+ """find_loader(fullname, path=None) -> self, str or None.
+
+ Search for a module specified by 'fullname'. 'fullname' must be the
+ fully qualified (dotted) module name. It returns the zipimporter
+ instance itself if the module was found, a string containing the
+ full path name if it's possibly a portion of a namespace package,
+ or None otherwise. The optional 'path' argument is ignored -- it's
+ there for compatibility with the importer protocol.
+
+ Deprecated since Python 3.10. Use find_spec() instead.
+ """
+
+ @deprecated("Deprecated since Python 3.10; removed in Python 3.12. Use `find_spec()` instead.")
+ def find_module(self, fullname: str, path: str | None = None) -> zipimporter | None:
+ """find_module(fullname, path=None) -> self or None.
+
+ Search for a module specified by 'fullname'. 'fullname' must be the
+ fully qualified (dotted) module name. It returns the zipimporter
+ instance itself if the module was found, or None if it wasn't.
+ The optional 'path' argument is ignored -- it's there for compatibility
+ with the importer protocol.
+
+ Deprecated since Python 3.10. Use find_spec() instead.
+ """
+ else:
+ def find_loader(self, fullname: str, path: str | None = None) -> tuple[zipimporter | None, list[str]]:
+ """find_loader(fullname, path=None) -> self, str or None.
+
+ Search for a module specified by 'fullname'. 'fullname' must be the
+ fully qualified (dotted) module name. It returns the zipimporter
+ instance itself if the module was found, a string containing the
+ full path name if it's possibly a portion of a namespace package,
+ or None otherwise. The optional 'path' argument is ignored -- it's
+ there for compatibility with the importer protocol.
+ """
+
+ def find_module(self, fullname: str, path: str | None = None) -> zipimporter | None:
+ """find_module(fullname, path=None) -> self or None.
+
+ Search for a module specified by 'fullname'. 'fullname' must be the
+ fully qualified (dotted) module name. It returns the zipimporter
+ instance itself if the module was found, or None if it wasn't.
+ The optional 'path' argument is ignored -- it's there for compatibility
+ with the importer protocol.
+ """
def get_code(self, fullname: str) -> CodeType:
"""get_code(fullname) -> code object.
@@ -126,18 +150,18 @@ class zipimporter(_LoaderBasics):
Return True if the module specified by fullname is a package.
Raise ZipImportError if the module couldn't be found.
"""
+ if sys.version_info >= (3, 10):
+ @deprecated("Deprecated since Python 3.10; removed in Python 3.15. Use `exec_module()` instead.")
+ def load_module(self, fullname: str) -> ModuleType:
+ """load_module(fullname) -> module.
- @deprecated("Deprecated since 3.10; use exec_module() instead")
- def load_module(self, fullname: str) -> ModuleType:
- """load_module(fullname) -> module.
+ Load the module specified by 'fullname'. 'fullname' must be the
+ fully qualified (dotted) module name. It returns the imported
+ module, or raises ZipImportError if it could not be imported.
- Load the module specified by 'fullname'. 'fullname' must be the
- fully qualified (dotted) module name. It returns the imported
- module, or raises ZipImportError if it could not be imported.
+ Deprecated since Python 3.10. Use exec_module() instead.
+ """
- Deprecated since Python 3.10. Use exec_module() instead.
- """
- if sys.version_info >= (3, 10):
def exec_module(self, module: ModuleType) -> None:
"""Execute the module."""
@@ -152,3 +176,11 @@ class zipimporter(_LoaderBasics):
def invalidate_caches(self) -> None:
"""Invalidates the cache of file data of the archive path."""
+ else:
+ def load_module(self, fullname: str) -> ModuleType:
+ """load_module(fullname) -> module.
+
+ Load the module specified by 'fullname'. 'fullname' must be the
+ fully qualified (dotted) module name. It returns the imported
+ module, or raises ZipImportError if it wasn't found.
+ """
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/zlib.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/zlib.pyi
index 93e1ac5c1e77f..97d70804a36fe 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/zlib.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/zlib.pyi
@@ -19,11 +19,11 @@ from typing import Any, Final, final, type_check_only
from typing_extensions import Self
DEFLATED: Final = 8
-DEF_MEM_LEVEL: int # can change
+DEF_MEM_LEVEL: Final[int]
DEF_BUF_SIZE: Final = 16384
-MAX_WBITS: int
-ZLIB_VERSION: str # can change
-ZLIB_RUNTIME_VERSION: str # can change
+MAX_WBITS: Final[int]
+ZLIB_VERSION: Final[str]
+ZLIB_RUNTIME_VERSION: Final[str]
Z_NO_COMPRESSION: Final = 0
Z_PARTIAL_FLUSH: Final = 1
Z_BEST_COMPRESSION: Final = 9
@@ -41,6 +41,10 @@ Z_RLE: Final = 3
Z_SYNC_FLUSH: Final = 2
Z_TREES: Final = 6
+if sys.version_info >= (3, 14) and sys.platform == "win32":
+ # Available when zlib was built with zlib-ng, usually only on Windows
+ ZLIBNG_VERSION: Final[str]
+
class error(Exception): ...
# This class is not exposed at runtime. It calls itself zlib.Compress.
diff --git a/crates/ty_vendored/vendor/typeshed/stdlib/zoneinfo/_common.pyi b/crates/ty_vendored/vendor/typeshed/stdlib/zoneinfo/_common.pyi
index b527aab5669f5..69ddef03f693a 100644
--- a/crates/ty_vendored/vendor/typeshed/stdlib/zoneinfo/_common.pyi
+++ b/crates/ty_vendored/vendor/typeshed/stdlib/zoneinfo/_common.pyi
@@ -1,6 +1,7 @@
import io
-from typing import Any, Protocol
+from typing import Any, Protocol, type_check_only
+@type_check_only
class _IOBytes(Protocol):
def read(self, size: int, /) -> bytes: ...
def seek(self, size: int, whence: int = ..., /) -> Any: ...
From 6de84ed56eac4f1f3efe9d8a9d47c9b30a445707 Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Fri, 15 Aug 2025 14:52:30 +0100
Subject: [PATCH 008/160] Add `else`-branch narrowing for `if type(a) is A`
when `A` is `@final` (#19925)
---
.../resources/mdtest/narrow/type.md | 44 ++++++++++++++++++-
crates/ty_python_semantic/src/types/narrow.rs | 9 ++--
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/type.md b/crates/ty_python_semantic/resources/mdtest/narrow/type.md
index 004d53be3fa97..0376ca8d0466c 100644
--- a/crates/ty_python_semantic/resources/mdtest/narrow/type.md
+++ b/crates/ty_python_semantic/resources/mdtest/narrow/type.md
@@ -3,10 +3,15 @@
## `type(x) is C`
```py
+from typing import final
+
class A: ...
class B: ...
-def _(x: A | B):
+@final
+class C: ...
+
+def _(x: A | B, y: A | C):
if type(x) is A:
reveal_type(x) # revealed: A
else:
@@ -14,20 +19,55 @@ def _(x: A | B):
# of `x` could be a subclass of `A`, so we need
# to infer the full union type:
reveal_type(x) # revealed: A | B
+
+ if type(y) is C:
+ reveal_type(y) # revealed: C
+ else:
+ # here, however, inferring `A` is fine,
+ # because `C` is `@final`: no subclass of `A`
+ # and `C` could exist
+ reveal_type(y) # revealed: A
+
+ if type(y) is A:
+ reveal_type(y) # revealed: A
+ else:
+ # but here, `type(y)` could be a subclass of `A`,
+ # in which case the `type(y) is A` call would evaluate
+ # to `False` even if `y` was an instance of `A`,
+ # so narrowing cannot occur
+ reveal_type(y) # revealed: A | C
```
## `type(x) is not C`
```py
+from typing import final
+
class A: ...
class B: ...
-def _(x: A | B):
+@final
+class C: ...
+
+def _(x: A | B, y: A | C):
if type(x) is not A:
# Same reasoning as above: no narrowing should occur here.
reveal_type(x) # revealed: A | B
else:
reveal_type(x) # revealed: A
+
+ if type(y) is not C:
+ # same reasoning as above: narrowing *can* occur here because `C` is `@final`
+ reveal_type(y) # revealed: A
+ else:
+ reveal_type(y) # revealed: C
+
+ if type(y) is not A:
+ # same reasoning as above: narrowing *cannot* occur here
+ # because `A` is not `@final`
+ reveal_type(y) # revealed: A | C
+ else:
+ reveal_type(y) # revealed: A
```
## `type(x) == C`, `type(x) != C`
diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs
index 2693570e1c228..39c2ba402dfef 100644
--- a/crates/ty_python_semantic/src/types/narrow.rs
+++ b/crates/ty_python_semantic/src/types/narrow.rs
@@ -772,13 +772,15 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
_ => continue,
};
- let is_valid_constraint = if is_positive {
+ let is_positive = if is_positive {
op == &ast::CmpOp::Is
} else {
op == &ast::CmpOp::IsNot
};
- if !is_valid_constraint {
+ // `else`-branch narrowing for `if type(x) is Y` can only be done
+ // if `Y` is a final class
+ if !rhs_class.is_final(self.db) && !is_positive {
continue;
}
@@ -791,7 +793,8 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
let place = self.expect_place(&target);
constraints.insert(
place,
- Type::instance(self.db, rhs_class.unknown_specialization(self.db)),
+ Type::instance(self.db, rhs_class.unknown_specialization(self.db))
+ .negate_if(self.db, !is_positive),
);
}
}
From f344dda82c0478b8ea3cc2d510b21e7933f4c89c Mon Sep 17 00:00:00 2001
From: Micha Reiser
Date: Fri, 15 Aug 2025 17:55:38 +0200
Subject: [PATCH 009/160] Bump Rust MSRV to 1.87 (#19924)
---
Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Cargo.toml b/Cargo.toml
index bed513fe3de47..ce3061284af48 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,7 @@ resolver = "2"
[workspace.package]
# Please update rustfmt.toml when bumping the Rust edition
edition = "2024"
-rust-version = "1.86"
+rust-version = "1.87"
homepage = "https://docs.astral.sh/ruff"
documentation = "https://docs.astral.sh/ruff"
repository = "https://github.com/astral-sh/ruff"
From 9ced219ffcc698c2fa99c0580d09ee79889a8cf6 Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Fri, 15 Aug 2025 17:52:14 +0100
Subject: [PATCH 010/160] [ty] Remove incorrect type narrowing for `if type(x)
is C[int]` (#19926)
---
.../resources/mdtest/narrow/type.md | 50 +++++++++++++++++++
crates/ty_python_semantic/src/types/narrow.rs | 8 +--
2 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/type.md b/crates/ty_python_semantic/resources/mdtest/narrow/type.md
index 0376ca8d0466c..ef754d021ae7e 100644
--- a/crates/ty_python_semantic/resources/mdtest/narrow/type.md
+++ b/crates/ty_python_semantic/resources/mdtest/narrow/type.md
@@ -70,6 +70,56 @@ def _(x: A | B, y: A | C):
reveal_type(y) # revealed: A
```
+## No narrowing for `type(x) is C[int]`
+
+At runtime, `type(x)` will never return a generic alias object (only ever a class-literal object),
+so no narrowing can occur if `type(x)` is compared with a generic alias object.
+
+```toml
+[environment]
+python-version = "3.12"
+```
+
+```py
+class A[T]: ...
+class B: ...
+
+def f(x: A[int] | B):
+ if type(x) is A[int]:
+ # this branch is actually unreachable -- we *could* reveal `Never` here!
+ reveal_type(x) # revealed: A[int] | B
+ else:
+ reveal_type(x) # revealed: A[int] | B
+
+ if type(x) is A:
+ # TODO: this should be `A[int]`, but `A[int] | B` would be better than `Never`
+ reveal_type(x) # revealed: Never
+ else:
+ reveal_type(x) # revealed: A[int] | B
+
+ if type(x) is B:
+ reveal_type(x) # revealed: B
+ else:
+ reveal_type(x) # revealed: A[int] | B
+
+ if type(x) is not A[int]:
+ reveal_type(x) # revealed: A[int] | B
+ else:
+ # this branch is actually unreachable -- we *could* reveal `Never` here!
+ reveal_type(x) # revealed: A[int] | B
+
+ if type(x) is not A:
+ reveal_type(x) # revealed: A[int] | B
+ else:
+ # TODO: this should be `A[int]`, but `A[int] | B` would be better than `Never`
+ reveal_type(x) # revealed: Never
+
+ if type(x) is not B:
+ reveal_type(x) # revealed: A[int] | B
+ else:
+ reveal_type(x) # revealed: B
+```
+
## `type(x) == C`, `type(x) != C`
No narrowing can occur for equality comparisons, since there might be a custom `__eq__`
diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs
index 39c2ba402dfef..8569c961d5d8d 100644
--- a/crates/ty_python_semantic/src/types/narrow.rs
+++ b/crates/ty_python_semantic/src/types/narrow.rs
@@ -756,12 +756,8 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
node_index: _,
},
}) if keywords.is_empty() => {
- let rhs_class = match rhs_ty {
- Type::ClassLiteral(class) => class,
- Type::GenericAlias(alias) => alias.origin(self.db),
- _ => {
- continue;
- }
+ let Type::ClassLiteral(rhs_class) = rhs_ty else {
+ continue;
};
let target = match &**args {
From 26d6c3831f237a511507c9cf5498e89f6f1d72d4 Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Fri, 15 Aug 2025 18:20:14 +0100
Subject: [PATCH 011/160] [ty] Represent `NamedTuple` as an opaque special
form, not a class (#19915)
---
.../resources/mdtest/named_tuple.md | 82 +++++++++++++++++++
crates/ty_python_semantic/src/types.rs | 21 ++++-
crates/ty_python_semantic/src/types/class.rs | 32 ++++----
.../src/types/class_base.rs | 26 +++---
crates/ty_python_semantic/src/types/infer.rs | 34 +++++---
.../src/types/special_form.rs | 10 +++
.../ty_extensions/ty_extensions.pyi | 25 +++++-
7 files changed, 182 insertions(+), 48 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/named_tuple.md b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
index e642b25b2eb8d..94070455c9d68 100644
--- a/crates/ty_python_semantic/resources/mdtest/named_tuple.md
+++ b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
@@ -268,6 +268,88 @@ alice = Person(1, "Alice", 42)
bob = Person(2, "Bob")
```
+## The symbol `NamedTuple` itself
+
+At runtime, `NamedTuple` is a function, and we understand this:
+
+```py
+import types
+import typing
+
+def expects_functiontype(x: types.FunctionType): ...
+
+expects_functiontype(typing.NamedTuple)
+```
+
+This means we also understand that all attributes on function objects are available on the symbol
+`typing.NamedTuple`:
+
+```py
+reveal_type(typing.NamedTuple.__name__) # revealed: str
+reveal_type(typing.NamedTuple.__qualname__) # revealed: str
+reveal_type(typing.NamedTuple.__kwdefaults__) # revealed: dict[str, Any] | None
+
+# TODO: this should cause us to emit a diagnostic and reveal `Unknown` (function objects don't have an `__mro__` attribute),
+# but the fact that we don't isn't actually a `NamedTuple` bug (https://github.com/astral-sh/ty/issues/986)
+reveal_type(typing.NamedTuple.__mro__) # revealed: tuple[, ]
+```
+
+By the normal rules, `NamedTuple` and `type[NamedTuple]` should not be valid in type expressions --
+there is no object at runtime that is an "instance of `NamedTuple`", nor is there any class at
+runtime that is a "subclass of `NamedTuple`" -- these are both impossible, since `NamedTuple` is a
+function and not a class. However, for compatibility with other type checkers, we allow `NamedTuple`
+in type expressions and understand it as describing an interface that all `NamedTuple` classes would
+satisfy:
+
+```py
+def expects_named_tuple(x: typing.NamedTuple):
+ reveal_type(x) # revealed: tuple[object, ...] & NamedTupleLike
+ reveal_type(x._make) # revealed: bound method type[NamedTupleLike]._make(iterable: Iterable[Any]) -> Self@_make
+ reveal_type(x._replace) # revealed: bound method NamedTupleLike._replace(**kwargs) -> Self@_replace
+ # revealed: Overload[(value: tuple[object, ...], /) -> tuple[object, ...], (value: tuple[_T@__add__, ...], /) -> tuple[object, ...]]
+ reveal_type(x.__add__)
+ reveal_type(x.__iter__) # revealed: bound method tuple[object, ...].__iter__() -> Iterator[object]
+
+def _(y: type[typing.NamedTuple]):
+ reveal_type(y) # revealed: @Todo(unsupported type[X] special form)
+```
+
+Any instance of a `NamedTuple` class can therefore be passed for a function parameter that is
+annotated with `NamedTuple`:
+
+```py
+from typing import NamedTuple, Protocol, Iterable, Any
+from ty_extensions import static_assert, is_assignable_to
+
+class Point(NamedTuple):
+ x: int
+ y: int
+
+reveal_type(Point._make) # revealed: bound method ._make(iterable: Iterable[Any]) -> Self@_make
+reveal_type(Point._asdict) # revealed: def _asdict(self) -> dict[str, Any]
+reveal_type(Point._replace) # revealed: def _replace(self, **kwargs: Any) -> Self@_replace
+
+static_assert(is_assignable_to(Point, NamedTuple))
+
+expects_named_tuple(Point(x=42, y=56)) # fine
+
+# error: [invalid-argument-type] "Argument to function `expects_named_tuple` is incorrect: Expected `tuple[object, ...] & NamedTupleLike`, found `tuple[Literal[1], Literal[2]]`"
+expects_named_tuple((1, 2))
+```
+
+The type described by `NamedTuple` in type expressions is understood as being assignable to
+`tuple[object, ...]` and `tuple[Any, ...]`:
+
+```py
+static_assert(is_assignable_to(NamedTuple, tuple))
+static_assert(is_assignable_to(NamedTuple, tuple[object, ...]))
+static_assert(is_assignable_to(NamedTuple, tuple[Any, ...]))
+
+def expects_tuple(x: tuple[object, ...]): ...
+def _(x: NamedTuple):
+ expects_tuple(x) # fine
+```
+
## NamedTuple with custom `__getattr__`
This is a regression test for . Make sure that the
diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs
index 89b66a6b343a3..ad7a4c0ade918 100644
--- a/crates/ty_python_semantic/src/types.rs
+++ b/crates/ty_python_semantic/src/types.rs
@@ -4264,10 +4264,6 @@ impl<'db> Type<'db> {
.into()
}
- Some(KnownClass::NamedTuple) => {
- Binding::single(self, Signature::todo("functional `NamedTuple` syntax")).into()
- }
-
Some(KnownClass::Object) => {
// ```py
// class object:
@@ -4583,6 +4579,10 @@ impl<'db> Type<'db> {
.into()
}
+ Type::SpecialForm(SpecialFormType::NamedTuple) => {
+ Binding::single(self, Signature::todo("functional `NamedTuple` syntax")).into()
+ }
+
Type::GenericAlias(_) => {
// TODO annotated return type on `__new__` or metaclass `__call__`
// TODO check call vs signatures of `__new__` and/or `__init__`
@@ -5471,6 +5471,19 @@ impl<'db> Type<'db> {
// TODO: Use an opt-in rule for a bare `Callable`
SpecialFormType::Callable => Ok(CallableType::unknown(db)),
+ // Special case: `NamedTuple` in a type expression is understood to describe the type
+ // `tuple[object, ...] & `.
+ // This isn't very principled (since at runtime, `NamedTuple` is just a function),
+ // but it appears to be what users often expect, and it improves compatibility with
+ // other type checkers such as mypy.
+ // See conversation in https://github.com/astral-sh/ruff/pull/19915.
+ SpecialFormType::NamedTuple => Ok(IntersectionBuilder::new(db)
+ .positive_elements([
+ Type::homogeneous_tuple(db, Type::object(db)),
+ KnownClass::NamedTupleLike.to_instance(db),
+ ])
+ .build()),
+
SpecialFormType::TypingSelf => {
let module = parsed_module(db, scope_id.file(db)).load(db);
let index = semantic_index(db, scope_id.file(db));
diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs
index 60cf7c491e417..cd749f8444060 100644
--- a/crates/ty_python_semantic/src/types/class.rs
+++ b/crates/ty_python_semantic/src/types/class.rs
@@ -197,10 +197,7 @@ impl CodeGeneratorKind {
Some(CodeGeneratorKind::DataclassLike)
} else if class
.explicit_bases(db)
- .iter()
- .copied()
- .filter_map(Type::into_class_literal)
- .any(|class| class.is_known(db, KnownClass::NamedTuple))
+ .contains(&Type::SpecialForm(SpecialFormType::NamedTuple))
{
Some(CodeGeneratorKind::NamedTuple)
} else if class.is_typed_dict(db) {
@@ -3137,7 +3134,6 @@ pub enum KnownClass {
TypeVarTuple,
TypeAliasType,
NoDefaultType,
- NamedTuple,
NewType,
SupportsIndex,
Iterable,
@@ -3160,6 +3156,7 @@ pub enum KnownClass {
InitVar,
// _typeshed._type_checker_internals
NamedTupleFallback,
+ NamedTupleLike,
TypedDictFallback,
}
@@ -3245,8 +3242,6 @@ impl KnownClass {
| Self::ABCMeta
| Self::Iterable
| Self::Iterator
- // Empty tuples are AlwaysFalse; non-empty tuples are AlwaysTrue
- | Self::NamedTuple
// Evaluating `NotImplementedType` in a boolean context was deprecated in Python 3.9
// and raises a `TypeError` in Python >=3.14
// (see https://docs.python.org/3/library/constants.html#NotImplemented)
@@ -3260,6 +3255,7 @@ impl KnownClass {
| Self::KwOnly
| Self::InitVar
| Self::NamedTupleFallback
+ | Self::NamedTupleLike
| Self::TypedDictFallback => Some(Truthiness::Ambiguous),
Self::Tuple => None,
@@ -3342,8 +3338,8 @@ impl KnownClass {
| Self::ExceptionGroup
| Self::Field
| Self::SupportsIndex
- | Self::NamedTuple
| Self::NamedTupleFallback
+ | Self::NamedTupleLike
| Self::TypedDictFallback
| Self::Counter
| Self::DefaultDict
@@ -3412,7 +3408,6 @@ impl KnownClass {
| KnownClass::TypeVarTuple
| KnownClass::TypeAliasType
| KnownClass::NoDefaultType
- | KnownClass::NamedTuple
| KnownClass::NewType
| KnownClass::SupportsIndex
| KnownClass::Iterable
@@ -3429,6 +3424,7 @@ impl KnownClass {
| KnownClass::KwOnly
| KnownClass::InitVar
| KnownClass::NamedTupleFallback
+ | KnownClass::NamedTupleLike
| KnownClass::TypedDictFallback => false,
}
}
@@ -3489,7 +3485,6 @@ impl KnownClass {
| KnownClass::TypeVarTuple
| KnownClass::TypeAliasType
| KnownClass::NoDefaultType
- | KnownClass::NamedTuple
| KnownClass::NewType
| KnownClass::SupportsIndex
| KnownClass::Iterable
@@ -3506,6 +3501,7 @@ impl KnownClass {
| KnownClass::KwOnly
| KnownClass::InitVar
| KnownClass::NamedTupleFallback
+ | KnownClass::NamedTupleLike
| KnownClass::TypedDictFallback => false,
}
}
@@ -3566,7 +3562,6 @@ impl KnownClass {
| KnownClass::TypeVarTuple
| KnownClass::TypeAliasType
| KnownClass::NoDefaultType
- | KnownClass::NamedTuple
| KnownClass::NewType
| KnownClass::SupportsIndex
| KnownClass::Iterable
@@ -3582,6 +3577,7 @@ impl KnownClass {
| KnownClass::KwOnly
| KnownClass::InitVar
| KnownClass::TypedDictFallback
+ | KnownClass::NamedTupleLike
| KnownClass::NamedTupleFallback => false,
}
}
@@ -3604,6 +3600,7 @@ impl KnownClass {
| Self::Iterable
| Self::Iterator
| Self::Awaitable
+ | Self::NamedTupleLike
| Self::Generator => true,
Self::Any
@@ -3648,7 +3645,6 @@ impl KnownClass {
| Self::TypeVarTuple
| Self::TypeAliasType
| Self::NoDefaultType
- | Self::NamedTuple
| Self::NewType
| Self::ChainMap
| Self::Counter
@@ -3713,7 +3709,6 @@ impl KnownClass {
Self::GeneratorType => "GeneratorType",
Self::AsyncGeneratorType => "AsyncGeneratorType",
Self::CoroutineType => "CoroutineType",
- Self::NamedTuple => "NamedTuple",
Self::NoneType => "NoneType",
Self::SpecialForm => "_SpecialForm",
Self::TypeVar => "TypeVar",
@@ -3767,6 +3762,7 @@ impl KnownClass {
Self::KwOnly => "KW_ONLY",
Self::InitVar => "InitVar",
Self::NamedTupleFallback => "NamedTupleFallback",
+ Self::NamedTupleLike => "NamedTupleLike",
Self::TypedDictFallback => "TypedDictFallback",
}
}
@@ -3984,7 +3980,6 @@ impl KnownClass {
| Self::Generator
| Self::SpecialForm
| Self::TypeVar
- | Self::NamedTuple
| Self::StdlibAlias
| Self::Iterable
| Self::Iterator
@@ -4025,6 +4020,7 @@ impl KnownClass {
| Self::OrderedDict => KnownModule::Collections,
Self::Field | Self::KwOnly | Self::InitVar => KnownModule::Dataclasses,
Self::NamedTupleFallback | Self::TypedDictFallback => KnownModule::TypeCheckerInternals,
+ Self::NamedTupleLike => KnownModule::TyExtensions,
}
}
@@ -4095,7 +4091,6 @@ impl KnownClass {
| Self::Nonmember
| Self::ABCMeta
| Self::Super
- | Self::NamedTuple
| Self::NewType
| Self::Field
| Self::KwOnly
@@ -4103,6 +4098,7 @@ impl KnownClass {
| Self::Iterable
| Self::Iterator
| Self::NamedTupleFallback
+ | Self::NamedTupleLike
| Self::TypedDictFallback => Some(false),
Self::Tuple => None,
@@ -4177,7 +4173,6 @@ impl KnownClass {
| Self::ABCMeta
| Self::Super
| Self::UnionType
- | Self::NamedTuple
| Self::NewType
| Self::Field
| Self::KwOnly
@@ -4185,6 +4180,7 @@ impl KnownClass {
| Self::Iterable
| Self::Iterator
| Self::NamedTupleFallback
+ | Self::NamedTupleLike
| Self::TypedDictFallback => false,
}
}
@@ -4234,7 +4230,6 @@ impl KnownClass {
"UnionType" => Self::UnionType,
"MethodWrapperType" => Self::MethodWrapperType,
"WrapperDescriptorType" => Self::WrapperDescriptorType,
- "NamedTuple" => Self::NamedTuple,
"NewType" => Self::NewType,
"TypeAliasType" => Self::TypeAliasType,
"TypeVar" => Self::TypeVar,
@@ -4275,6 +4270,7 @@ impl KnownClass {
"KW_ONLY" => Self::KwOnly,
"InitVar" => Self::InitVar,
"NamedTupleFallback" => Self::NamedTupleFallback,
+ "NamedTupleLike" => Self::NamedTupleLike,
"TypedDictFallback" => Self::TypedDictFallback,
_ => return None,
};
@@ -4341,6 +4337,7 @@ impl KnownClass {
| Self::InitVar
| Self::NamedTupleFallback
| Self::TypedDictFallback
+ | Self::NamedTupleLike
| Self::Awaitable
| Self::Generator => module == self.canonical_module(db),
Self::NoneType => matches!(module, KnownModule::Typeshed | KnownModule::Types),
@@ -4353,7 +4350,6 @@ impl KnownClass {
| Self::ParamSpecArgs
| Self::ParamSpecKwargs
| Self::TypeVarTuple
- | Self::NamedTuple
| Self::Iterable
| Self::Iterator
| Self::NewType => matches!(module, KnownModule::Typing | KnownModule::TypingExtensions),
diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs
index c74dc815f3363..aff7e833ce19b 100644
--- a/crates/ty_python_semantic/src/types/class_base.rs
+++ b/crates/ty_python_semantic/src/types/class_base.rs
@@ -80,18 +80,6 @@ impl<'db> ClassBase<'db> {
Type::ClassLiteral(literal) => {
if literal.is_known(db, KnownClass::Any) {
Some(Self::Dynamic(DynamicType::Any))
- } else if literal.is_known(db, KnownClass::NamedTuple) {
- let fields = subclass.own_fields(db, None);
- Self::try_from_type(
- db,
- TupleType::heterogeneous(
- db,
- fields.values().map(|field| field.declared_ty),
- )?
- .to_class_type(db)
- .into(),
- subclass,
- )
} else {
Some(Self::Class(literal.default_specialization(db)))
}
@@ -215,6 +203,20 @@ impl<'db> ClassBase<'db> {
SpecialFormType::Protocol => Some(Self::Protocol),
SpecialFormType::Generic => Some(Self::Generic),
+ SpecialFormType::NamedTuple => {
+ let fields = subclass.own_fields(db, None);
+ Self::try_from_type(
+ db,
+ TupleType::heterogeneous(
+ db,
+ fields.values().map(|field| field.declared_ty),
+ )?
+ .to_class_type(db)
+ .into(),
+ subclass,
+ )
+ }
+
// TODO: Classes inheriting from `typing.Type` et al. also have `Generic` in their MRO
SpecialFormType::Dict => {
Self::try_from_type(db, KnownClass::Dict.to_class_literal(db), subclass)
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index 3f8ade1195f34..acd7fbb0baf7d 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -64,7 +64,7 @@ use super::string_annotation::{
use super::subclass_of::SubclassOfInner;
use super::{ClassBase, add_inferred_python_version_hint_to_diagnostic};
use crate::module_name::{ModuleName, ModuleNameResolutionError};
-use crate::module_resolver::resolve_module;
+use crate::module_resolver::{KnownModule, file_to_module, resolve_module};
use crate::node_key::NodeKey;
use crate::place::{
Boundness, ConsideredDefinitions, LookupError, Place, PlaceAndQualifiers,
@@ -3034,20 +3034,29 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let maybe_known_class = KnownClass::try_from_file_and_name(self.db(), self.file(), name);
- let class_ty = Type::from(ClassLiteral::new(
- self.db(),
- name.id.clone(),
- body_scope,
- maybe_known_class,
- deprecated,
- dataclass_params,
- dataclass_transformer_params,
- ));
+ let ty = if maybe_known_class.is_none()
+ && &name.id == "NamedTuple"
+ && matches!(
+ file_to_module(self.db(), self.file()).and_then(|module| module.known(self.db())),
+ Some(KnownModule::Typing | KnownModule::TypingExtensions)
+ ) {
+ Type::SpecialForm(SpecialFormType::NamedTuple)
+ } else {
+ Type::from(ClassLiteral::new(
+ self.db(),
+ name.id.clone(),
+ body_scope,
+ maybe_known_class,
+ deprecated,
+ dataclass_params,
+ dataclass_transformer_params,
+ ))
+ };
self.add_declaration_with_binding(
class_node.into(),
definition,
- &DeclaredAndInferredType::are_the_same_type(class_ty),
+ &DeclaredAndInferredType::are_the_same_type(ty),
);
// if there are type parameters, then the keywords and bases are within that scope
@@ -6206,7 +6215,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| KnownClass::Property
| KnownClass::Super
| KnownClass::TypeVar
- | KnownClass::NamedTuple
| KnownClass::TypeAliasType
| KnownClass::Deprecated
)
@@ -10800,7 +10808,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
SpecialFormType::Tuple => {
Type::tuple(self.infer_tuple_type_expression(arguments_slice))
}
- SpecialFormType::Generic | SpecialFormType::Protocol => {
+ SpecialFormType::Generic | SpecialFormType::Protocol | SpecialFormType::NamedTuple => {
self.infer_expression(arguments_slice);
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
diff --git a/crates/ty_python_semantic/src/types/special_form.rs b/crates/ty_python_semantic/src/types/special_form.rs
index a502a6864d42c..f0dd81b150cdf 100644
--- a/crates/ty_python_semantic/src/types/special_form.rs
+++ b/crates/ty_python_semantic/src/types/special_form.rs
@@ -117,6 +117,11 @@ pub enum SpecialFormType {
/// Note that instances of subscripted `typing.Generic` are not represented by this type;
/// see also [`super::KnownInstanceType::SubscriptedGeneric`].
Generic,
+
+ /// The symbol `typing.NamedTuple` (which can also be found as `typing_extensions.NamedTuple`).
+ /// Typeshed defines this symbol as a class, but this isn't accurate: it's actually a factory function
+ /// at runtime. We therefore represent it as a special form internally.
+ NamedTuple,
}
impl SpecialFormType {
@@ -163,6 +168,8 @@ impl SpecialFormType {
| Self::OrderedDict => KnownClass::StdlibAlias,
Self::Unknown | Self::AlwaysTruthy | Self::AlwaysFalsy => KnownClass::Object,
+
+ Self::NamedTuple => KnownClass::FunctionType,
}
}
@@ -230,6 +237,7 @@ impl SpecialFormType {
| Self::TypeIs
| Self::TypingSelf
| Self::Protocol
+ | Self::NamedTuple
| Self::ReadOnly => {
matches!(module, KnownModule::Typing | KnownModule::TypingExtensions)
}
@@ -261,6 +269,7 @@ impl SpecialFormType {
| Self::Counter
| Self::DefaultDict
| Self::Deque
+ | Self::NamedTuple
| Self::OrderedDict => true,
// All other special forms are not callable
@@ -344,6 +353,7 @@ impl SpecialFormType {
SpecialFormType::CallableTypeOf => "ty_extensions.CallableTypeOf",
SpecialFormType::Protocol => "typing.Protocol",
SpecialFormType::Generic => "typing.Generic",
+ SpecialFormType::NamedTuple => "typing.NamedTuple",
}
}
}
diff --git a/crates/ty_vendored/ty_extensions/ty_extensions.pyi b/crates/ty_vendored/ty_extensions/ty_extensions.pyi
index 4dd041762fa41..6968bcb75a89d 100644
--- a/crates/ty_vendored/ty_extensions/ty_extensions.pyi
+++ b/crates/ty_vendored/ty_extensions/ty_extensions.pyi
@@ -1,5 +1,15 @@
+import sys
+from collections.abc import Iterable
from enum import Enum
-from typing import Any, LiteralString, _SpecialForm
+from typing import (
+ Any,
+ ClassVar,
+ LiteralString,
+ Protocol,
+ _SpecialForm,
+)
+
+from typing_extensions import Self # noqa: UP035
# Special operations
def static_assert(condition: object, msg: LiteralString | None = None) -> None: ...
@@ -69,3 +79,16 @@ def has_member(obj: Any, name: str) -> bool: ...
# diagnostic describing the protocol's interface. Passing a non-protocol type
# will cause ty to emit an error diagnostic.
def reveal_protocol_interface(protocol: type) -> None: ...
+
+# A protocol describing an interface that should be satisfied by all named tuples
+# created using `typing.NamedTuple` or `collections.namedtuple`.
+class NamedTupleLike(Protocol):
+ # from typing.NamedTuple stub
+ _field_defaults: ClassVar[dict[str, Any]]
+ _fields: ClassVar[tuple[str, ...]]
+ @classmethod
+ def _make(self: Self, iterable: Iterable[Any]) -> Self: ...
+ def _asdict(self, /) -> dict[str, Any]: ...
+ def _replace(self: Self, /, **kwargs) -> Self: ...
+ if sys.version_info >= (3, 13):
+ def __replace__(self: Self, **kwargs) -> Self: ...
From 2dc2f68b0f48a18ff038d9aadeb07ca8ca73a085 Mon Sep 17 00:00:00 2001
From: Dan Parizher <105245560+danparizher@users.noreply.github.com>
Date: Fri, 15 Aug 2025 15:09:55 -0400
Subject: [PATCH 012/160] [`pycodestyle`] Make `E731` fix unsafe instead of
display-only for class assignments (#19700)
## Summary
Fixes #19650
---------
Co-authored-by: Brent Westbrook
---
.../pycodestyle/rules/lambda_assignment.rs | 35 ++++++++-----------
...les__pycodestyle__tests__E731_E731.py.snap | 12 +++----
2 files changed, 21 insertions(+), 26 deletions(-)
diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/lambda_assignment.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/lambda_assignment.rs
index c8cbc21ce6aa7..24c47e1c7c035 100644
--- a/crates/ruff_linter/src/rules/pycodestyle/rules/lambda_assignment.rs
+++ b/crates/ruff_linter/src/rules/pycodestyle/rules/lambda_assignment.rs
@@ -10,7 +10,7 @@ use ruff_source_file::UniversalNewlines;
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
-use crate::{Edit, Fix, FixAvailability, Violation};
+use crate::{Applicability, Edit, Fix, FixAvailability, Violation};
/// ## What it does
/// Checks for lambda expressions which are assigned to a variable.
@@ -105,29 +105,24 @@ pub(crate) fn lambda_assignment(
}
}
- // Otherwise, if the assignment is in a class body, flag it, but use a display-only fix.
- // Rewriting safely would require making this a static method.
- //
- // Similarly, if the lambda is shadowing a variable in the current scope,
+ // If the lambda is shadowing a variable in the current scope,
// rewriting it as a function declaration may break type-checking.
// See: https://github.com/astral-sh/ruff/issues/5421
- if checker.semantic().current_scope().kind.is_class()
- || checker
- .semantic()
- .current_scope()
- .get_all(id)
- .any(|binding_id| checker.semantic().binding(binding_id).kind.is_annotation())
+ let applicability = if checker
+ .semantic()
+ .current_scope()
+ .get_all(id)
+ .any(|binding_id| checker.semantic().binding(binding_id).kind.is_annotation())
{
- diagnostic.set_fix(Fix::display_only_edit(Edit::range_replacement(
- indented,
- stmt.range(),
- )));
+ Applicability::DisplayOnly
} else {
- diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
- indented,
- stmt.range(),
- )));
- }
+ Applicability::Unsafe
+ };
+
+ diagnostic.set_fix(Fix::applicable_edit(
+ Edit::range_replacement(indented, stmt.range()),
+ applicability,
+ ));
}
}
diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap
index 9b7e9c54c8d45..f3054605a493f 100644
--- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap
+++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap
@@ -105,7 +105,7 @@ help: Rewrite `f` as a `def`
26 27 |
27 28 | def scope():
-E731 Do not assign a `lambda` expression, use a `def`
+E731 [*] Do not assign a `lambda` expression, use a `def`
--> E731.py:57:5
|
55 | class Scope:
@@ -115,7 +115,7 @@ E731 Do not assign a `lambda` expression, use a `def`
|
help: Rewrite `f` as a `def`
-ℹ Display-only fix
+ℹ Unsafe fix
54 54 |
55 55 | class Scope:
56 56 | # E731
@@ -318,7 +318,7 @@ help: Rewrite `f` as a `def`
137 138 |
138 139 | class TemperatureScales(Enum):
-E731 Do not assign a `lambda` expression, use a `def`
+E731 [*] Do not assign a `lambda` expression, use a `def`
--> E731.py:139:5
|
138 | class TemperatureScales(Enum):
@@ -328,7 +328,7 @@ E731 Do not assign a `lambda` expression, use a `def`
|
help: Rewrite `CELSIUS` as a `def`
-ℹ Display-only fix
+ℹ Unsafe fix
136 136 |
137 137 |
138 138 | class TemperatureScales(Enum):
@@ -339,7 +339,7 @@ help: Rewrite `CELSIUS` as a `def`
141 142 |
142 143 |
-E731 Do not assign a `lambda` expression, use a `def`
+E731 [*] Do not assign a `lambda` expression, use a `def`
--> E731.py:140:5
|
138 | class TemperatureScales(Enum):
@@ -349,7 +349,7 @@ E731 Do not assign a `lambda` expression, use a `def`
|
help: Rewrite `FAHRENHEIT` as a `def`
-ℹ Display-only fix
+ℹ Unsafe fix
137 137 |
138 138 | class TemperatureScales(Enum):
139 139 | CELSIUS = (lambda deg_c: deg_c)
From 2e1d6623cd5ba3e8ddbffee4df76e3ff0359b903 Mon Sep 17 00:00:00 2001
From: Frazer McLean
Date: Fri, 15 Aug 2025 21:18:06 +0200
Subject: [PATCH 013/160] [`flake8-simplify`] Implement fix for `maxsplit`
without separator (`SIM905`) (#19851)
**Stacked on top of #19849; diff will include that PR until it is
merged.**
---
## Summary
As part of #19849, I noticed this fix could be implemented.
## Test Plan
Tests added based on CPython behaviour.
---
.../test/fixtures/flake8_simplify/SIM905.py | 4 +
crates/ruff_linter/src/preview.rs | 5 +
.../src/rules/flake8_simplify/mod.rs | 1 +
.../rules/split_static_string.rs | 38 +-
...ke8_simplify__tests__SIM905_SIM905.py.snap | 28 +
...ify__tests__preview__SIM905_SIM905.py.snap | 1580 +++++++++++++++++
6 files changed, 1650 insertions(+), 6 deletions(-)
create mode 100644 crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM905_SIM905.py.snap
diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py
index 1981b422ad981..6b954b530b4de 100644
--- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py
+++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py
@@ -166,3 +166,7 @@
print("S\x1cP\x1dL\x1eI\x1fT".split())
print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+
+# leading/trailing whitespace should not count towards maxsplit
+" a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+" a b c d ".rsplit(maxsplit=2) # [" a b", "c", "d"]
diff --git a/crates/ruff_linter/src/preview.rs b/crates/ruff_linter/src/preview.rs
index 3bcc8721fb9cb..73edcbf71dfdc 100644
--- a/crates/ruff_linter/src/preview.rs
+++ b/crates/ruff_linter/src/preview.rs
@@ -230,3 +230,8 @@ pub(crate) const fn is_add_future_annotations_imports_enabled(settings: &LinterS
pub(crate) const fn is_trailing_comma_type_params_enabled(settings: &LinterSettings) -> bool {
settings.preview.is_enabled()
}
+
+// https://github.com/astral-sh/ruff/pull/19851
+pub(crate) const fn is_maxsplit_without_separator_fix_enabled(settings: &LinterSettings) -> bool {
+ settings.preview.is_enabled()
+}
diff --git a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs
index 1fd42b3450245..d3ac85a8fb1e2 100644
--- a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs
+++ b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs
@@ -60,6 +60,7 @@ mod tests {
}
#[test_case(Rule::MultipleWithStatements, Path::new("SIM117.py"))]
+ #[test_case(Rule::SplitStaticString, Path::new("SIM905.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs
index 367f2b5b34e26..c8a6f46e03e00 100644
--- a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs
+++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs
@@ -9,6 +9,8 @@ use ruff_python_ast::{
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
+use crate::preview::is_maxsplit_without_separator_fix_enabled;
+use crate::settings::LinterSettings;
use crate::{Applicability, Edit, Fix, FixAvailability, Violation};
/// ## What it does
@@ -84,7 +86,9 @@ pub(crate) fn split_static_string(
let sep_arg = arguments.find_argument_value("sep", 0);
let split_replacement = if let Some(sep) = sep_arg {
match sep {
- Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value, direction),
+ Expr::NoneLiteral(_) => {
+ split_default(str_value, maxsplit_value, direction, checker.settings())
+ }
Expr::StringLiteral(sep_value) => {
let sep_value_str = sep_value.value.to_str();
Some(split_sep(
@@ -100,7 +104,7 @@ pub(crate) fn split_static_string(
}
}
} else {
- split_default(str_value, maxsplit_value, direction)
+ split_default(str_value, maxsplit_value, direction, checker.settings())
};
let mut diagnostic = checker.report_diagnostic(SplitStaticString, call.range());
@@ -174,6 +178,7 @@ fn split_default(
str_value: &StringLiteralValue,
max_split: i32,
direction: Direction,
+ settings: &LinterSettings,
) -> Option {
// From the Python documentation:
// > If sep is not specified or is None, a different splitting algorithm is applied: runs of
@@ -185,10 +190,31 @@ fn split_default(
let string_val = str_value.to_str();
match max_split.cmp(&0) {
Ordering::Greater => {
- // Autofix for `maxsplit` without separator not yet implemented, as
- // `split_whitespace().remainder()` is not stable:
- // https://doc.rust-lang.org/std/str/struct.SplitWhitespace.html#method.remainder
- None
+ if !is_maxsplit_without_separator_fix_enabled(settings) {
+ return None;
+ }
+ let Ok(max_split) = usize::try_from(max_split) else {
+ return None;
+ };
+ let list_items: Vec<&str> = if direction == Direction::Left {
+ string_val
+ .trim_start_matches(py_unicode_is_whitespace)
+ .splitn(max_split + 1, py_unicode_is_whitespace)
+ .filter(|s| !s.is_empty())
+ .collect()
+ } else {
+ let mut items: Vec<&str> = string_val
+ .trim_end_matches(py_unicode_is_whitespace)
+ .rsplitn(max_split + 1, py_unicode_is_whitespace)
+ .filter(|s| !s.is_empty())
+ .collect();
+ items.reverse();
+ items
+ };
+ Some(construct_replacement(
+ &list_items,
+ str_value.first_literal_flags(),
+ ))
}
Ordering::Equal => {
// Behavior for maxsplit = 0 when sep is None:
diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap
index 84feb52b7d457..bda8037b7f790 100644
--- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap
@@ -1439,6 +1439,7 @@ help: Replace with list literal
166 |+print(["S", "P", "L", "I", "T"])
167 167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
168 168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+169 169 |
SIM905 [*] Consider using a list literal instead of `str.split`
--> SIM905.py:167:7
@@ -1458,6 +1459,8 @@ help: Replace with list literal
167 |-print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
167 |+print([">"])
168 168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+169 169 |
+170 170 | # leading/trailing whitespace should not count towards maxsplit
SIM905 [*] Consider using a list literal instead of `str.split`
--> SIM905.py:168:7
@@ -1466,6 +1469,8 @@ SIM905 [*] Consider using a list literal instead of `str.split`
167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+169 |
+170 | # leading/trailing whitespace should not count towards maxsplit
|
help: Replace with list literal
@@ -1475,3 +1480,26 @@ help: Replace with list literal
167 167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
168 |-print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
168 |+print(["<"])
+169 169 |
+170 170 | # leading/trailing whitespace should not count towards maxsplit
+171 171 | " a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+
+SIM905 Consider using a list literal instead of `str.split`
+ --> SIM905.py:171:1
+ |
+170 | # leading/trailing whitespace should not count towards maxsplit
+171 | " a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+172 | " a b c d ".rsplit(maxsplit=2) # [" a b", "c", "d"]
+ |
+help: Replace with list literal
+
+SIM905 Consider using a list literal instead of `str.split`
+ --> SIM905.py:172:1
+ |
+170 | # leading/trailing whitespace should not count towards maxsplit
+171 | " a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+172 | " a b c d ".rsplit(maxsplit=2) # [" a b", "c", "d"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: Replace with list literal
diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM905_SIM905.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM905_SIM905.py.snap
new file mode 100644
index 0000000000000..e45eabb21c132
--- /dev/null
+++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM905_SIM905.py.snap
@@ -0,0 +1,1580 @@
+---
+source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
+---
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:6:1
+ |
+ 5 | # positives
+ 6 | / """
+ 7 | | itemA
+ 8 | | itemB
+ 9 | | itemC
+10 | | """.split()
+ | |___________^
+11 |
+12 | "a,b,c,d".split(",")
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+3 3 | no_sep = None
+4 4 |
+5 5 | # positives
+6 |-"""
+7 |- itemA
+8 |- itemB
+9 |- itemC
+10 |-""".split()
+ 6 |+["itemA", "itemB", "itemC"]
+11 7 |
+12 8 | "a,b,c,d".split(",")
+13 9 | "a,b,c,d".split(None)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:12:1
+ |
+10 | """.split()
+11 |
+12 | "a,b,c,d".split(",")
+ | ^^^^^^^^^^^^^^^^^^^^
+13 | "a,b,c,d".split(None)
+14 | "a,b,c,d".split(",", 1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+9 9 | itemC
+10 10 | """.split()
+11 11 |
+12 |-"a,b,c,d".split(",")
+ 12 |+["a", "b", "c", "d"]
+13 13 | "a,b,c,d".split(None)
+14 14 | "a,b,c,d".split(",", 1)
+15 15 | "a,b,c,d".split(None, 1)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:13:1
+ |
+12 | "a,b,c,d".split(",")
+13 | "a,b,c,d".split(None)
+ | ^^^^^^^^^^^^^^^^^^^^^
+14 | "a,b,c,d".split(",", 1)
+15 | "a,b,c,d".split(None, 1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+10 10 | """.split()
+11 11 |
+12 12 | "a,b,c,d".split(",")
+13 |-"a,b,c,d".split(None)
+ 13 |+["a,b,c,d"]
+14 14 | "a,b,c,d".split(",", 1)
+15 15 | "a,b,c,d".split(None, 1)
+16 16 | "a,b,c,d".split(sep=",")
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:14:1
+ |
+12 | "a,b,c,d".split(",")
+13 | "a,b,c,d".split(None)
+14 | "a,b,c,d".split(",", 1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+15 | "a,b,c,d".split(None, 1)
+16 | "a,b,c,d".split(sep=",")
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+11 11 |
+12 12 | "a,b,c,d".split(",")
+13 13 | "a,b,c,d".split(None)
+14 |-"a,b,c,d".split(",", 1)
+ 14 |+["a", "b,c,d"]
+15 15 | "a,b,c,d".split(None, 1)
+16 16 | "a,b,c,d".split(sep=",")
+17 17 | "a,b,c,d".split(sep=None)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:15:1
+ |
+13 | "a,b,c,d".split(None)
+14 | "a,b,c,d".split(",", 1)
+15 | "a,b,c,d".split(None, 1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+16 | "a,b,c,d".split(sep=",")
+17 | "a,b,c,d".split(sep=None)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+12 12 | "a,b,c,d".split(",")
+13 13 | "a,b,c,d".split(None)
+14 14 | "a,b,c,d".split(",", 1)
+15 |-"a,b,c,d".split(None, 1)
+ 15 |+["a,b,c,d"]
+16 16 | "a,b,c,d".split(sep=",")
+17 17 | "a,b,c,d".split(sep=None)
+18 18 | "a,b,c,d".split(sep=",", maxsplit=1)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:16:1
+ |
+14 | "a,b,c,d".split(",", 1)
+15 | "a,b,c,d".split(None, 1)
+16 | "a,b,c,d".split(sep=",")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+17 | "a,b,c,d".split(sep=None)
+18 | "a,b,c,d".split(sep=",", maxsplit=1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+13 13 | "a,b,c,d".split(None)
+14 14 | "a,b,c,d".split(",", 1)
+15 15 | "a,b,c,d".split(None, 1)
+16 |-"a,b,c,d".split(sep=",")
+ 16 |+["a", "b", "c", "d"]
+17 17 | "a,b,c,d".split(sep=None)
+18 18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 19 | "a,b,c,d".split(sep=None, maxsplit=1)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:17:1
+ |
+15 | "a,b,c,d".split(None, 1)
+16 | "a,b,c,d".split(sep=",")
+17 | "a,b,c,d".split(sep=None)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 | "a,b,c,d".split(sep=None, maxsplit=1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+14 14 | "a,b,c,d".split(",", 1)
+15 15 | "a,b,c,d".split(None, 1)
+16 16 | "a,b,c,d".split(sep=",")
+17 |-"a,b,c,d".split(sep=None)
+ 17 |+["a,b,c,d"]
+18 18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 20 | "a,b,c,d".split(maxsplit=1, sep=",")
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:18:1
+ |
+16 | "a,b,c,d".split(sep=",")
+17 | "a,b,c,d".split(sep=None)
+18 | "a,b,c,d".split(sep=",", maxsplit=1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 | "a,b,c,d".split(maxsplit=1, sep=",")
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+15 15 | "a,b,c,d".split(None, 1)
+16 16 | "a,b,c,d".split(sep=",")
+17 17 | "a,b,c,d".split(sep=None)
+18 |-"a,b,c,d".split(sep=",", maxsplit=1)
+ 18 |+["a", "b,c,d"]
+19 19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 21 | "a,b,c,d".split(maxsplit=1, sep=None)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:19:1
+ |
+17 | "a,b,c,d".split(sep=None)
+18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 | "a,b,c,d".split(sep=None, maxsplit=1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 | "a,b,c,d".split(maxsplit=1, sep=None)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+16 16 | "a,b,c,d".split(sep=",")
+17 17 | "a,b,c,d".split(sep=None)
+18 18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 |-"a,b,c,d".split(sep=None, maxsplit=1)
+ 19 |+["a,b,c,d"]
+20 20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 22 | "a,b,c,d".split(",", maxsplit=1)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:20:1
+ |
+18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 | "a,b,c,d".split(maxsplit=1, sep=",")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 | "a,b,c,d".split(",", maxsplit=1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+17 17 | "a,b,c,d".split(sep=None)
+18 18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 |-"a,b,c,d".split(maxsplit=1, sep=",")
+ 20 |+["a", "b,c,d"]
+21 21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 22 | "a,b,c,d".split(",", maxsplit=1)
+23 23 | "a,b,c,d".split(None, maxsplit=1)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:21:1
+ |
+19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 | "a,b,c,d".split(maxsplit=1, sep=None)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+22 | "a,b,c,d".split(",", maxsplit=1)
+23 | "a,b,c,d".split(None, maxsplit=1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+18 18 | "a,b,c,d".split(sep=",", maxsplit=1)
+19 19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 |-"a,b,c,d".split(maxsplit=1, sep=None)
+ 21 |+["a,b,c,d"]
+22 22 | "a,b,c,d".split(",", maxsplit=1)
+23 23 | "a,b,c,d".split(None, maxsplit=1)
+24 24 | "a,b,c,d".split(maxsplit=1)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:22:1
+ |
+20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 | "a,b,c,d".split(",", maxsplit=1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+23 | "a,b,c,d".split(None, maxsplit=1)
+24 | "a,b,c,d".split(maxsplit=1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+19 19 | "a,b,c,d".split(sep=None, maxsplit=1)
+20 20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 |-"a,b,c,d".split(",", maxsplit=1)
+ 22 |+["a", "b,c,d"]
+23 23 | "a,b,c,d".split(None, maxsplit=1)
+24 24 | "a,b,c,d".split(maxsplit=1)
+25 25 | "a,b,c,d".split(maxsplit=1.0)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:23:1
+ |
+21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 | "a,b,c,d".split(",", maxsplit=1)
+23 | "a,b,c,d".split(None, maxsplit=1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+24 | "a,b,c,d".split(maxsplit=1)
+25 | "a,b,c,d".split(maxsplit=1.0)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+20 20 | "a,b,c,d".split(maxsplit=1, sep=",")
+21 21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 22 | "a,b,c,d".split(",", maxsplit=1)
+23 |-"a,b,c,d".split(None, maxsplit=1)
+ 23 |+["a,b,c,d"]
+24 24 | "a,b,c,d".split(maxsplit=1)
+25 25 | "a,b,c,d".split(maxsplit=1.0)
+26 26 | "a,b,c,d".split(maxsplit=1)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:24:1
+ |
+22 | "a,b,c,d".split(",", maxsplit=1)
+23 | "a,b,c,d".split(None, maxsplit=1)
+24 | "a,b,c,d".split(maxsplit=1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+25 | "a,b,c,d".split(maxsplit=1.0)
+26 | "a,b,c,d".split(maxsplit=1)
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+21 21 | "a,b,c,d".split(maxsplit=1, sep=None)
+22 22 | "a,b,c,d".split(",", maxsplit=1)
+23 23 | "a,b,c,d".split(None, maxsplit=1)
+24 |-"a,b,c,d".split(maxsplit=1)
+ 24 |+["a,b,c,d"]
+25 25 | "a,b,c,d".split(maxsplit=1.0)
+26 26 | "a,b,c,d".split(maxsplit=1)
+27 27 | "a,b,c,d".split(maxsplit=0)
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:26:1
+ |
+24 | "a,b,c,d".split(maxsplit=1)
+25 | "a,b,c,d".split(maxsplit=1.0)
+26 | "a,b,c,d".split(maxsplit=1)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+27 | "a,b,c,d".split(maxsplit=0)
+28 | "VERB AUX PRON ADP DET".split(" ")
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+23 23 | "a,b,c,d".split(None, maxsplit=1)
+24 24 | "a,b,c,d".split(maxsplit=1)
+25 25 | "a,b,c,d".split(maxsplit=1.0)
+26 |-"a,b,c,d".split(maxsplit=1)
+ 26 |+["a,b,c,d"]
+27 27 | "a,b,c,d".split(maxsplit=0)
+28 28 | "VERB AUX PRON ADP DET".split(" ")
+29 29 | ' 1 2 3 '.split()
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:27:1
+ |
+25 | "a,b,c,d".split(maxsplit=1.0)
+26 | "a,b,c,d".split(maxsplit=1)
+27 | "a,b,c,d".split(maxsplit=0)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+28 | "VERB AUX PRON ADP DET".split(" ")
+29 | ' 1 2 3 '.split()
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+24 24 | "a,b,c,d".split(maxsplit=1)
+25 25 | "a,b,c,d".split(maxsplit=1.0)
+26 26 | "a,b,c,d".split(maxsplit=1)
+27 |-"a,b,c,d".split(maxsplit=0)
+ 27 |+["a,b,c,d"]
+28 28 | "VERB AUX PRON ADP DET".split(" ")
+29 29 | ' 1 2 3 '.split()
+30 30 | '1<>2<>3<4'.split('<>')
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:28:1
+ |
+26 | "a,b,c,d".split(maxsplit=1)
+27 | "a,b,c,d".split(maxsplit=0)
+28 | "VERB AUX PRON ADP DET".split(" ")
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+29 | ' 1 2 3 '.split()
+30 | '1<>2<>3<4'.split('<>')
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+25 25 | "a,b,c,d".split(maxsplit=1.0)
+26 26 | "a,b,c,d".split(maxsplit=1)
+27 27 | "a,b,c,d".split(maxsplit=0)
+28 |-"VERB AUX PRON ADP DET".split(" ")
+ 28 |+["VERB", "AUX", "PRON", "ADP", "DET"]
+29 29 | ' 1 2 3 '.split()
+30 30 | '1<>2<>3<4'.split('<>')
+31 31 |
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:29:1
+ |
+27 | "a,b,c,d".split(maxsplit=0)
+28 | "VERB AUX PRON ADP DET".split(" ")
+29 | ' 1 2 3 '.split()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+30 | '1<>2<>3<4'.split('<>')
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+26 26 | "a,b,c,d".split(maxsplit=1)
+27 27 | "a,b,c,d".split(maxsplit=0)
+28 28 | "VERB AUX PRON ADP DET".split(" ")
+29 |-' 1 2 3 '.split()
+ 29 |+['1', '2', '3']
+30 30 | '1<>2<>3<4'.split('<>')
+31 31 |
+32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:30:1
+ |
+28 | "VERB AUX PRON ADP DET".split(" ")
+29 | ' 1 2 3 '.split()
+30 | '1<>2<>3<4'.split('<>')
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+31 |
+32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+27 27 | "a,b,c,d".split(maxsplit=0)
+28 28 | "VERB AUX PRON ADP DET".split(" ")
+29 29 | ' 1 2 3 '.split()
+30 |-'1<>2<>3<4'.split('<>')
+ 30 |+['1', '2', '3<4']
+31 31 |
+32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+33 33 | "".split() # []
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:32:1
+ |
+30 | '1<>2<>3<4'.split('<>')
+31 |
+32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+33 | "".split() # []
+34 | """
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+29 29 | ' 1 2 3 '.split()
+30 30 | '1<>2<>3<4'.split('<>')
+31 31 |
+32 |-" a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+ 32 |+[" a", "a a", "a a "] # [" a", "a a", "a a "]
+33 33 | "".split() # []
+34 34 | """
+35 35 | """.split() # []
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:33:1
+ |
+32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+33 | "".split() # []
+ | ^^^^^^^^^^
+34 | """
+35 | """.split() # []
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+30 30 | '1<>2<>3<4'.split('<>')
+31 31 |
+32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+33 |-"".split() # []
+ 33 |+[] # []
+34 34 | """
+35 35 | """.split() # []
+36 36 | " ".split() # []
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:34:1
+ |
+32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+33 | "".split() # []
+34 | / """
+35 | | """.split() # []
+ | |___________^
+36 | " ".split() # []
+37 | "/abc/".split() # ["/abc/"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+31 31 |
+32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
+33 33 | "".split() # []
+34 |-"""
+35 |-""".split() # []
+ 34 |+[] # []
+36 35 | " ".split() # []
+37 36 | "/abc/".split() # ["/abc/"]
+38 37 | ("a,b,c"
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:36:1
+ |
+34 | """
+35 | """.split() # []
+36 | " ".split() # []
+ | ^^^^^^^^^^^^^^^^^
+37 | "/abc/".split() # ["/abc/"]
+38 | ("a,b,c"
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+33 33 | "".split() # []
+34 34 | """
+35 35 | """.split() # []
+36 |-" ".split() # []
+ 36 |+[] # []
+37 37 | "/abc/".split() # ["/abc/"]
+38 38 | ("a,b,c"
+39 39 | # comment
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:37:1
+ |
+35 | """.split() # []
+36 | " ".split() # []
+37 | "/abc/".split() # ["/abc/"]
+ | ^^^^^^^^^^^^^^^
+38 | ("a,b,c"
+39 | # comment
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+34 34 | """
+35 35 | """.split() # []
+36 36 | " ".split() # []
+37 |-"/abc/".split() # ["/abc/"]
+ 37 |+["/abc/"] # ["/abc/"]
+38 38 | ("a,b,c"
+39 39 | # comment
+40 40 | .split()
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:38:2
+ |
+36 | " ".split() # []
+37 | "/abc/".split() # ["/abc/"]
+38 | ("a,b,c"
+ | __^
+39 | | # comment
+40 | | .split()
+ | |________^
+41 | ) # ["a,b,c"]
+42 | ("a,b,c"
+ |
+help: Replace with list literal
+
+ℹ Unsafe fix
+35 35 | """.split() # []
+36 36 | " ".split() # []
+37 37 | "/abc/".split() # ["/abc/"]
+38 |-("a,b,c"
+39 |-# comment
+40 |-.split()
+ 38 |+(["a,b,c"]
+41 39 | ) # ["a,b,c"]
+42 40 | ("a,b,c"
+43 41 | # comment1
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:42:2
+ |
+40 | .split()
+41 | ) # ["a,b,c"]
+42 | ("a,b,c"
+ | __^
+43 | | # comment1
+44 | | .split(",")
+ | |___________^
+45 | ) # ["a", "b", "c"]
+46 | ("a,"
+ |
+help: Replace with list literal
+
+ℹ Unsafe fix
+39 39 | # comment
+40 40 | .split()
+41 41 | ) # ["a,b,c"]
+42 |-("a,b,c"
+43 |-# comment1
+44 |-.split(",")
+ 42 |+(["a", "b", "c"]
+45 43 | ) # ["a", "b", "c"]
+46 44 | ("a,"
+47 45 | # comment
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:46:2
+ |
+44 | .split(",")
+45 | ) # ["a", "b", "c"]
+46 | ("a,"
+ | __^
+47 | | # comment
+48 | | "b,"
+49 | | "c"
+50 | | .split(",")
+ | |___________^
+51 | ) # ["a", "b", "c"]
+ |
+help: Replace with list literal
+
+ℹ Unsafe fix
+43 43 | # comment1
+44 44 | .split(",")
+45 45 | ) # ["a", "b", "c"]
+46 |-("a,"
+47 |-# comment
+48 |-"b,"
+49 |-"c"
+50 |-.split(",")
+ 46 |+(["a", "b", "c"]
+51 47 | ) # ["a", "b", "c"]
+52 48 |
+53 49 | "hello "\
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:53:1
+ |
+51 | ) # ["a", "b", "c"]
+52 |
+53 | / "hello "\
+54 | | "world".split()
+ | |___________________^
+55 | # ["hello", "world"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+50 50 | .split(",")
+51 51 | ) # ["a", "b", "c"]
+52 52 |
+53 |-"hello "\
+54 |- "world".split()
+ 53 |+["hello", "world"]
+55 54 | # ["hello", "world"]
+56 55 |
+57 56 | # prefixes and isc
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:58:1
+ |
+57 | # prefixes and isc
+58 | u"a b".split() # [u"a", u"b"]
+ | ^^^^^^^^^^^^^^
+59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+60 | ("a " "b").split() # ["a", "b"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+55 55 | # ["hello", "world"]
+56 56 |
+57 57 | # prefixes and isc
+58 |-u"a b".split() # [u"a", u"b"]
+ 58 |+[u"a", u"b"] # [u"a", u"b"]
+59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+60 60 | ("a " "b").split() # ["a", "b"]
+61 61 | "a " "b".split() # ["a", "b"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:59:1
+ |
+57 | # prefixes and isc
+58 | u"a b".split() # [u"a", u"b"]
+59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+ | ^^^^^^^^^^^^^^^^^
+60 | ("a " "b").split() # ["a", "b"]
+61 | "a " "b".split() # ["a", "b"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+56 56 |
+57 57 | # prefixes and isc
+58 58 | u"a b".split() # [u"a", u"b"]
+59 |-r"a \n b".split() # [r"a", r"\n", r"b"]
+ 59 |+[r"a", r"\n", r"b"] # [r"a", r"\n", r"b"]
+60 60 | ("a " "b").split() # ["a", "b"]
+61 61 | "a " "b".split() # ["a", "b"]
+62 62 | u"a " "b".split() # [u"a", u"b"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:60:1
+ |
+58 | u"a b".split() # [u"a", u"b"]
+59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+60 | ("a " "b").split() # ["a", "b"]
+ | ^^^^^^^^^^^^^^^^^^
+61 | "a " "b".split() # ["a", "b"]
+62 | u"a " "b".split() # [u"a", u"b"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+57 57 | # prefixes and isc
+58 58 | u"a b".split() # [u"a", u"b"]
+59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+60 |-("a " "b").split() # ["a", "b"]
+ 60 |+["a", "b"] # ["a", "b"]
+61 61 | "a " "b".split() # ["a", "b"]
+62 62 | u"a " "b".split() # [u"a", u"b"]
+63 63 | "a " u"b".split() # ["a", "b"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:61:1
+ |
+59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+60 | ("a " "b").split() # ["a", "b"]
+61 | "a " "b".split() # ["a", "b"]
+ | ^^^^^^^^^^^^^^^^
+62 | u"a " "b".split() # [u"a", u"b"]
+63 | "a " u"b".split() # ["a", "b"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+58 58 | u"a b".split() # [u"a", u"b"]
+59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+60 60 | ("a " "b").split() # ["a", "b"]
+61 |-"a " "b".split() # ["a", "b"]
+ 61 |+["a", "b"] # ["a", "b"]
+62 62 | u"a " "b".split() # [u"a", u"b"]
+63 63 | "a " u"b".split() # ["a", "b"]
+64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:62:1
+ |
+60 | ("a " "b").split() # ["a", "b"]
+61 | "a " "b".split() # ["a", "b"]
+62 | u"a " "b".split() # [u"a", u"b"]
+ | ^^^^^^^^^^^^^^^^^
+63 | "a " u"b".split() # ["a", "b"]
+64 | u"a " r"\n".split() # [u"a", u"\\n"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
+60 60 | ("a " "b").split() # ["a", "b"]
+61 61 | "a " "b".split() # ["a", "b"]
+62 |-u"a " "b".split() # [u"a", u"b"]
+ 62 |+[u"a", u"b"] # [u"a", u"b"]
+63 63 | "a " u"b".split() # ["a", "b"]
+64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 65 | r"\n " u"\n".split() # [r"\n"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:63:1
+ |
+61 | "a " "b".split() # ["a", "b"]
+62 | u"a " "b".split() # [u"a", u"b"]
+63 | "a " u"b".split() # ["a", "b"]
+ | ^^^^^^^^^^^^^^^^^
+64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 | r"\n " u"\n".split() # [r"\n"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+60 60 | ("a " "b").split() # ["a", "b"]
+61 61 | "a " "b".split() # ["a", "b"]
+62 62 | u"a " "b".split() # [u"a", u"b"]
+63 |-"a " u"b".split() # ["a", "b"]
+ 63 |+["a", "b"] # ["a", "b"]
+64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 65 | r"\n " u"\n".split() # [r"\n"]
+66 66 | r"\n " "\n".split() # [r"\n"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:64:1
+ |
+62 | u"a " "b".split() # [u"a", u"b"]
+63 | "a " u"b".split() # ["a", "b"]
+64 | u"a " r"\n".split() # [u"a", u"\\n"]
+ | ^^^^^^^^^^^^^^^^^^^
+65 | r"\n " u"\n".split() # [r"\n"]
+66 | r"\n " "\n".split() # [r"\n"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+61 61 | "a " "b".split() # ["a", "b"]
+62 62 | u"a " "b".split() # [u"a", u"b"]
+63 63 | "a " u"b".split() # ["a", "b"]
+64 |-u"a " r"\n".split() # [u"a", u"\\n"]
+ 64 |+[u"a", u"\\n"] # [u"a", u"\\n"]
+65 65 | r"\n " u"\n".split() # [r"\n"]
+66 66 | r"\n " "\n".split() # [r"\n"]
+67 67 | "a " r"\n".split() # ["a", "\\n"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:65:1
+ |
+63 | "a " u"b".split() # ["a", "b"]
+64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 | r"\n " u"\n".split() # [r"\n"]
+ | ^^^^^^^^^^^^^^^^^^^^
+66 | r"\n " "\n".split() # [r"\n"]
+67 | "a " r"\n".split() # ["a", "\\n"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+62 62 | u"a " "b".split() # [u"a", u"b"]
+63 63 | "a " u"b".split() # ["a", "b"]
+64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 |-r"\n " u"\n".split() # [r"\n"]
+ 65 |+[r"\n"] # [r"\n"]
+66 66 | r"\n " "\n".split() # [r"\n"]
+67 67 | "a " r"\n".split() # ["a", "\\n"]
+68 68 |
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:66:1
+ |
+64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 | r"\n " u"\n".split() # [r"\n"]
+66 | r"\n " "\n".split() # [r"\n"]
+ | ^^^^^^^^^^^^^^^^^^^
+67 | "a " r"\n".split() # ["a", "\\n"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+63 63 | "a " u"b".split() # ["a", "b"]
+64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 65 | r"\n " u"\n".split() # [r"\n"]
+66 |-r"\n " "\n".split() # [r"\n"]
+ 66 |+[r"\n"] # [r"\n"]
+67 67 | "a " r"\n".split() # ["a", "\\n"]
+68 68 |
+69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:67:1
+ |
+65 | r"\n " u"\n".split() # [r"\n"]
+66 | r"\n " "\n".split() # [r"\n"]
+67 | "a " r"\n".split() # ["a", "\\n"]
+ | ^^^^^^^^^^^^^^^^^^
+68 |
+69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
+65 65 | r"\n " u"\n".split() # [r"\n"]
+66 66 | r"\n " "\n".split() # [r"\n"]
+67 |-"a " r"\n".split() # ["a", "\\n"]
+ 67 |+["a", "\\n"] # ["a", "\\n"]
+68 68 |
+69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:69:1
+ |
+67 | "a " r"\n".split() # ["a", "\\n"]
+68 |
+69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+66 66 | r"\n " "\n".split() # [r"\n"]
+67 67 | "a " r"\n".split() # ["a", "\\n"]
+68 68 |
+69 |-"a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+ 69 |+["a,b,c"] # ["a,b,c"]
+70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+71 71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+72 72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:70:1
+ |
+69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+67 67 | "a " r"\n".split() # ["a", "\\n"]
+68 68 |
+69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+70 |-"a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+ 70 |+["a", "b", "c"] # ["a", "b", "c"]
+71 71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+72 72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
+73 73 |
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:71:1
+ |
+69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+68 68 |
+69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+71 |-"a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+ 71 |+["a", "b", "c"] # ["a", "b", "c"]
+72 72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
+73 73 |
+74 74 | # negatives
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:72:1
+ |
+70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+73 |
+74 | # negatives
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
+70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
+71 71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
+72 |-"a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
+ 72 |+["a,b,c"] # ["a,b,c"]
+73 73 |
+74 74 | # negatives
+75 75 |
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:103:1
+ |
+102 | # another positive demonstrating quote preservation
+103 | / """
+104 | | "itemA"
+105 | | 'itemB'
+106 | | '''itemC'''
+107 | | "'itemD'"
+108 | | """.split()
+ | |___________^
+109 |
+110 | # https://github.com/astral-sh/ruff/issues/18042
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+100 100 |
+101 101 |
+102 102 | # another positive demonstrating quote preservation
+103 |-"""
+104 |-"itemA"
+105 |-'itemB'
+106 |-'''itemC'''
+107 |-"'itemD'"
+108 |-""".split()
+ 103 |+['"itemA"', "'itemB'", "'''itemC'''", "\"'itemD'\""]
+109 104 |
+110 105 | # https://github.com/astral-sh/ruff/issues/18042
+111 106 | print("a,b".rsplit(","))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:111:7
+ |
+110 | # https://github.com/astral-sh/ruff/issues/18042
+111 | print("a,b".rsplit(","))
+ | ^^^^^^^^^^^^^^^^^
+112 | print("a,b,c".rsplit(",", 1))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+108 108 | """.split()
+109 109 |
+110 110 | # https://github.com/astral-sh/ruff/issues/18042
+111 |-print("a,b".rsplit(","))
+ 111 |+print(["a", "b"])
+112 112 | print("a,b,c".rsplit(",", 1))
+113 113 |
+114 114 | # https://github.com/astral-sh/ruff/issues/18069
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:112:7
+ |
+110 | # https://github.com/astral-sh/ruff/issues/18042
+111 | print("a,b".rsplit(","))
+112 | print("a,b,c".rsplit(",", 1))
+ | ^^^^^^^^^^^^^^^^^^^^^^
+113 |
+114 | # https://github.com/astral-sh/ruff/issues/18069
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+109 109 |
+110 110 | # https://github.com/astral-sh/ruff/issues/18042
+111 111 | print("a,b".rsplit(","))
+112 |-print("a,b,c".rsplit(",", 1))
+ 112 |+print(["a,b", "c"])
+113 113 |
+114 114 | # https://github.com/astral-sh/ruff/issues/18069
+115 115 |
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:116:7
+ |
+114 | # https://github.com/astral-sh/ruff/issues/18069
+115 |
+116 | print("".split(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^
+117 | print("".split(sep=None, maxsplit=0))
+118 | print(" ".split(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+113 113 |
+114 114 | # https://github.com/astral-sh/ruff/issues/18069
+115 115 |
+116 |-print("".split(maxsplit=0))
+ 116 |+print([])
+117 117 | print("".split(sep=None, maxsplit=0))
+118 118 | print(" ".split(maxsplit=0))
+119 119 | print(" ".split(sep=None, maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:117:7
+ |
+116 | print("".split(maxsplit=0))
+117 | print("".split(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+118 | print(" ".split(maxsplit=0))
+119 | print(" ".split(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+114 114 | # https://github.com/astral-sh/ruff/issues/18069
+115 115 |
+116 116 | print("".split(maxsplit=0))
+117 |-print("".split(sep=None, maxsplit=0))
+ 117 |+print([])
+118 118 | print(" ".split(maxsplit=0))
+119 119 | print(" ".split(sep=None, maxsplit=0))
+120 120 | print(" x ".split(maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:118:7
+ |
+116 | print("".split(maxsplit=0))
+117 | print("".split(sep=None, maxsplit=0))
+118 | print(" ".split(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^
+119 | print(" ".split(sep=None, maxsplit=0))
+120 | print(" x ".split(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+115 115 |
+116 116 | print("".split(maxsplit=0))
+117 117 | print("".split(sep=None, maxsplit=0))
+118 |-print(" ".split(maxsplit=0))
+ 118 |+print([])
+119 119 | print(" ".split(sep=None, maxsplit=0))
+120 120 | print(" x ".split(maxsplit=0))
+121 121 | print(" x ".split(sep=None, maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:119:7
+ |
+117 | print("".split(sep=None, maxsplit=0))
+118 | print(" ".split(maxsplit=0))
+119 | print(" ".split(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+120 | print(" x ".split(maxsplit=0))
+121 | print(" x ".split(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+116 116 | print("".split(maxsplit=0))
+117 117 | print("".split(sep=None, maxsplit=0))
+118 118 | print(" ".split(maxsplit=0))
+119 |-print(" ".split(sep=None, maxsplit=0))
+ 119 |+print([])
+120 120 | print(" x ".split(maxsplit=0))
+121 121 | print(" x ".split(sep=None, maxsplit=0))
+122 122 | print(" x ".split(maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:120:7
+ |
+118 | print(" ".split(maxsplit=0))
+119 | print(" ".split(sep=None, maxsplit=0))
+120 | print(" x ".split(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+121 | print(" x ".split(sep=None, maxsplit=0))
+122 | print(" x ".split(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+117 117 | print("".split(sep=None, maxsplit=0))
+118 118 | print(" ".split(maxsplit=0))
+119 119 | print(" ".split(sep=None, maxsplit=0))
+120 |-print(" x ".split(maxsplit=0))
+ 120 |+print(["x "])
+121 121 | print(" x ".split(sep=None, maxsplit=0))
+122 122 | print(" x ".split(maxsplit=0))
+123 123 | print(" x ".split(sep=None, maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:121:7
+ |
+119 | print(" ".split(sep=None, maxsplit=0))
+120 | print(" x ".split(maxsplit=0))
+121 | print(" x ".split(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+122 | print(" x ".split(maxsplit=0))
+123 | print(" x ".split(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+118 118 | print(" ".split(maxsplit=0))
+119 119 | print(" ".split(sep=None, maxsplit=0))
+120 120 | print(" x ".split(maxsplit=0))
+121 |-print(" x ".split(sep=None, maxsplit=0))
+ 121 |+print(["x "])
+122 122 | print(" x ".split(maxsplit=0))
+123 123 | print(" x ".split(sep=None, maxsplit=0))
+124 124 | print("".rsplit(maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:122:7
+ |
+120 | print(" x ".split(maxsplit=0))
+121 | print(" x ".split(sep=None, maxsplit=0))
+122 | print(" x ".split(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+123 | print(" x ".split(sep=None, maxsplit=0))
+124 | print("".rsplit(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+119 119 | print(" ".split(sep=None, maxsplit=0))
+120 120 | print(" x ".split(maxsplit=0))
+121 121 | print(" x ".split(sep=None, maxsplit=0))
+122 |-print(" x ".split(maxsplit=0))
+ 122 |+print(["x "])
+123 123 | print(" x ".split(sep=None, maxsplit=0))
+124 124 | print("".rsplit(maxsplit=0))
+125 125 | print("".rsplit(sep=None, maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:123:7
+ |
+121 | print(" x ".split(sep=None, maxsplit=0))
+122 | print(" x ".split(maxsplit=0))
+123 | print(" x ".split(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+124 | print("".rsplit(maxsplit=0))
+125 | print("".rsplit(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+120 120 | print(" x ".split(maxsplit=0))
+121 121 | print(" x ".split(sep=None, maxsplit=0))
+122 122 | print(" x ".split(maxsplit=0))
+123 |-print(" x ".split(sep=None, maxsplit=0))
+ 123 |+print(["x "])
+124 124 | print("".rsplit(maxsplit=0))
+125 125 | print("".rsplit(sep=None, maxsplit=0))
+126 126 | print(" ".rsplit(maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:124:7
+ |
+122 | print(" x ".split(maxsplit=0))
+123 | print(" x ".split(sep=None, maxsplit=0))
+124 | print("".rsplit(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^
+125 | print("".rsplit(sep=None, maxsplit=0))
+126 | print(" ".rsplit(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+121 121 | print(" x ".split(sep=None, maxsplit=0))
+122 122 | print(" x ".split(maxsplit=0))
+123 123 | print(" x ".split(sep=None, maxsplit=0))
+124 |-print("".rsplit(maxsplit=0))
+ 124 |+print([])
+125 125 | print("".rsplit(sep=None, maxsplit=0))
+126 126 | print(" ".rsplit(maxsplit=0))
+127 127 | print(" ".rsplit(sep=None, maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:125:7
+ |
+123 | print(" x ".split(sep=None, maxsplit=0))
+124 | print("".rsplit(maxsplit=0))
+125 | print("".rsplit(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+126 | print(" ".rsplit(maxsplit=0))
+127 | print(" ".rsplit(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+122 122 | print(" x ".split(maxsplit=0))
+123 123 | print(" x ".split(sep=None, maxsplit=0))
+124 124 | print("".rsplit(maxsplit=0))
+125 |-print("".rsplit(sep=None, maxsplit=0))
+ 125 |+print([])
+126 126 | print(" ".rsplit(maxsplit=0))
+127 127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 128 | print(" x ".rsplit(maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:126:7
+ |
+124 | print("".rsplit(maxsplit=0))
+125 | print("".rsplit(sep=None, maxsplit=0))
+126 | print(" ".rsplit(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^
+127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 | print(" x ".rsplit(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+123 123 | print(" x ".split(sep=None, maxsplit=0))
+124 124 | print("".rsplit(maxsplit=0))
+125 125 | print("".rsplit(sep=None, maxsplit=0))
+126 |-print(" ".rsplit(maxsplit=0))
+ 126 |+print([])
+127 127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 128 | print(" x ".rsplit(maxsplit=0))
+129 129 | print(" x ".rsplit(maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:127:7
+ |
+125 | print("".rsplit(sep=None, maxsplit=0))
+126 | print(" ".rsplit(maxsplit=0))
+127 | print(" ".rsplit(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+128 | print(" x ".rsplit(maxsplit=0))
+129 | print(" x ".rsplit(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+124 124 | print("".rsplit(maxsplit=0))
+125 125 | print("".rsplit(sep=None, maxsplit=0))
+126 126 | print(" ".rsplit(maxsplit=0))
+127 |-print(" ".rsplit(sep=None, maxsplit=0))
+ 127 |+print([])
+128 128 | print(" x ".rsplit(maxsplit=0))
+129 129 | print(" x ".rsplit(maxsplit=0))
+130 130 | print(" x ".rsplit(sep=None, maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:128:7
+ |
+126 | print(" ".rsplit(maxsplit=0))
+127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 | print(" x ".rsplit(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+129 | print(" x ".rsplit(maxsplit=0))
+130 | print(" x ".rsplit(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+125 125 | print("".rsplit(sep=None, maxsplit=0))
+126 126 | print(" ".rsplit(maxsplit=0))
+127 127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 |-print(" x ".rsplit(maxsplit=0))
+ 128 |+print([" x"])
+129 129 | print(" x ".rsplit(maxsplit=0))
+130 130 | print(" x ".rsplit(sep=None, maxsplit=0))
+131 131 | print(" x ".rsplit(maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:129:7
+ |
+127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 | print(" x ".rsplit(maxsplit=0))
+129 | print(" x ".rsplit(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+130 | print(" x ".rsplit(sep=None, maxsplit=0))
+131 | print(" x ".rsplit(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+126 126 | print(" ".rsplit(maxsplit=0))
+127 127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 128 | print(" x ".rsplit(maxsplit=0))
+129 |-print(" x ".rsplit(maxsplit=0))
+ 129 |+print([" x"])
+130 130 | print(" x ".rsplit(sep=None, maxsplit=0))
+131 131 | print(" x ".rsplit(maxsplit=0))
+132 132 | print(" x ".rsplit(sep=None, maxsplit=0))
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:130:7
+ |
+128 | print(" x ".rsplit(maxsplit=0))
+129 | print(" x ".rsplit(maxsplit=0))
+130 | print(" x ".rsplit(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+131 | print(" x ".rsplit(maxsplit=0))
+132 | print(" x ".rsplit(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+127 127 | print(" ".rsplit(sep=None, maxsplit=0))
+128 128 | print(" x ".rsplit(maxsplit=0))
+129 129 | print(" x ".rsplit(maxsplit=0))
+130 |-print(" x ".rsplit(sep=None, maxsplit=0))
+ 130 |+print([" x"])
+131 131 | print(" x ".rsplit(maxsplit=0))
+132 132 | print(" x ".rsplit(sep=None, maxsplit=0))
+133 133 |
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:131:7
+ |
+129 | print(" x ".rsplit(maxsplit=0))
+130 | print(" x ".rsplit(sep=None, maxsplit=0))
+131 | print(" x ".rsplit(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+132 | print(" x ".rsplit(sep=None, maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+128 128 | print(" x ".rsplit(maxsplit=0))
+129 129 | print(" x ".rsplit(maxsplit=0))
+130 130 | print(" x ".rsplit(sep=None, maxsplit=0))
+131 |-print(" x ".rsplit(maxsplit=0))
+ 131 |+print([" x"])
+132 132 | print(" x ".rsplit(sep=None, maxsplit=0))
+133 133 |
+134 134 | # https://github.com/astral-sh/ruff/issues/19581 - embedded quotes in raw strings
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:132:7
+ |
+130 | print(" x ".rsplit(sep=None, maxsplit=0))
+131 | print(" x ".rsplit(maxsplit=0))
+132 | print(" x ".rsplit(sep=None, maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+133 |
+134 | # https://github.com/astral-sh/ruff/issues/19581 - embedded quotes in raw strings
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+129 129 | print(" x ".rsplit(maxsplit=0))
+130 130 | print(" x ".rsplit(sep=None, maxsplit=0))
+131 131 | print(" x ".rsplit(maxsplit=0))
+132 |-print(" x ".rsplit(sep=None, maxsplit=0))
+ 132 |+print([" x"])
+133 133 |
+134 134 | # https://github.com/astral-sh/ruff/issues/19581 - embedded quotes in raw strings
+135 135 | r"""simple@example.com
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:135:1
+ |
+134 | # https://github.com/astral-sh/ruff/issues/19581 - embedded quotes in raw strings
+135 | / r"""simple@example.com
+136 | | very.common@example.com
+137 | | FirstName.LastName@EasierReading.org
+138 | | x@example.com
+139 | | long.email-address-with-hyphens@and.subdomains.example.com
+140 | | user.name+tag+sorting@example.com
+141 | | name/surname@example.com
+142 | | xample@s.example
+143 | | " "@example.org
+144 | | "john..doe"@example.org
+145 | | mailhost!username@example.org
+146 | | "very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com
+147 | | user%example.com@example.org
+148 | | user-@example.org
+149 | | I❤️CHOCOLATE@example.com
+150 | | this\ still\"not\\allowed@example.com
+151 | | stellyamburrr985@example.com
+152 | | Abc.123@example.com
+153 | | user+mailbox/department=shipping@example.com
+154 | | !#$%&'*+-/=?^_`.{|}~@example.com
+155 | | "Abc@def"@example.com
+156 | | "Fred\ Bloggs"@example.com
+157 | | "Joe.\\Blow"@example.com""".split("\n")
+ | |_______________________________________^
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+132 132 | print(" x ".rsplit(sep=None, maxsplit=0))
+133 133 |
+134 134 | # https://github.com/astral-sh/ruff/issues/19581 - embedded quotes in raw strings
+135 |-r"""simple@example.com
+136 |-very.common@example.com
+137 |-FirstName.LastName@EasierReading.org
+138 |-x@example.com
+139 |-long.email-address-with-hyphens@and.subdomains.example.com
+140 |-user.name+tag+sorting@example.com
+141 |-name/surname@example.com
+142 |-xample@s.example
+143 |-" "@example.org
+144 |-"john..doe"@example.org
+145 |-mailhost!username@example.org
+146 |-"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com
+147 |-user%example.com@example.org
+148 |-user-@example.org
+149 |-I❤️CHOCOLATE@example.com
+150 |-this\ still\"not\\allowed@example.com
+151 |-stellyamburrr985@example.com
+152 |-Abc.123@example.com
+153 |-user+mailbox/department=shipping@example.com
+154 |-!#$%&'*+-/=?^_`.{|}~@example.com
+155 |-"Abc@def"@example.com
+156 |-"Fred\ Bloggs"@example.com
+157 |-"Joe.\\Blow"@example.com""".split("\n")
+ 135 |+[r"simple@example.com", r"very.common@example.com", r"FirstName.LastName@EasierReading.org", r"x@example.com", r"long.email-address-with-hyphens@and.subdomains.example.com", r"user.name+tag+sorting@example.com", r"name/surname@example.com", r"xample@s.example", r'" "@example.org', r'"john..doe"@example.org', r"mailhost!username@example.org", r'"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com', r"user%example.com@example.org", r"user-@example.org", r"I❤️CHOCOLATE@example.com", r'this\ still\"not\\allowed@example.com', r"stellyamburrr985@example.com", r"Abc.123@example.com", r"user+mailbox/department=shipping@example.com", r"!#$%&'*+-/=?^_`.{|}~@example.com", r'"Abc@def"@example.com', r'"Fred\ Bloggs"@example.com', r'"Joe.\\Blow"@example.com']
+158 136 |
+159 137 |
+160 138 | r"""first
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:160:1
+ |
+160 | / r"""first
+161 | | 'no need' to escape
+162 | | "swap" quote style
+163 | | "use' ugly triple quotes""".split("\n")
+ | |_______________________________________^
+164 |
+165 | # https://github.com/astral-sh/ruff/issues/19845
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+157 157 | "Joe.\\Blow"@example.com""".split("\n")
+158 158 |
+159 159 |
+160 |-r"""first
+161 |-'no need' to escape
+162 |-"swap" quote style
+163 |-"use' ugly triple quotes""".split("\n")
+ 160 |+[r"first", r"'no need' to escape", r'"swap" quote style', r""""use' ugly triple quotes"""]
+164 161 |
+165 162 | # https://github.com/astral-sh/ruff/issues/19845
+166 163 | print("S\x1cP\x1dL\x1eI\x1fT".split())
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:166:7
+ |
+165 | # https://github.com/astral-sh/ruff/issues/19845
+166 | print("S\x1cP\x1dL\x1eI\x1fT".split())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
+168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+163 163 | "use' ugly triple quotes""".split("\n")
+164 164 |
+165 165 | # https://github.com/astral-sh/ruff/issues/19845
+166 |-print("S\x1cP\x1dL\x1eI\x1fT".split())
+ 166 |+print(["S", "P", "L", "I", "T"])
+167 167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
+168 168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+169 169 |
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:167:7
+ |
+165 | # https://github.com/astral-sh/ruff/issues/19845
+166 | print("S\x1cP\x1dL\x1eI\x1fT".split())
+167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+164 164 |
+165 165 | # https://github.com/astral-sh/ruff/issues/19845
+166 166 | print("S\x1cP\x1dL\x1eI\x1fT".split())
+167 |-print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
+ 167 |+print([">"])
+168 168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+169 169 |
+170 170 | # leading/trailing whitespace should not count towards maxsplit
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:168:7
+ |
+166 | print("S\x1cP\x1dL\x1eI\x1fT".split())
+167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
+168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+169 |
+170 | # leading/trailing whitespace should not count towards maxsplit
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+165 165 | # https://github.com/astral-sh/ruff/issues/19845
+166 166 | print("S\x1cP\x1dL\x1eI\x1fT".split())
+167 167 | print("\x1c\x1d\x1e\x1f>".split(maxsplit=0))
+168 |-print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+ 168 |+print(["<"])
+169 169 |
+170 170 | # leading/trailing whitespace should not count towards maxsplit
+171 171 | " a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:171:1
+ |
+170 | # leading/trailing whitespace should not count towards maxsplit
+171 | " a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+172 | " a b c d ".rsplit(maxsplit=2) # [" a b", "c", "d"]
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+168 168 | print("<\x1c\x1d\x1e\x1f".rsplit(maxsplit=0))
+169 169 |
+170 170 | # leading/trailing whitespace should not count towards maxsplit
+171 |-" a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+ 171 |+["a", "b", "c d "] # ["a", "b", "c d "]
+172 172 | " a b c d ".rsplit(maxsplit=2) # [" a b", "c", "d"]
+
+SIM905 [*] Consider using a list literal instead of `str.split`
+ --> SIM905.py:172:1
+ |
+170 | # leading/trailing whitespace should not count towards maxsplit
+171 | " a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+172 | " a b c d ".rsplit(maxsplit=2) # [" a b", "c", "d"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: Replace with list literal
+
+ℹ Safe fix
+169 169 |
+170 170 | # leading/trailing whitespace should not count towards maxsplit
+171 171 | " a b c d ".split(maxsplit=2) # ["a", "b", "c d "]
+172 |-" a b c d ".rsplit(maxsplit=2) # [" a b", "c", "d"]
+ 172 |+[" a b", "c", "d"] # [" a b", "c", "d"]
From f0e9c1d8f9d73c911a6d2109e31c9dd6ff6ab44c Mon Sep 17 00:00:00 2001
From: Dan Parizher <105245560+danparizher@users.noreply.github.com>
Date: Fri, 15 Aug 2025 17:17:50 -0400
Subject: [PATCH 014/160] [`isort`] Handle multiple continuation lines after
module docstring (`I002`) (#19818)
## Summary
Fixes #19815
---------
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
---
.../docstring_with_multiple_continuations.py | 4 ++++
crates/ruff_linter/src/importer/insertion.rs | 17 ++++++++++++++---
crates/ruff_linter/src/rules/isort/mod.rs | 2 ++
...ocstring_with_multiple_continuations.py.snap | 13 +++++++++++++
...ocstring_with_multiple_continuations.py.snap | 13 +++++++++++++
5 files changed, 46 insertions(+), 3 deletions(-)
create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/required_imports/docstring_with_multiple_continuations.py
create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_docstring_with_multiple_continuations.py.snap
create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_with_alias_docstring_with_multiple_continuations.py.snap
diff --git a/crates/ruff_linter/resources/test/fixtures/isort/required_imports/docstring_with_multiple_continuations.py b/crates/ruff_linter/resources/test/fixtures/isort/required_imports/docstring_with_multiple_continuations.py
new file mode 100644
index 0000000000000..d98a63c3be376
--- /dev/null
+++ b/crates/ruff_linter/resources/test/fixtures/isort/required_imports/docstring_with_multiple_continuations.py
@@ -0,0 +1,4 @@
+"""Hello, world!"""\
+\
+
+x = 1; y = 2
diff --git a/crates/ruff_linter/src/importer/insertion.rs b/crates/ruff_linter/src/importer/insertion.rs
index fbef92894e410..69c9afbe6c61e 100644
--- a/crates/ruff_linter/src/importer/insertion.rs
+++ b/crates/ruff_linter/src/importer/insertion.rs
@@ -63,9 +63,9 @@ impl<'a> Insertion<'a> {
return Insertion::inline(" ", location.add(offset).add(TextSize::of(';')), ";");
}
- // If the first token after the docstring is a continuation character (i.e. "\"), advance
- // an additional row to prevent inserting in the same logical line.
- if match_continuation(locator.after(location)).is_some() {
+ // While the first token after the docstring is a continuation character (i.e. "\"), advance
+ // additional rows to prevent inserting in the same logical line.
+ while match_continuation(locator.after(location)).is_some() {
location = locator.full_line_end(location);
}
@@ -379,6 +379,17 @@ mod tests {
Insertion::own_line("", TextSize::from(22), "\n")
);
+ let contents = r#"
+"""Hello, world!"""\
+\
+
+"#
+ .trim_start();
+ assert_eq!(
+ insert(contents)?,
+ Insertion::own_line("", TextSize::from(24), "\n")
+ );
+
let contents = r"
x = 1
"
diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs
index 0ad92d763bacc..6f18ce05b817d 100644
--- a/crates/ruff_linter/src/rules/isort/mod.rs
+++ b/crates/ruff_linter/src/rules/isort/mod.rs
@@ -797,6 +797,7 @@ mod tests {
#[test_case(Path::new("docstring_followed_by_continuation.py"))]
#[test_case(Path::new("docstring_only.py"))]
#[test_case(Path::new("docstring_with_continuation.py"))]
+ #[test_case(Path::new("docstring_with_multiple_continuations.py"))]
#[test_case(Path::new("docstring_with_semicolon.py"))]
#[test_case(Path::new("empty.py"))]
#[test_case(Path::new("existing_import.py"))]
@@ -832,6 +833,7 @@ mod tests {
#[test_case(Path::new("docstring_followed_by_continuation.py"))]
#[test_case(Path::new("docstring_only.py"))]
#[test_case(Path::new("docstring_with_continuation.py"))]
+ #[test_case(Path::new("docstring_with_multiple_continuations.py"))]
#[test_case(Path::new("docstring_with_semicolon.py"))]
#[test_case(Path::new("empty.py"))]
#[test_case(Path::new("existing_import.py"))]
diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_docstring_with_multiple_continuations.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_docstring_with_multiple_continuations.py.snap
new file mode 100644
index 0000000000000..3c438a2ed8204
--- /dev/null
+++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_docstring_with_multiple_continuations.py.snap
@@ -0,0 +1,13 @@
+---
+source: crates/ruff_linter/src/rules/isort/mod.rs
+---
+I002 [*] Missing required import: `from __future__ import annotations`
+--> docstring_with_multiple_continuations.py:1:1
+help: Insert required import: `from __future__ import annotations`
+
+ℹ Safe fix
+1 1 | """Hello, world!"""\
+2 2 | \
+3 3 |
+ 4 |+from __future__ import annotations
+4 5 | x = 1; y = 2
diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_with_alias_docstring_with_multiple_continuations.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_with_alias_docstring_with_multiple_continuations.py.snap
new file mode 100644
index 0000000000000..ce1f0d64bac87
--- /dev/null
+++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__required_import_with_alias_docstring_with_multiple_continuations.py.snap
@@ -0,0 +1,13 @@
+---
+source: crates/ruff_linter/src/rules/isort/mod.rs
+---
+I002 [*] Missing required import: `from __future__ import annotations as _annotations`
+--> docstring_with_multiple_continuations.py:1:1
+help: Insert required import: `from __future__ import annotations as _annotations`
+
+ℹ Safe fix
+1 1 | """Hello, world!"""\
+2 2 | \
+3 3 |
+ 4 |+from __future__ import annotations as _annotations
+4 5 | x = 1; y = 2
From 527a690a732ebec0ee2c5e43f6aebe0238a7e789 Mon Sep 17 00:00:00 2001
From: Micha Reiser
Date: Sat, 16 Aug 2025 16:37:28 +0200
Subject: [PATCH 015/160] [ty] Fix example in environment docs (#19937)
---
crates/ty/docs/configuration.md | 2 +-
crates/ty_project/src/metadata/options.rs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/crates/ty/docs/configuration.md b/crates/ty/docs/configuration.md
index f2a39837fa717..946c814a5d852 100644
--- a/crates/ty/docs/configuration.md
+++ b/crates/ty/docs/configuration.md
@@ -44,7 +44,7 @@ or pyright's `stubPath` configuration setting.
```toml
[tool.ty.environment]
-extra-paths = ["~/shared/my-search-path"]
+extra-paths = ["./shared/my-search-path"]
```
---
diff --git a/crates/ty_project/src/metadata/options.rs b/crates/ty_project/src/metadata/options.rs
index cc008bbd091e9..5d21320049181 100644
--- a/crates/ty_project/src/metadata/options.rs
+++ b/crates/ty_project/src/metadata/options.rs
@@ -498,7 +498,7 @@ pub struct EnvironmentOptions {
default = r#"[]"#,
value_type = "list[str]",
example = r#"
- extra-paths = ["~/shared/my-search-path"]
+ extra-paths = ["./shared/my-search-path"]
"#
)]
pub extra_paths: Option>,
From f4d8826428cc8638f17f04cf514410f0753d9893 Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Sat, 16 Aug 2025 18:45:15 +0100
Subject: [PATCH 016/160] [ty] Fix error message for invalidly providing type
arguments to `NamedTuple` when it occurs in a type expression (#19940)
---
crates/ty_python_semantic/resources/mdtest/named_tuple.md | 3 +++
crates/ty_python_semantic/src/types/infer.rs | 5 +++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/named_tuple.md b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
index 94070455c9d68..3d20c984923f3 100644
--- a/crates/ty_python_semantic/resources/mdtest/named_tuple.md
+++ b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
@@ -312,6 +312,9 @@ def expects_named_tuple(x: typing.NamedTuple):
def _(y: type[typing.NamedTuple]):
reveal_type(y) # revealed: @Todo(unsupported type[X] special form)
+
+# error: [invalid-type-form] "Special form `typing.NamedTuple` expected no type parameter"
+def _(z: typing.NamedTuple[int]): ...
```
Any instance of a `NamedTuple` class can therefore be passed for a function parameter that is
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index acd7fbb0baf7d..018eccd71ccd3 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -10783,7 +10783,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
SpecialFormType::TypingSelf
| SpecialFormType::TypeAlias
| SpecialFormType::TypedDict
- | SpecialFormType::Unknown => {
+ | SpecialFormType::Unknown
+ | SpecialFormType::NamedTuple => {
self.infer_type_expression(arguments_slice);
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
@@ -10808,7 +10809,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
SpecialFormType::Tuple => {
Type::tuple(self.infer_tuple_type_expression(arguments_slice))
}
- SpecialFormType::Generic | SpecialFormType::Protocol | SpecialFormType::NamedTuple => {
+ SpecialFormType::Generic | SpecialFormType::Protocol => {
self.infer_expression(arguments_slice);
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
From 9ac39cee98d568c712f3849cc816265488119989 Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Sat, 16 Aug 2025 19:38:43 +0100
Subject: [PATCH 017/160] [ty] Ban protocols from inheriting from non-protocol
generic classes (#19941)
---
.../resources/mdtest/protocols.md | 8 ++++++++
crates/ty_python_semantic/src/types/infer.rs | 17 +++++++----------
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/crates/ty_python_semantic/resources/mdtest/protocols.md b/crates/ty_python_semantic/resources/mdtest/protocols.md
index e68cc538ee8f1..5c7899c7a4248 100644
--- a/crates/ty_python_semantic/resources/mdtest/protocols.md
+++ b/crates/ty_python_semantic/resources/mdtest/protocols.md
@@ -150,6 +150,14 @@ class AlsoInvalid(MyProtocol, OtherProtocol, NotAProtocol, Protocol): ...
# revealed: tuple[, , , , typing.Protocol, typing.Generic, ]
reveal_type(AlsoInvalid.__mro__)
+
+class NotAGenericProtocol[T]: ...
+
+# error: [invalid-protocol] "Protocol class `StillInvalid` cannot inherit from non-protocol class `NotAGenericProtocol`"
+class StillInvalid(NotAGenericProtocol[int], Protocol): ...
+
+# revealed: tuple[, , typing.Protocol, typing.Generic, ]
+reveal_type(StillInvalid.__mro__)
```
But two exceptions to this rule are `object` and `Generic`:
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index 018eccd71ccd3..2a6ebc63ae863 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -1117,13 +1117,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// - Check for inheritance from a `@final` classes
// - If the class is a protocol class: check for inheritance from a non-protocol class
for (i, base_class) in class.explicit_bases(self.db()).iter().enumerate() {
- if let Some((class, solid_base)) = base_class
- .to_class_type(self.db())
- .and_then(|class| Some((class, class.nearest_solid_base(self.db())?)))
- {
- solid_bases.insert(solid_base, i, class.class_literal(self.db()).0);
- }
-
let base_class = match base_class {
Type::SpecialForm(SpecialFormType::Generic) => {
if let Some(builder) = self
@@ -1155,13 +1148,17 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
);
continue;
}
- Type::ClassLiteral(class) => class,
- // dynamic/unknown bases are never `@final`
+ Type::ClassLiteral(class) => ClassType::NonGeneric(*class),
+ Type::GenericAlias(class) => ClassType::Generic(*class),
_ => continue,
};
+ if let Some(solid_base) = base_class.nearest_solid_base(self.db()) {
+ solid_bases.insert(solid_base, i, base_class.class_literal(self.db()).0);
+ }
+
if is_protocol
- && !(base_class.is_protocol(self.db())
+ && !(base_class.class_literal(self.db()).0.is_protocol(self.db())
|| base_class.is_known(self.db(), KnownClass::Object))
{
if let Some(builder) = self
From b892e4548e9b71949b1a6cb52d10ccb0c61e50d3 Mon Sep 17 00:00:00 2001
From: Douglas Creager
Date: Sat, 16 Aug 2025 18:25:03 -0400
Subject: [PATCH 018/160] [ty] Track when type variables are inferable or not
(#19786)
`Type::TypeVar` now distinguishes whether the typevar in question is
inferable or not.
A typevar is _not inferable_ inside the body of the generic class or
function that binds it:
```py
def f[T](t: T) -> T:
return t
```
The infered type of `t` in the function body is `TypeVar(T,
NotInferable)`. This represents how e.g. assignability checks need to be
valid for all possible specializations of the typevar. Most of the
existing assignability/etc logic only applies to non-inferable typevars.
Outside of the function body, the typevar is _inferable_:
```py
f(4)
```
Here, the parameter type of `f` is `TypeVar(T, Inferable)`. This
represents how e.g. assignability doesn't need to hold for _all_
specializations; instead, we need to find the constraints under which
this specific assignability check holds.
This is in support of starting to perform specialization inference _as
part of_ performing the assignability check at the call site.
In the [[POPL2015][]] paper, this concept is called _monomorphic_ /
_polymorphic_, but I thought _non-inferable_ / _inferable_ would be
clearer for us.
Depends on #19784
[POPL2015]: https://doi.org/10.1145/2676726.2676991
---------
Co-authored-by: Carl Meyer
---
crates/ty_ide/src/completion.rs | 4 +-
crates/ty_ide/src/semantic_tokens.rs | 4 +-
.../resources/mdtest/annotations/self.md | 64 ++--
.../mdtest/generics/legacy/classes.md | 18 ++
.../mdtest/generics/pep695/classes.md | 13 +
.../resources/mdtest/named_tuple.md | 8 +-
.../ty_python_semantic/src/semantic_model.rs | 2 +-
crates/ty_python_semantic/src/types.rs | 291 +++++++++++++-----
.../ty_python_semantic/src/types/builder.rs | 3 +-
crates/ty_python_semantic/src/types/class.rs | 7 +-
.../src/types/class_base.rs | 1 +
.../ty_python_semantic/src/types/display.rs | 18 +-
.../ty_python_semantic/src/types/function.rs | 1 +
.../ty_python_semantic/src/types/generics.rs | 38 ++-
.../src/types/ide_support.rs | 1 +
crates/ty_python_semantic/src/types/infer.rs | 9 +-
crates/ty_python_semantic/src/types/narrow.rs | 3 +-
.../src/types/signatures.rs | 43 ++-
.../src/types/subclass_of.rs | 2 +-
.../src/types/type_ordering.rs | 4 +
.../ty_python_semantic/src/types/visitor.rs | 7 +
21 files changed, 383 insertions(+), 158 deletions(-)
diff --git a/crates/ty_ide/src/completion.rs b/crates/ty_ide/src/completion.rs
index c452ff75ffcb5..72d4a29756fc0 100644
--- a/crates/ty_ide/src/completion.rs
+++ b/crates/ty_ide/src/completion.rs
@@ -1247,7 +1247,7 @@ quux.
__init_subclass__ :: bound method Quux.__init_subclass__() -> None
__module__ :: str
__ne__ :: bound method Quux.__ne__(value: object, /) -> bool
- __new__ :: bound method Quux.__new__() -> Self@__new__
+ __new__ :: bound method Quux.__new__() -> Quux
__reduce__ :: bound method Quux.__reduce__() -> str | tuple[Any, ...]
__reduce_ex__ :: bound method Quux.__reduce_ex__(protocol: SupportsIndex, /) -> str | tuple[Any, ...]
__repr__ :: bound method Quux.__repr__() -> str
@@ -1292,7 +1292,7 @@ quux.b
__init_subclass__ :: bound method Quux.__init_subclass__() -> None
__module__ :: str
__ne__ :: bound method Quux.__ne__(value: object, /) -> bool
- __new__ :: bound method Quux.__new__() -> Self@__new__
+ __new__ :: bound method Quux.__new__() -> Quux
__reduce__ :: bound method Quux.__reduce__() -> str | tuple[Any, ...]
__reduce_ex__ :: bound method Quux.__reduce_ex__(protocol: SupportsIndex, /) -> str | tuple[Any, ...]
__repr__ :: bound method Quux.__repr__() -> str
diff --git a/crates/ty_ide/src/semantic_tokens.rs b/crates/ty_ide/src/semantic_tokens.rs
index f8f6955bc53a1..749671ad1813c 100644
--- a/crates/ty_ide/src/semantic_tokens.rs
+++ b/crates/ty_ide/src/semantic_tokens.rs
@@ -337,7 +337,9 @@ impl<'db> SemanticTokenVisitor<'db> {
match ty {
Type::ClassLiteral(_) => (SemanticTokenType::Class, modifiers),
- Type::TypeVar(_) => (SemanticTokenType::TypeParameter, modifiers),
+ Type::NonInferableTypeVar(_) | Type::TypeVar(_) => {
+ (SemanticTokenType::TypeParameter, modifiers)
+ }
Type::FunctionLiteral(_) => {
// Check if this is a method based on current scope
if self.in_class_scope {
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/self.md b/crates/ty_python_semantic/resources/mdtest/annotations/self.md
index d03dd21c02ae1..e476e03a75c46 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/self.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/self.md
@@ -1,16 +1,16 @@
# Self
+```toml
+[environment]
+python-version = "3.11"
+```
+
`Self` is treated as if it were a `TypeVar` bound to the class it's being used on.
`typing.Self` is only available in Python 3.11 and later.
## Methods
-```toml
-[environment]
-python-version = "3.11"
-```
-
```py
from typing import Self
@@ -74,11 +74,6 @@ reveal_type(C().method()) # revealed: C
## Class Methods
-```toml
-[environment]
-python-version = "3.11"
-```
-
```py
from typing import Self, TypeVar
@@ -101,11 +96,6 @@ reveal_type(Shape.bar()) # revealed: Unknown
## Attributes
-```toml
-[environment]
-python-version = "3.11"
-```
-
TODO: The use of `Self` to annotate the `next_node` attribute should be
[modeled as a property][self attribute], using `Self` in its parameter and return type.
@@ -127,11 +117,6 @@ reveal_type(LinkedList().next()) # revealed: LinkedList
## Generic Classes
-```toml
-[environment]
-python-version = "3.11"
-```
-
```py
from typing import Self, Generic, TypeVar
@@ -153,11 +138,6 @@ TODO:
## Annotations
-```toml
-[environment]
-python-version = "3.11"
-```
-
```py
from typing import Self
@@ -171,11 +151,6 @@ class Shape:
`Self` cannot be used in the signature of a function or variable.
-```toml
-[environment]
-python-version = "3.11"
-```
-
```py
from typing import Self, Generic, TypeVar
@@ -218,4 +193,33 @@ class MyMetaclass(type):
return super().__new__(cls)
```
+## Binding a method fixes `Self`
+
+When a method is bound, any instances of `Self` in its signature are "fixed", since we now know the
+specific type of the bound parameter.
+
+```py
+from typing import Self
+
+class C:
+ def instance_method(self, other: Self) -> Self:
+ return self
+
+ @classmethod
+ def class_method(cls) -> Self:
+ return cls()
+
+# revealed: bound method C.instance_method(other: C) -> C
+reveal_type(C().instance_method)
+# revealed: bound method .class_method() -> C
+reveal_type(C.class_method)
+
+class D(C): ...
+
+# revealed: bound method D.instance_method(other: D) -> D
+reveal_type(D().instance_method)
+# revealed: bound method .class_method() -> D
+reveal_type(D.class_method)
+```
+
[self attribute]: https://typing.python.org/en/latest/spec/generics.html#use-in-attribute-annotations
diff --git a/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md b/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md
index 0a60e08d85f68..234de56a8cb73 100644
--- a/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md
+++ b/crates/ty_python_semantic/resources/mdtest/generics/legacy/classes.md
@@ -491,6 +491,24 @@ class A(Generic[T]):
reveal_type(A(x=1)) # revealed: A[int]
```
+### Class typevar has another typevar as a default
+
+```py
+from typing import Generic, TypeVar
+
+T = TypeVar("T")
+U = TypeVar("U", default=T)
+
+class C(Generic[T, U]): ...
+
+reveal_type(C()) # revealed: C[Unknown, Unknown]
+
+class D(Generic[T, U]):
+ def __init__(self) -> None: ...
+
+reveal_type(D()) # revealed: D[Unknown, Unknown]
+```
+
## Generic subclass
When a generic subclass fills its superclass's type parameter with one of its own, the actual types
diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md
index 261c3d370d975..56cdbc426bf9a 100644
--- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md
+++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md
@@ -438,6 +438,19 @@ class A[T]:
reveal_type(A(x=1)) # revealed: A[int]
```
+### Class typevar has another typevar as a default
+
+```py
+class C[T, U = T]: ...
+
+reveal_type(C()) # revealed: C[Unknown, Unknown]
+
+class D[T, U = T]:
+ def __init__(self) -> None: ...
+
+reveal_type(D()) # revealed: D[Unknown, Unknown]
+```
+
## Generic subclass
When a generic subclass fills its superclass's type parameter with one of its own, the actual types
diff --git a/crates/ty_python_semantic/resources/mdtest/named_tuple.md b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
index 3d20c984923f3..b89d0a457e942 100644
--- a/crates/ty_python_semantic/resources/mdtest/named_tuple.md
+++ b/crates/ty_python_semantic/resources/mdtest/named_tuple.md
@@ -243,7 +243,7 @@ class Person(NamedTuple):
reveal_type(Person._field_defaults) # revealed: dict[str, Any]
reveal_type(Person._fields) # revealed: tuple[str, ...]
-reveal_type(Person._make) # revealed: bound method ._make(iterable: Iterable[Any]) -> Self@_make
+reveal_type(Person._make) # revealed: bound method ._make(iterable: Iterable[Any]) -> Person
reveal_type(Person._asdict) # revealed: def _asdict(self) -> dict[str, Any]
reveal_type(Person._replace) # revealed: def _replace(self, **kwargs: Any) -> Self@_replace
@@ -304,8 +304,8 @@ satisfy:
```py
def expects_named_tuple(x: typing.NamedTuple):
reveal_type(x) # revealed: tuple[object, ...] & NamedTupleLike
- reveal_type(x._make) # revealed: bound method type[NamedTupleLike]._make(iterable: Iterable[Any]) -> Self@_make
- reveal_type(x._replace) # revealed: bound method NamedTupleLike._replace(**kwargs) -> Self@_replace
+ reveal_type(x._make) # revealed: bound method type[NamedTupleLike]._make(iterable: Iterable[Any]) -> NamedTupleLike
+ reveal_type(x._replace) # revealed: bound method NamedTupleLike._replace(**kwargs) -> NamedTupleLike
# revealed: Overload[(value: tuple[object, ...], /) -> tuple[object, ...], (value: tuple[_T@__add__, ...], /) -> tuple[object, ...]]
reveal_type(x.__add__)
reveal_type(x.__iter__) # revealed: bound method tuple[object, ...].__iter__() -> Iterator[object]
@@ -328,7 +328,7 @@ class Point(NamedTuple):
x: int
y: int
-reveal_type(Point._make) # revealed: bound method ._make(iterable: Iterable[Any]) -> Self@_make
+reveal_type(Point._make) # revealed: bound method ._make(iterable: Iterable[Any]) -> Point
reveal_type(Point._asdict) # revealed: def _asdict(self) -> dict[str, Any]
reveal_type(Point._replace) # revealed: def _replace(self, **kwargs: Any) -> Self@_replace
diff --git a/crates/ty_python_semantic/src/semantic_model.rs b/crates/ty_python_semantic/src/semantic_model.rs
index 52587fe60f713..1aeeb36db7778 100644
--- a/crates/ty_python_semantic/src/semantic_model.rs
+++ b/crates/ty_python_semantic/src/semantic_model.rs
@@ -232,7 +232,7 @@ impl<'db> Completion<'db> {
| Type::BytesLiteral(_) => CompletionKind::Value,
Type::EnumLiteral(_) => CompletionKind::Enum,
Type::ProtocolInstance(_) => CompletionKind::Interface,
- Type::TypeVar(_) => CompletionKind::TypeParameter,
+ Type::NonInferableTypeVar(_) | Type::TypeVar(_) => CompletionKind::TypeParameter,
Type::Union(union) => union.elements(db).iter().find_map(|&ty| imp(db, ty))?,
Type::Intersection(intersection) => {
intersection.iter_positive(db).find_map(|ty| imp(db, ty))?
diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs
index ad7a4c0ade918..2636acfd899fd 100644
--- a/crates/ty_python_semantic/src/types.rs
+++ b/crates/ty_python_semantic/src/types.rs
@@ -44,7 +44,7 @@ use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
use crate::types::enums::{enum_metadata, is_single_member_enum};
use crate::types::function::{
- DataclassTransformerParams, FunctionSpans, FunctionType, KnownFunction,
+ DataclassTransformerParams, FunctionDecorators, FunctionSpans, FunctionType, KnownFunction,
};
use crate::types::generics::{
GenericContext, PartialSpecialization, Specialization, bind_typevar, walk_generic_context,
@@ -612,9 +612,15 @@ pub enum Type<'db> {
LiteralString,
/// A bytes literal
BytesLiteral(BytesLiteralType<'db>),
- /// An instance of a typevar in a generic class or function. When the generic class or function
- /// is specialized, we will replace this typevar with its specialization.
+ /// An instance of a typevar in a context where we can infer a specialization for it. (This is
+ /// typically the signature of a generic function, or of a constructor of a generic class.)
+ /// When the generic class or function binding this typevar is specialized, we will replace the
+ /// typevar with its specialization.
TypeVar(BoundTypeVarInstance<'db>),
+ /// An instance of a typevar where we cannot infer a specialization for it. (This is typically
+ /// the body of the generic function or class that binds the typevar.) In these positions,
+ /// properties like assignability must hold for all possible specializations.
+ NonInferableTypeVar(BoundTypeVarInstance<'db>),
/// A bound super object like `super()` or `super(A, A())`
/// This type doesn't handle an unbound super object like `super(A)`; for that we just use
/// a `Type::NominalInstance` of `builtins.super`.
@@ -823,6 +829,9 @@ impl<'db> Type<'db> {
)
.build(),
Type::TypeVar(bound_typevar) => Type::TypeVar(bound_typevar.materialize(db, variance)),
+ Type::NonInferableTypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar.materialize(db, variance))
+ }
Type::TypeIs(type_is) => {
type_is.with_type(db, type_is.return_type(db).materialize(db, variance))
}
@@ -1127,6 +1136,9 @@ impl<'db> Type<'db> {
Type::TypeVar(bound_typevar) => visitor.visit(self, || {
Type::TypeVar(bound_typevar.normalized_impl(db, visitor))
}),
+ Type::NonInferableTypeVar(bound_typevar) => visitor.visit(self, || {
+ Type::NonInferableTypeVar(bound_typevar.normalized_impl(db, visitor))
+ }),
Type::KnownInstance(known_instance) => visitor.visit(self, || {
Type::KnownInstance(known_instance.normalized_impl(db, visitor))
}),
@@ -1203,6 +1215,7 @@ impl<'db> Type<'db> {
| Type::Union(_)
| Type::Intersection(_)
| Type::Callable(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::BoundSuper(_)
| Type::TypeIs(_)
@@ -1283,6 +1296,7 @@ impl<'db> Type<'db> {
| Type::KnownInstance(_)
| Type::PropertyInstance(_)
| Type::Intersection(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::BoundSuper(_) => None,
}
@@ -1399,13 +1413,17 @@ impl<'db> Type<'db> {
// However, there is one exception to this general rule: for any given typevar `T`,
// `T` will always be a subtype of any union containing `T`.
// A similar rule applies in reverse to intersection types.
- (Type::TypeVar(_), Type::Union(union)) if union.elements(db).contains(&self) => true,
- (Type::Intersection(intersection), Type::TypeVar(_))
+ (Type::NonInferableTypeVar(_), Type::Union(union))
+ if union.elements(db).contains(&self) =>
+ {
+ true
+ }
+ (Type::Intersection(intersection), Type::NonInferableTypeVar(_))
if intersection.positive(db).contains(&target) =>
{
true
}
- (Type::Intersection(intersection), Type::TypeVar(_))
+ (Type::Intersection(intersection), Type::NonInferableTypeVar(_))
if intersection.negative(db).contains(&target) =>
{
false
@@ -1416,16 +1434,15 @@ impl<'db> Type<'db> {
//
// Note that this is not handled by the early return at the beginning of this method,
// since subtyping between a TypeVar and an arbitrary other type cannot be guaranteed to be reflexive.
- (Type::TypeVar(lhs_bound_typevar), Type::TypeVar(rhs_bound_typevar))
- if lhs_bound_typevar == rhs_bound_typevar =>
- {
- true
- }
+ (
+ Type::NonInferableTypeVar(lhs_bound_typevar),
+ Type::NonInferableTypeVar(rhs_bound_typevar),
+ ) if lhs_bound_typevar == rhs_bound_typevar => true,
// A fully static typevar is a subtype of its upper bound, and to something similar to
// the union of its constraints. An unbound, unconstrained, fully static typevar has an
// implicit upper bound of `object` (which is handled above).
- (Type::TypeVar(bound_typevar), _)
+ (Type::NonInferableTypeVar(bound_typevar), _)
if bound_typevar.typevar(db).bound_or_constraints(db).is_some() =>
{
match bound_typevar.typevar(db).bound_or_constraints(db) {
@@ -1444,7 +1461,7 @@ impl<'db> Type<'db> {
// If the typevar is constrained, there must be multiple constraints, and the typevar
// might be specialized to any one of them. However, the constraints do not have to be
// disjoint, which means an lhs type might be a subtype of all of the constraints.
- (_, Type::TypeVar(bound_typevar))
+ (_, Type::NonInferableTypeVar(bound_typevar))
if bound_typevar
.typevar(db)
.constraints(db)
@@ -1496,7 +1513,10 @@ impl<'db> Type<'db> {
// (If the typevar is bounded, it might be specialized to a smaller type than the
// bound. This is true even if the bound is a final class, since the typevar can still
// be specialized to `Never`.)
- (_, Type::TypeVar(_)) => false,
+ (_, Type::NonInferableTypeVar(_)) => false,
+
+ // TODO: Infer specializations here
+ (Type::TypeVar(_), _) | (_, Type::TypeVar(_)) => false,
// Note that the definition of `Type::AlwaysFalsy` depends on the return value of `__bool__`.
// If `__bool__` always returns True or False, it can be treated as a subtype of `AlwaysTruthy` or `AlwaysFalsy`, respectively.
@@ -1756,7 +1776,7 @@ impl<'db> Type<'db> {
// Other than the special cases enumerated above, `Instance` types and typevars are
// never subtypes of any other variants
- (Type::NominalInstance(_) | Type::TypeVar(_), _) => false,
+ (Type::NominalInstance(_) | Type::NonInferableTypeVar(_), _) => false,
}
}
@@ -1913,14 +1933,14 @@ impl<'db> Type<'db> {
// be specialized to the same type. (This is an important difference between typevars
// and `Any`!) Different typevars might be disjoint, depending on their bounds and
// constraints, which are handled below.
- (Type::TypeVar(self_bound_typevar), Type::TypeVar(other_bound_typevar))
+ (Type::NonInferableTypeVar(self_bound_typevar), Type::NonInferableTypeVar(other_bound_typevar))
if self_bound_typevar == other_bound_typevar =>
{
false
}
- (tvar @ Type::TypeVar(_), Type::Intersection(intersection))
- | (Type::Intersection(intersection), tvar @ Type::TypeVar(_))
+ (tvar @ Type::NonInferableTypeVar(_), Type::Intersection(intersection))
+ | (Type::Intersection(intersection), tvar @ Type::NonInferableTypeVar(_))
if intersection.negative(db).contains(&tvar) =>
{
true
@@ -1930,7 +1950,7 @@ impl<'db> Type<'db> {
// specialized to any type. A bounded typevar is not disjoint from its bound, and is
// only disjoint from other types if its bound is. A constrained typevar is disjoint
// from a type if all of its constraints are.
- (Type::TypeVar(bound_typevar), other) | (other, Type::TypeVar(bound_typevar)) => {
+ (Type::NonInferableTypeVar(bound_typevar), other) | (other, Type::NonInferableTypeVar(bound_typevar)) => {
match bound_typevar.typevar(db).bound_or_constraints(db) {
None => false,
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
@@ -1943,6 +1963,10 @@ impl<'db> Type<'db> {
}
}
+ // TODO: Infer specializations here
+ (Type::TypeVar(_), _)
+ | (_, Type::TypeVar(_)) => false,
+
(Type::Union(union), other) | (other, Type::Union(union)) => union
.elements(db)
.iter()
@@ -2383,7 +2407,7 @@ impl<'db> Type<'db> {
// the bound is a final singleton class, since it can still be specialized to `Never`.
// A constrained typevar is a singleton if all of its constraints are singletons. (Note
// that you cannot specialize a constrained typevar to a subtype of a constraint.)
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) => {
match bound_typevar.typevar(db).bound_or_constraints(db) {
None => false,
Some(TypeVarBoundOrConstraints::UpperBound(_)) => false,
@@ -2394,6 +2418,8 @@ impl<'db> Type<'db> {
}
}
+ Type::TypeVar(_) => false,
+
// We eagerly transform `SubclassOf` to `ClassLiteral` for final types, so `SubclassOf` is never a singleton.
Type::SubclassOf(..) => false,
Type::BoundSuper(..) => false,
@@ -2513,7 +2539,7 @@ impl<'db> Type<'db> {
// `Never`. A constrained typevar is single-valued if all of its constraints are
// single-valued. (Note that you cannot specialize a constrained typevar to a subtype
// of a constraint.)
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) => {
match bound_typevar.typevar(db).bound_or_constraints(db) {
None => false,
Some(TypeVarBoundOrConstraints::UpperBound(_)) => false,
@@ -2524,6 +2550,8 @@ impl<'db> Type<'db> {
}
}
+ Type::TypeVar(_) => false,
+
Type::SubclassOf(..) => {
// TODO: Same comment as above for `is_singleton`
false
@@ -2680,6 +2708,7 @@ impl<'db> Type<'db> {
| Type::LiteralString
| Type::BytesLiteral(_)
| Type::EnumLiteral(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::NominalInstance(_)
| Type::ProtocolInstance(_)
@@ -2790,7 +2819,7 @@ impl<'db> Type<'db> {
Type::object(db).instance_member(db, name)
}
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) => {
match bound_typevar.typevar(db).bound_or_constraints(db) {
None => Type::object(db).instance_member(db, name),
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
@@ -2803,6 +2832,16 @@ impl<'db> Type<'db> {
}
}
+ Type::TypeVar(_) => {
+ debug_assert!(
+ false,
+ "should not be able to access instance member `{name}` \
+ of type variable {} in inferable position",
+ self.display(db)
+ );
+ Place::Unbound.into()
+ }
+
Type::IntLiteral(_) => KnownClass::Int.to_instance(db).instance_member(db, name),
Type::BooleanLiteral(_) | Type::TypeIs(_) => {
KnownClass::Bool.to_instance(db).instance_member(db, name)
@@ -3329,6 +3368,7 @@ impl<'db> Type<'db> {
| Type::BytesLiteral(..)
| Type::EnumLiteral(..)
| Type::LiteralString
+ | Type::NonInferableTypeVar(..)
| Type::TypeVar(..)
| Type::SpecialForm(..)
| Type::KnownInstance(..)
@@ -3664,7 +3704,7 @@ impl<'db> Type<'db> {
}
},
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) => {
match bound_typevar.typevar(db).bound_or_constraints(db) {
None => Truthiness::Ambiguous,
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
@@ -3675,6 +3715,7 @@ impl<'db> Type<'db> {
}
}
}
+ Type::TypeVar(_) => Truthiness::Ambiguous,
Type::NominalInstance(instance) => instance
.class(db)
@@ -3767,7 +3808,7 @@ impl<'db> Type<'db> {
.into()
}
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) => {
match bound_typevar.typevar(db).bound_or_constraints(db) {
None => CallableBinding::not_callable(self).into(),
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound.bindings(db),
@@ -3780,6 +3821,15 @@ impl<'db> Type<'db> {
}
}
+ Type::TypeVar(_) => {
+ debug_assert!(
+ false,
+ "should not be able to call type variable {} in inferable position",
+ self.display(db)
+ );
+ CallableBinding::not_callable(self).into()
+ }
+
Type::BoundMethod(bound_method) => {
let signature = bound_method.function(db).signature(db);
CallableBinding::from_overloads(self, signature.overloads.iter().cloned())
@@ -5111,20 +5161,22 @@ impl<'db> Type<'db> {
// have the class's typevars still in the method signature when we attempt to call it. To
// do this, we instead use the _identity_ specialization, which maps each of the class's
// generic typevars to itself.
- let (generic_origin, generic_context, self_type) =
- match self {
- Type::ClassLiteral(class) => match class.generic_context(db) {
- Some(generic_context) => (
- Some(class),
- Some(generic_context),
- Type::from(class.apply_specialization(db, |_| {
- generic_context.identity_specialization(db)
- })),
- ),
- _ => (None, None, self),
- },
+ let (generic_origin, generic_context, self_type) = match self {
+ Type::ClassLiteral(class) => match class.generic_context(db) {
+ Some(generic_context) => (
+ Some(class),
+ Some(generic_context),
+ Type::from(class.apply_specialization(db, |_| {
+ // It is important that identity_specialization specializes the class with
+ // _inferable_ typevars, so that our specialization inference logic will
+ // try to find a specialization for them.
+ generic_context.identity_specialization(db)
+ })),
+ ),
_ => (None, None, self),
- };
+ },
+ _ => (None, None, self),
+ };
// As of now we do not model custom `__call__` on meta-classes, so the code below
// only deals with interplay between `__new__` and `__init__` methods.
@@ -5281,32 +5333,10 @@ impl<'db> Type<'db> {
// If there is no bound or constraints on a typevar `T`, `T: object` implicitly, which
// has no instance type. Otherwise, synthesize a typevar with bound or constraints
// mapped through `to_instance`.
- Type::TypeVar(bound_typevar) => {
- let typevar = bound_typevar.typevar(db);
- let bound_or_constraints = match typevar.bound_or_constraints(db)? {
- TypeVarBoundOrConstraints::UpperBound(upper_bound) => {
- TypeVarBoundOrConstraints::UpperBound(upper_bound.to_instance(db)?)
- }
- TypeVarBoundOrConstraints::Constraints(constraints) => {
- TypeVarBoundOrConstraints::Constraints(
- constraints.to_instance(db)?.into_union()?,
- )
- }
- };
- Some(Type::TypeVar(BoundTypeVarInstance::new(
- db,
- TypeVarInstance::new(
- db,
- Name::new(format!("{}'instance", typevar.name(db))),
- None,
- Some(bound_or_constraints.into()),
- typevar.variance(db),
- None,
- typevar.kind(db),
- ),
- bound_typevar.binding_context(db),
- )))
+ Type::NonInferableTypeVar(bound_typevar) => {
+ Some(Type::NonInferableTypeVar(bound_typevar.to_instance(db)?))
}
+ Type::TypeVar(bound_typevar) => Some(Type::TypeVar(bound_typevar.to_instance(db)?)),
Type::TypeAlias(alias) => alias.value_type(db).to_instance(db),
Type::Intersection(_) => Some(todo_type!("Type::Intersection.to_instance")),
Type::BooleanLiteral(_)
@@ -5390,6 +5420,7 @@ impl<'db> Type<'db> {
| Type::LiteralString
| Type::ModuleLiteral(_)
| Type::StringLiteral(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::Callable(_)
| Type::BoundMethod(_)
@@ -5423,7 +5454,7 @@ impl<'db> Type<'db> {
typevar_binding_context,
*typevar,
)
- .map(Type::TypeVar)
+ .map(Type::NonInferableTypeVar)
.unwrap_or(*self))
}
KnownInstanceType::Deprecated(_) => Err(InvalidTypeExpressionError {
@@ -5506,7 +5537,7 @@ impl<'db> Type<'db> {
Some(TypeVarBoundOrConstraints::UpperBound(instance).into()),
TypeVarVariance::Invariant,
None,
- TypeVarKind::Implicit,
+ TypeVarKind::TypingSelf,
);
Ok(bind_typevar(
db,
@@ -5516,7 +5547,7 @@ impl<'db> Type<'db> {
typevar_binding_context,
typevar,
)
- .map(Type::TypeVar)
+ .map(Type::NonInferableTypeVar)
.unwrap_or(*self))
}
SpecialFormType::TypeAlias => Ok(Type::Dynamic(DynamicType::TodoTypeAlias)),
@@ -5685,7 +5716,7 @@ impl<'db> Type<'db> {
}
Type::Callable(_) | Type::DataclassTransformer(_) => KnownClass::Type.to_instance(db),
Type::ModuleLiteral(_) => KnownClass::ModuleType.to_class_literal(db),
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) => {
match bound_typevar.typevar(db).bound_or_constraints(db) {
None => KnownClass::Type.to_instance(db),
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound.to_meta_type(db),
@@ -5696,6 +5727,7 @@ impl<'db> Type<'db> {
}
}
}
+ Type::TypeVar(_) => KnownClass::Type.to_instance(db),
Type::ClassLiteral(class) => class.metaclass(db),
Type::GenericAlias(alias) => ClassType::from(*alias).metaclass(db),
@@ -5792,16 +5824,46 @@ impl<'db> Type<'db> {
TypeMapping::PartialSpecialization(partial) => {
partial.get(db, bound_typevar).unwrap_or(self)
}
- TypeMapping::PromoteLiterals | TypeMapping::BindLegacyTypevars(_) => self,
+ TypeMapping::BindSelf(self_type) => {
+ if bound_typevar.typevar(db).is_self(db) {
+ *self_type
+ } else {
+ self
+ }
+ }
+ TypeMapping::PromoteLiterals | TypeMapping::BindLegacyTypevars(_) |
+ TypeMapping::MarkTypeVarsInferable(_) => self,
+ }
+
+ Type::NonInferableTypeVar(bound_typevar) => match type_mapping {
+ TypeMapping::Specialization(specialization) => {
+ specialization.get(db, bound_typevar).unwrap_or(self)
+ }
+ TypeMapping::PartialSpecialization(partial) => {
+ partial.get(db, bound_typevar).unwrap_or(self)
+ }
+ TypeMapping::MarkTypeVarsInferable(binding_context) => {
+ if bound_typevar.binding_context(db) == *binding_context {
+ Type::TypeVar(bound_typevar)
+ } else {
+ self
+ }
+ }
+ TypeMapping::PromoteLiterals |
+ TypeMapping::BindLegacyTypevars(_) |
+ TypeMapping::BindSelf(_)
+ => self,
}
Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) => match type_mapping {
- TypeMapping::Specialization(_) |
- TypeMapping::PartialSpecialization(_) |
- TypeMapping::PromoteLiterals => self,
TypeMapping::BindLegacyTypevars(binding_context) => {
Type::TypeVar(BoundTypeVarInstance::new(db, typevar, *binding_context))
}
+ TypeMapping::Specialization(_) |
+ TypeMapping::PartialSpecialization(_) |
+ TypeMapping::PromoteLiterals |
+ TypeMapping::BindSelf(_) |
+ TypeMapping::MarkTypeVarsInferable(_) => self,
}
Type::FunctionLiteral(function) => {
@@ -5896,7 +5958,9 @@ impl<'db> Type<'db> {
| Type::EnumLiteral(_) => match type_mapping {
TypeMapping::Specialization(_) |
TypeMapping::PartialSpecialization(_) |
- TypeMapping::BindLegacyTypevars(_) => self,
+ TypeMapping::BindLegacyTypevars(_) |
+ TypeMapping::BindSelf(_) |
+ TypeMapping::MarkTypeVarsInferable(_) => self,
TypeMapping::PromoteLiterals => self.literal_fallback_instance(db)
.expect("literal type should have fallback instance type"),
}
@@ -5929,10 +5993,10 @@ impl<'db> Type<'db> {
typevars: &mut FxOrderSet>,
) {
match self {
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
if matches!(
bound_typevar.typevar(db).kind(db),
- TypeVarKind::Legacy | TypeVarKind::Implicit
+ TypeVarKind::Legacy | TypeVarKind::TypingSelf
) && binding_context.is_none_or(|binding_context| {
bound_typevar.binding_context(db) == BindingContext::Definition(binding_context)
}) {
@@ -6145,6 +6209,7 @@ impl<'db> Type<'db> {
| Self::PropertyInstance(_)
| Self::BoundSuper(_) => self.to_meta_type(db).definition(db),
+ Self::NonInferableTypeVar(bound_typevar) |
Self::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(bound_typevar.typevar(db).definition(db)?)),
Self::ProtocolInstance(protocol) => match protocol.inner {
@@ -6270,6 +6335,10 @@ pub enum TypeMapping<'a, 'db> {
/// Binds a legacy typevar with the generic context (class, function, type alias) that it is
/// being used in.
BindLegacyTypevars(BindingContext<'db>),
+ /// Binds any `typing.Self` typevar with a particular `self` class.
+ BindSelf(Type<'db>),
+ /// Marks the typevars that are bound by a generic class or function as inferable.
+ MarkTypeVarsInferable(BindingContext<'db>),
}
fn walk_type_mapping<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
@@ -6284,7 +6353,12 @@ fn walk_type_mapping<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
TypeMapping::PartialSpecialization(specialization) => {
walk_partial_specialization(db, specialization, visitor);
}
- TypeMapping::PromoteLiterals | TypeMapping::BindLegacyTypevars(_) => {}
+ TypeMapping::BindSelf(self_type) => {
+ visitor.visit_type(db, *self_type);
+ }
+ TypeMapping::PromoteLiterals
+ | TypeMapping::BindLegacyTypevars(_)
+ | TypeMapping::MarkTypeVarsInferable(_) => {}
}
}
@@ -6301,6 +6375,10 @@ impl<'db> TypeMapping<'_, 'db> {
TypeMapping::BindLegacyTypevars(binding_context) => {
TypeMapping::BindLegacyTypevars(*binding_context)
}
+ TypeMapping::BindSelf(self_type) => TypeMapping::BindSelf(*self_type),
+ TypeMapping::MarkTypeVarsInferable(binding_context) => {
+ TypeMapping::MarkTypeVarsInferable(*binding_context)
+ }
}
}
@@ -6316,6 +6394,12 @@ impl<'db> TypeMapping<'_, 'db> {
TypeMapping::BindLegacyTypevars(binding_context) => {
TypeMapping::BindLegacyTypevars(*binding_context)
}
+ TypeMapping::BindSelf(self_type) => {
+ TypeMapping::BindSelf(self_type.normalized_impl(db, visitor))
+ }
+ TypeMapping::MarkTypeVarsInferable(binding_context) => {
+ TypeMapping::MarkTypeVarsInferable(*binding_context)
+ }
}
}
}
@@ -6836,7 +6920,7 @@ pub enum TypeVarKind {
/// `def foo[T](x: T) -> T: ...`
Pep695,
/// `typing.Self`
- Implicit,
+ TypingSelf,
}
/// A type variable that has not been bound to a generic context yet.
@@ -6926,8 +7010,8 @@ impl<'db> TypeVarInstance<'db> {
BoundTypeVarInstance::new(db, self, BindingContext::Definition(binding_context))
}
- pub(crate) fn is_implicit(self, db: &'db dyn Db) -> bool {
- matches!(self.kind(db), TypeVarKind::Implicit)
+ pub(crate) fn is_self(self, db: &'db dyn Db) -> bool {
+ matches!(self.kind(db), TypeVarKind::TypingSelf)
}
pub(crate) fn upper_bound(self, db: &'db dyn Db) -> Option> {
@@ -7022,6 +7106,26 @@ impl<'db> TypeVarInstance<'db> {
)
}
+ fn to_instance(self, db: &'db dyn Db) -> Option {
+ let bound_or_constraints = match self.bound_or_constraints(db)? {
+ TypeVarBoundOrConstraints::UpperBound(upper_bound) => {
+ TypeVarBoundOrConstraints::UpperBound(upper_bound.to_instance(db)?)
+ }
+ TypeVarBoundOrConstraints::Constraints(constraints) => {
+ TypeVarBoundOrConstraints::Constraints(constraints.to_instance(db)?.into_union()?)
+ }
+ };
+ Some(Self::new(
+ db,
+ Name::new(format!("{}'instance", self.name(db))),
+ None,
+ Some(bound_or_constraints.into()),
+ self.variance(db),
+ None,
+ self.kind(db),
+ ))
+ }
+
#[salsa::tracked]
fn lazy_bound(self, db: &'db dyn Db) -> Option> {
let definition = self.definition(db)?;
@@ -7138,6 +7242,14 @@ impl<'db> BoundTypeVarInstance<'db> {
self.binding_context(db),
)
}
+
+ fn to_instance(self, db: &'db dyn Db) -> Option {
+ Some(Self::new(
+ db,
+ self.typevar(db).to_instance(db)?,
+ self.binding_context(db),
+ ))
+ }
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
@@ -8328,16 +8440,35 @@ fn walk_bound_method_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
visitor.visit_type(db, method.self_instance(db));
}
+#[salsa::tracked]
impl<'db> BoundMethodType<'db> {
+ /// Returns the type that replaces any `typing.Self` annotations in the bound method signature.
+ /// This is normally the bound-instance type (the type of `self` or `cls`), but if the bound method is
+ /// a `@classmethod`, then it should be an instance of that bound-instance type.
+ pub(crate) fn typing_self_type(self, db: &'db dyn Db) -> Type<'db> {
+ let mut self_instance = self.self_instance(db);
+ if self
+ .function(db)
+ .has_known_decorator(db, FunctionDecorators::CLASSMETHOD)
+ {
+ self_instance = self_instance.to_instance(db).unwrap_or_else(Type::unknown);
+ }
+ self_instance
+ }
+
+ #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)]
pub(crate) fn into_callable_type(self, db: &'db dyn Db) -> CallableType<'db> {
+ let function = self.function(db);
+ let self_instance = self.typing_self_type(db);
+
CallableType::new(
db,
CallableSignature::from_overloads(
- self.function(db)
+ function
.signature(db)
.overloads
.iter()
- .map(signatures::Signature::bind_self),
+ .map(|signature| signature.bind_self(db, Some(self_instance))),
),
false,
)
@@ -8435,7 +8566,7 @@ impl<'db> CallableType<'db> {
pub(crate) fn bind_self(self, db: &'db dyn Db) -> Type<'db> {
Type::Callable(CallableType::new(
db,
- self.signatures(db).bind_self(),
+ self.signatures(db).bind_self(db, None),
false,
))
}
diff --git a/crates/ty_python_semantic/src/types/builder.rs b/crates/ty_python_semantic/src/types/builder.rs
index 8e529e4fcafd5..0f6ba1782d3e5 100644
--- a/crates/ty_python_semantic/src/types/builder.rs
+++ b/crates/ty_python_semantic/src/types/builder.rs
@@ -983,7 +983,8 @@ impl<'db> InnerIntersectionBuilder<'db> {
let mut positive_to_remove = SmallVec::<[usize; 1]>::new();
for (typevar_index, ty) in self.positive.iter().enumerate() {
- let Type::TypeVar(bound_typevar) = ty else {
+ let (Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar)) = ty
+ else {
continue;
};
let Some(TypeVarBoundOrConstraints::Constraints(constraints)) =
diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs
index cd749f8444060..beac62e3618d0 100644
--- a/crates/ty_python_semantic/src/types/class.rs
+++ b/crates/ty_python_semantic/src/types/class.rs
@@ -966,6 +966,7 @@ impl<'db> ClassType<'db> {
/// Return a callable type (or union of callable types) that represents the callable
/// constructor signature of this class.
+ #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)]
pub(super) fn into_callable(self, db: &'db dyn Db) -> Type<'db> {
let self_ty = Type::from(self);
let metaclass_dunder_call_function_symbol = self_ty
@@ -1017,9 +1018,10 @@ impl<'db> ClassType<'db> {
})
});
+ let instance_ty = Type::instance(db, self);
let dunder_new_bound_method = Type::Callable(CallableType::new(
db,
- dunder_new_signature.bind_self(),
+ dunder_new_signature.bind_self(db, Some(instance_ty)),
true,
));
@@ -1057,9 +1059,10 @@ impl<'db> ClassType<'db> {
if let Some(signature) = signature {
let synthesized_signature = |signature: &Signature<'db>| {
+ let instance_ty = Type::instance(db, self);
Signature::new(signature.parameters().clone(), Some(correct_return_type))
.with_definition(signature.definition())
- .bind_self()
+ .bind_self(db, Some(instance_ty))
};
let synthesized_dunder_init_signature = CallableSignature::from_overloads(
diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs
index aff7e833ce19b..e8a5fd1e41e8f 100644
--- a/crates/ty_python_semantic/src/types/class_base.rs
+++ b/crates/ty_python_semantic/src/types/class_base.rs
@@ -155,6 +155,7 @@ impl<'db> ClassBase<'db> {
| Type::StringLiteral(_)
| Type::LiteralString
| Type::ModuleLiteral(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::BoundSuper(_)
| Type::ProtocolInstance(_)
diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs
index b50ca3d996b10..3d23a8393d25a 100644
--- a/crates/ty_python_semantic/src/types/display.rs
+++ b/crates/ty_python_semantic/src/types/display.rs
@@ -130,6 +130,8 @@ impl Display for DisplayRepresentation<'_> {
Type::Callable(callable) => callable.display(self.db).fmt(f),
Type::BoundMethod(bound_method) => {
let function = bound_method.function(self.db);
+ let self_ty = bound_method.self_instance(self.db);
+ let typing_self_ty = bound_method.typing_self_type(self.db);
match function.signature(self.db).overloads.as_slice() {
[signature] => {
@@ -142,9 +144,11 @@ impl Display for DisplayRepresentation<'_> {
f,
"bound method {instance}.{method}{type_parameters}{signature}",
method = function.name(self.db),
- instance = bound_method.self_instance(self.db).display(self.db),
+ instance = self_ty.display(self.db),
type_parameters = type_parameters,
- signature = signature.bind_self().display(self.db)
+ signature = signature
+ .bind_self(self.db, Some(typing_self_ty))
+ .display(self.db)
)
}
signatures => {
@@ -152,7 +156,11 @@ impl Display for DisplayRepresentation<'_> {
f.write_str("Overload[")?;
let mut join = f.join(", ");
for signature in signatures {
- join.entry(&signature.bind_self().display(self.db));
+ join.entry(
+ &signature
+ .bind_self(self.db, Some(typing_self_ty))
+ .display(self.db),
+ );
}
f.write_str("]")
}
@@ -214,7 +222,7 @@ impl Display for DisplayRepresentation<'_> {
name = enum_literal.name(self.db),
)
}
- Type::TypeVar(bound_typevar) => {
+ Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
f.write_str(bound_typevar.typevar(self.db).name(self.db))?;
if let Some(binding_context) = bound_typevar.binding_context(self.db).name(self.db)
{
@@ -455,7 +463,7 @@ impl Display for DisplayGenericContext<'_> {
let non_implicit_variables: Vec<_> = variables
.iter()
- .filter(|bound_typevar| !bound_typevar.typevar(self.db).is_implicit(self.db))
+ .filter(|bound_typevar| !bound_typevar.typevar(self.db).is_self(self.db))
.collect();
if non_implicit_variables.is_empty() {
diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs
index 632425f16c3be..b482e23e7439f 100644
--- a/crates/ty_python_semantic/src/types/function.rs
+++ b/crates/ty_python_semantic/src/types/function.rs
@@ -1014,6 +1014,7 @@ fn is_instance_truthiness<'db>(
| Type::PropertyInstance(..)
| Type::AlwaysTruthy
| Type::AlwaysFalsy
+ | Type::NonInferableTypeVar(..)
| Type::TypeVar(..)
| Type::BoundSuper(..)
| Type::TypeIs(..)
diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs
index 00089be337e41..8b628fd375528 100644
--- a/crates/ty_python_semantic/src/types/generics.rs
+++ b/crates/ty_python_semantic/src/types/generics.rs
@@ -236,7 +236,8 @@ impl<'db> GenericContext<'db> {
db: &'db dyn Db,
known_class: Option,
) -> Specialization<'db> {
- let partial = self.specialize_partial(db, &vec![None; self.variables(db).len()]);
+ let partial =
+ self.specialize_partial(db, std::iter::repeat_n(None, self.variables(db).len()));
if known_class == Some(KnownClass::Tuple) {
Specialization::new(
db,
@@ -249,6 +250,10 @@ impl<'db> GenericContext<'db> {
}
}
+ /// Returns a specialization of this generic context where each typevar is mapped to itself.
+ /// (And in particular, to an _inferable_ version of itself, since this will be used in our
+ /// class constructor invocation machinery to infer a specialization for the class from the
+ /// arguments passed to its constructor.)
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> Specialization<'db> {
let types = self
.variables(db)
@@ -314,11 +319,12 @@ impl<'db> GenericContext<'db> {
/// Creates a specialization of this generic context. Panics if the length of `types` does not
/// match the number of typevars in the generic context. If any provided type is `None`, we
/// will use the corresponding typevar's default type.
- pub(crate) fn specialize_partial(
- self,
- db: &'db dyn Db,
- types: &[Option>],
- ) -> Specialization<'db> {
+ pub(crate) fn specialize_partial(self, db: &'db dyn Db, types: I) -> Specialization<'db>
+ where
+ I: IntoIterator
- >>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ let types = types.into_iter();
let variables = self.variables(db);
assert!(variables.len() == types.len());
@@ -331,9 +337,9 @@ impl<'db> GenericContext<'db> {
// If there is a mapping for `T`, we want to map `U` to that type, not to `T`. To handle
// this, we repeatedly apply the specialization to itself, until we reach a fixed point.
let mut expanded = vec![Type::unknown(); types.len()];
- for (idx, (ty, typevar)) in types.iter().zip(variables).enumerate() {
+ for (idx, (ty, typevar)) in types.zip(variables).enumerate() {
if let Some(ty) = ty {
- expanded[idx] = *ty;
+ expanded[idx] = ty;
continue;
}
@@ -749,18 +755,12 @@ impl<'db> SpecializationBuilder<'db> {
}
pub(crate) fn build(&mut self, generic_context: GenericContext<'db>) -> Specialization<'db> {
- let types: Box<[_]> = generic_context
+ let types = generic_context
.variables(self.db)
.iter()
- .map(|variable| {
- self.types
- .get(variable)
- .copied()
- .unwrap_or(variable.default_type(self.db).unwrap_or(Type::unknown()))
- })
- .collect();
+ .map(|variable| self.types.get(variable).copied());
// TODO Infer the tuple spec for a tuple type
- Specialization::new(self.db, generic_context, types, None)
+ generic_context.specialize_partial(self.db, types)
}
fn add_type_mapping(&mut self, bound_typevar: BoundTypeVarInstance<'db>, ty: Type<'db>) {
@@ -777,6 +777,10 @@ impl<'db> SpecializationBuilder<'db> {
formal: Type<'db>,
actual: Type<'db>,
) -> Result<(), SpecializationError<'db>> {
+ if formal == actual {
+ return Ok(());
+ }
+
// If the actual type is a subtype of the formal type, then return without adding any new
// type mappings. (Note that if the formal type contains any typevars, this check will
// fail, since no non-typevar types are assignable to a typevar. Also note that we are
diff --git a/crates/ty_python_semantic/src/types/ide_support.rs b/crates/ty_python_semantic/src/types/ide_support.rs
index 12f3a07bd08ec..36a139145c301 100644
--- a/crates/ty_python_semantic/src/types/ide_support.rs
+++ b/crates/ty_python_semantic/src/types/ide_support.rs
@@ -151,6 +151,7 @@ impl<'db> AllMembers<'db> {
| Type::ProtocolInstance(_)
| Type::SpecialForm(_)
| Type::KnownInstance(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::BoundSuper(_)
| Type::TypeIs(_) => match ty.to_meta_type(db) {
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index 2a6ebc63ae863..c819d1d3486e9 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -4025,6 +4025,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
+ | Type::NonInferableTypeVar(..)
| Type::TypeVar(..)
| Type::AlwaysTruthy
| Type::AlwaysFalsy
@@ -7231,6 +7232,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::BytesLiteral(_)
| Type::EnumLiteral(_)
| Type::BoundSuper(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::TypeIs(_)
| Type::TypedDict(_),
@@ -7572,6 +7574,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::BytesLiteral(_)
| Type::EnumLiteral(_)
| Type::BoundSuper(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::TypeIs(_)
| Type::TypedDict(_),
@@ -7601,6 +7604,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::BytesLiteral(_)
| Type::EnumLiteral(_)
| Type::BoundSuper(_)
+ | Type::NonInferableTypeVar(_)
| Type::TypeVar(_)
| Type::TypeIs(_)
| Type::TypedDict(_),
@@ -8652,7 +8656,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
.next()
.expect("valid bindings should have matching overload");
Type::from(generic_class.apply_specialization(self.db(), |_| {
- generic_context.specialize_partial(self.db(), overload.parameter_types())
+ generic_context
+ .specialize_partial(self.db(), overload.parameter_types().iter().copied())
}))
}
@@ -10604,7 +10609,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
let mut signature_iter = callable_binding.into_iter().map(|binding| {
if argument_type.is_bound_method() {
- binding.signature.bind_self()
+ binding.signature.bind_self(self.db(), Some(argument_type))
} else {
binding.signature.clone()
}
diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs
index 8569c961d5d8d..d1df76dee6fa2 100644
--- a/crates/ty_python_semantic/src/types/narrow.rs
+++ b/crates/ty_python_semantic/src/types/narrow.rs
@@ -215,7 +215,7 @@ impl ClassInfoConstraintFunction {
Type::Union(union) => {
union.try_map(db, |element| self.generate_constraint(db, *element))
}
- Type::TypeVar(bound_typevar) => match bound_typevar
+ Type::NonInferableTypeVar(bound_typevar) => match bound_typevar
.typevar(db)
.bound_or_constraints(db)?
{
@@ -259,6 +259,7 @@ impl ClassInfoConstraintFunction {
| Type::IntLiteral(_)
| Type::KnownInstance(_)
| Type::TypeIs(_)
+ | Type::TypeVar(_)
| Type::WrapperDescriptor(_)
| Type::DataclassTransformer(_)
| Type::TypedDict(_) => None,
diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs
index 11ca44bb8fa7e..8d1492adc6970 100644
--- a/crates/ty_python_semantic/src/types/signatures.rs
+++ b/crates/ty_python_semantic/src/types/signatures.rs
@@ -19,7 +19,8 @@ use super::{DynamicType, Type, TypeVarVariance, definition_expression_type};
use crate::semantic_index::definition::Definition;
use crate::types::generics::{GenericContext, walk_generic_context};
use crate::types::{
- BoundTypeVarInstance, KnownClass, NormalizedVisitor, TypeMapping, TypeRelation, todo_type,
+ BindingContext, BoundTypeVarInstance, KnownClass, NormalizedVisitor, TypeMapping, TypeRelation,
+ todo_type,
};
use crate::{Db, FxOrderSet};
use ruff_python_ast::{self as ast, name::Name};
@@ -98,9 +99,16 @@ impl<'db> CallableSignature<'db> {
}
}
- pub(crate) fn bind_self(&self) -> Self {
+ /// Binds the first (presumably `self`) parameter of this signature. If a `self_type` is
+ /// provided, we will replace any occurrences of `typing.Self` in the parameter and return
+ /// annotations with that type.
+ pub(crate) fn bind_self(&self, db: &'db dyn Db, self_type: Option>) -> Self {
Self {
- overloads: self.overloads.iter().map(Signature::bind_self).collect(),
+ overloads: self
+ .overloads
+ .iter()
+ .map(|signature| signature.bind_self(db, self_type))
+ .collect(),
}
}
@@ -328,8 +336,11 @@ impl<'db> Signature<'db> {
let parameters =
Parameters::from_parameters(db, definition, function_node.parameters.as_ref());
let return_ty = function_node.returns.as_ref().map(|returns| {
- let plain_return_ty = definition_expression_type(db, definition, returns.as_ref());
-
+ let plain_return_ty = definition_expression_type(db, definition, returns.as_ref())
+ .apply_type_mapping(
+ db,
+ &TypeMapping::MarkTypeVarsInferable(BindingContext::Definition(definition)),
+ );
if function_node.is_async && !is_generator {
KnownClass::CoroutineType
.to_specialized_instance(db, [Type::any(), Type::any(), plain_return_ty])
@@ -457,13 +468,20 @@ impl<'db> Signature<'db> {
self.definition
}
- pub(crate) fn bind_self(&self) -> Self {
+ pub(crate) fn bind_self(&self, db: &'db dyn Db, self_type: Option>) -> Self {
+ let mut parameters = Parameters::new(self.parameters().iter().skip(1).cloned());
+ let mut return_ty = self.return_ty;
+ if let Some(self_type) = self_type {
+ parameters = parameters.apply_type_mapping(db, &TypeMapping::BindSelf(self_type));
+ return_ty =
+ return_ty.map(|ty| ty.apply_type_mapping(db, &TypeMapping::BindSelf(self_type)));
+ }
Self {
generic_context: self.generic_context,
inherited_generic_context: self.inherited_generic_context,
definition: self.definition,
- parameters: Parameters::new(self.parameters().iter().skip(1).cloned()),
- return_ty: self.return_ty,
+ parameters,
+ return_ty,
}
}
@@ -1432,9 +1450,12 @@ impl<'db> Parameter<'db> {
kind: ParameterKind<'db>,
) -> Self {
Self {
- annotated_type: parameter
- .annotation()
- .map(|annotation| definition_expression_type(db, definition, annotation)),
+ annotated_type: parameter.annotation().map(|annotation| {
+ definition_expression_type(db, definition, annotation).apply_type_mapping(
+ db,
+ &TypeMapping::MarkTypeVarsInferable(BindingContext::Definition(definition)),
+ )
+ }),
kind,
form: ParameterForm::Value,
}
diff --git a/crates/ty_python_semantic/src/types/subclass_of.rs b/crates/ty_python_semantic/src/types/subclass_of.rs
index 1a67759432b3d..c27e92018e1e4 100644
--- a/crates/ty_python_semantic/src/types/subclass_of.rs
+++ b/crates/ty_python_semantic/src/types/subclass_of.rs
@@ -91,7 +91,7 @@ impl<'db> SubclassOfType<'db> {
TypeVarVariance::Invariant => {
// We need to materialize this to `type[T]` but that isn't representable so
// we instead use a type variable with an upper bound of `type`.
- Type::TypeVar(BoundTypeVarInstance::new(
+ Type::NonInferableTypeVar(BoundTypeVarInstance::new(
db,
TypeVarInstance::new(
db,
diff --git a/crates/ty_python_semantic/src/types/type_ordering.rs b/crates/ty_python_semantic/src/types/type_ordering.rs
index 0747fc8d176d6..21612c36148ac 100644
--- a/crates/ty_python_semantic/src/types/type_ordering.rs
+++ b/crates/ty_python_semantic/src/types/type_ordering.rs
@@ -142,6 +142,10 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
(Type::ProtocolInstance(_), _) => Ordering::Less,
(_, Type::ProtocolInstance(_)) => Ordering::Greater,
+ (Type::NonInferableTypeVar(left), Type::NonInferableTypeVar(right)) => left.cmp(right),
+ (Type::NonInferableTypeVar(_), _) => Ordering::Less,
+ (_, Type::NonInferableTypeVar(_)) => Ordering::Greater,
+
(Type::TypeVar(left), Type::TypeVar(right)) => left.cmp(right),
(Type::TypeVar(_), _) => Ordering::Less,
(_, Type::TypeVar(_)) => Ordering::Greater,
diff --git a/crates/ty_python_semantic/src/types/visitor.rs b/crates/ty_python_semantic/src/types/visitor.rs
index deb68eab7427c..4b58f20bf5071 100644
--- a/crates/ty_python_semantic/src/types/visitor.rs
+++ b/crates/ty_python_semantic/src/types/visitor.rs
@@ -114,6 +114,7 @@ enum NonAtomicType<'db> {
NominalInstance(NominalInstanceType<'db>),
PropertyInstance(PropertyInstanceType<'db>),
TypeIs(TypeIsType<'db>),
+ NonInferableTypeVar(BoundTypeVarInstance<'db>),
TypeVar(BoundTypeVarInstance<'db>),
ProtocolInstance(ProtocolInstanceType<'db>),
TypedDict(TypedDictType<'db>),
@@ -177,6 +178,9 @@ impl<'db> From> for TypeKind<'db> {
Type::PropertyInstance(property) => {
TypeKind::NonAtomic(NonAtomicType::PropertyInstance(property))
}
+ Type::NonInferableTypeVar(bound_typevar) => {
+ TypeKind::NonAtomic(NonAtomicType::NonInferableTypeVar(bound_typevar))
+ }
Type::TypeVar(bound_typevar) => {
TypeKind::NonAtomic(NonAtomicType::TypeVar(bound_typevar))
}
@@ -216,6 +220,9 @@ fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
visitor.visit_property_instance_type(db, property);
}
NonAtomicType::TypeIs(type_is) => visitor.visit_typeis_type(db, type_is),
+ NonAtomicType::NonInferableTypeVar(bound_typevar) => {
+ visitor.visit_bound_type_var_type(db, bound_typevar);
+ }
NonAtomicType::TypeVar(bound_typevar) => {
visitor.visit_bound_type_var_type(db, bound_typevar);
}
From ec3163781c645b2e72414e8b0c5686e815d34e0d Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Sun, 17 Aug 2025 18:54:24 +0100
Subject: [PATCH 019/160] [ty] Remove unused code (#19949)
---
crates/ty_ide/src/lib.rs | 3 +-
crates/ty_python_semantic/src/types.rs | 206 +++++++-----------
.../src/types/call/arguments.rs | 2 +-
.../ty_python_semantic/src/types/generics.rs | 13 +-
4 files changed, 83 insertions(+), 141 deletions(-)
diff --git a/crates/ty_ide/src/lib.rs b/crates/ty_ide/src/lib.rs
index 45d5c897f0615..55e4a920f84a1 100644
--- a/crates/ty_ide/src/lib.rs
+++ b/crates/ty_ide/src/lib.rs
@@ -235,7 +235,8 @@ impl HasNavigationTargets for Type<'_> {
fn navigation_targets(&self, db: &dyn Db) -> NavigationTargets {
match self {
Type::Union(union) => union
- .iter(db)
+ .elements(db)
+ .iter()
.flat_map(|target| target.navigation_targets(db))
.collect(),
diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs
index 2636acfd899fd..3440ee58b0590 100644
--- a/crates/ty_python_semantic/src/types.rs
+++ b/crates/ty_python_semantic/src/types.rs
@@ -3,7 +3,6 @@ use itertools::{Either, Itertools};
use ruff_db::parsed::parsed_module;
use std::borrow::Cow;
-use std::slice::Iter;
use bitflags::bitflags;
use call::{CallDunderError, CallError, CallErrorKind};
@@ -635,15 +634,15 @@ pub enum Type<'db> {
#[salsa::tracked]
impl<'db> Type<'db> {
- pub const fn any() -> Self {
+ pub(crate) const fn any() -> Self {
Self::Dynamic(DynamicType::Any)
}
- pub const fn unknown() -> Self {
+ pub(crate) const fn unknown() -> Self {
Self::Dynamic(DynamicType::Unknown)
}
- pub fn object(db: &'db dyn Db) -> Self {
+ pub(crate) fn object(db: &'db dyn Db) -> Self {
KnownClass::Object.to_instance(db)
}
@@ -651,12 +650,12 @@ impl<'db> Type<'db> {
matches!(self, Type::Dynamic(DynamicType::Unknown))
}
- pub const fn is_never(&self) -> bool {
+ pub(crate) const fn is_never(&self) -> bool {
matches!(self, Type::Never)
}
/// Returns `true` if `self` is [`Type::Callable`].
- pub const fn is_callable_type(&self) -> bool {
+ pub(crate) const fn is_callable_type(&self) -> bool {
matches!(self, Type::Callable(..))
}
@@ -670,7 +669,7 @@ impl<'db> Type<'db> {
.is_some_and(|instance| instance.class(db).is_known(db, KnownClass::Bool))
}
- pub fn is_notimplemented(&self, db: &'db dyn Db) -> bool {
+ pub(crate) fn is_notimplemented(&self, db: &'db dyn Db) -> bool {
self.into_nominal_instance().is_some_and(|instance| {
instance
.class(db)
@@ -678,16 +677,16 @@ impl<'db> Type<'db> {
})
}
- pub fn is_object(&self, db: &'db dyn Db) -> bool {
+ pub(crate) fn is_object(&self, db: &'db dyn Db) -> bool {
self.into_nominal_instance()
.is_some_and(|instance| instance.is_object(db))
}
- pub const fn is_todo(&self) -> bool {
+ pub(crate) const fn is_todo(&self) -> bool {
matches!(self, Type::Dynamic(DynamicType::Todo(_)))
}
- pub const fn is_generic_alias(&self) -> bool {
+ pub(crate) const fn is_generic_alias(&self) -> bool {
matches!(self, Type::GenericAlias(_))
}
@@ -843,43 +842,38 @@ impl<'db> Type<'db> {
}
}
- pub const fn into_class_literal(self) -> Option> {
+ pub(crate) const fn into_class_literal(self) -> Option> {
match self {
Type::ClassLiteral(class_type) => Some(class_type),
_ => None,
}
}
- pub const fn into_subclass_of(self) -> Option> {
- match self {
- Type::SubclassOf(subclass_of) => Some(subclass_of),
- _ => None,
- }
- }
-
#[track_caller]
- pub fn expect_class_literal(self) -> ClassLiteral<'db> {
+ pub(crate) fn expect_class_literal(self) -> ClassLiteral<'db> {
self.into_class_literal()
.expect("Expected a Type::ClassLiteral variant")
}
- pub const fn is_subclass_of(&self) -> bool {
+ pub(crate) const fn is_subclass_of(&self) -> bool {
matches!(self, Type::SubclassOf(..))
}
- pub const fn is_class_literal(&self) -> bool {
+ #[cfg(test)]
+ pub(crate) const fn is_class_literal(&self) -> bool {
matches!(self, Type::ClassLiteral(..))
}
- pub fn into_enum_literal(self) -> Option> {
+ pub(crate) fn into_enum_literal(self) -> Option> {
match self {
Type::EnumLiteral(enum_literal) => Some(enum_literal),
_ => None,
}
}
+ #[cfg(test)]
#[track_caller]
- pub fn expect_enum_literal(self) -> EnumLiteralType<'db> {
+ pub(crate) fn expect_enum_literal(self) -> EnumLiteralType<'db> {
self.into_enum_literal()
.expect("Expected a Type::EnumLiteral variant")
}
@@ -898,7 +892,7 @@ impl<'db> Type<'db> {
/// Turn a class literal (`Type::ClassLiteral` or `Type::GenericAlias`) into a `ClassType`.
/// Since a `ClassType` must be specialized, apply the default specialization to any
/// unspecialized generic class literal.
- pub fn to_class_type(self, db: &'db dyn Db) -> Option> {
+ pub(crate) fn to_class_type(self, db: &'db dyn Db) -> Option> {
match self {
Type::ClassLiteral(class_literal) => Some(class_literal.default_specialization(db)),
Type::GenericAlias(alias) => Some(ClassType::Generic(alias)),
@@ -906,25 +900,15 @@ impl<'db> Type<'db> {
}
}
- #[track_caller]
- pub fn expect_class_type(self, db: &'db dyn Db) -> ClassType<'db> {
- self.to_class_type(db)
- .expect("Expected a Type::GenericAlias or Type::ClassLiteral variant")
- }
-
- pub fn is_class_type(&self, db: &'db dyn Db) -> bool {
- match self {
- Type::ClassLiteral(class) if class.generic_context(db).is_none() => true,
- Type::GenericAlias(_) => true,
- _ => false,
- }
- }
-
pub const fn is_property_instance(&self) -> bool {
matches!(self, Type::PropertyInstance(..))
}
- pub fn module_literal(db: &'db dyn Db, importing_file: File, submodule: Module<'db>) -> Self {
+ pub(crate) fn module_literal(
+ db: &'db dyn Db,
+ importing_file: File,
+ submodule: Module<'db>,
+ ) -> Self {
Self::ModuleLiteral(ModuleLiteralType::new(
db,
submodule,
@@ -932,70 +916,50 @@ impl<'db> Type<'db> {
))
}
- pub const fn into_module_literal(self) -> Option> {
+ pub(crate) const fn into_module_literal(self) -> Option> {
match self {
Type::ModuleLiteral(module) => Some(module),
_ => None,
}
}
- #[track_caller]
- pub fn expect_module_literal(self) -> ModuleLiteralType<'db> {
- self.into_module_literal()
- .expect("Expected a Type::ModuleLiteral variant")
- }
-
- pub const fn into_union(self) -> Option> {
+ pub(crate) const fn into_union(self) -> Option> {
match self {
Type::Union(union_type) => Some(union_type),
_ => None,
}
}
+ #[cfg(test)]
#[track_caller]
- pub fn expect_union(self) -> UnionType<'db> {
+ pub(crate) fn expect_union(self) -> UnionType<'db> {
self.into_union().expect("Expected a Type::Union variant")
}
- pub const fn is_union(&self) -> bool {
- matches!(self, Type::Union(..))
- }
-
- pub const fn into_intersection(self) -> Option> {
- match self {
- Type::Intersection(intersection_type) => Some(intersection_type),
- _ => None,
- }
- }
-
- #[track_caller]
- pub fn expect_intersection(self) -> IntersectionType<'db> {
- self.into_intersection()
- .expect("Expected a Type::Intersection variant")
- }
-
- pub const fn into_function_literal(self) -> Option> {
+ pub(crate) const fn into_function_literal(self) -> Option> {
match self {
Type::FunctionLiteral(function_type) => Some(function_type),
_ => None,
}
}
+ #[cfg(test)]
#[track_caller]
- pub fn expect_function_literal(self) -> FunctionType<'db> {
+ pub(crate) fn expect_function_literal(self) -> FunctionType<'db> {
self.into_function_literal()
.expect("Expected a Type::FunctionLiteral variant")
}
- pub const fn is_function_literal(&self) -> bool {
+ #[cfg(test)]
+ pub(crate) const fn is_function_literal(&self) -> bool {
matches!(self, Type::FunctionLiteral(..))
}
- pub const fn is_bound_method(&self) -> bool {
+ pub(crate) const fn is_bound_method(&self) -> bool {
matches!(self, Type::BoundMethod(..))
}
- pub fn is_union_of_single_valued(&self, db: &'db dyn Db) -> bool {
+ pub(crate) fn is_union_of_single_valued(&self, db: &'db dyn Db) -> bool {
self.into_union().is_some_and(|union| {
union
.elements(db)
@@ -1005,43 +969,22 @@ impl<'db> Type<'db> {
|| self.is_literal_string()
}
- pub const fn into_int_literal(self) -> Option {
- match self {
- Type::IntLiteral(value) => Some(value),
- _ => None,
- }
- }
-
- pub fn into_string_literal(self) -> Option> {
+ pub(crate) fn into_string_literal(self) -> Option> {
match self {
Type::StringLiteral(string_literal) => Some(string_literal),
_ => None,
}
}
- pub fn is_string_literal(&self) -> bool {
- matches!(self, Type::StringLiteral(..))
- }
-
- #[track_caller]
- pub fn expect_int_literal(self) -> i64 {
- self.into_int_literal()
- .expect("Expected a Type::IntLiteral variant")
- }
-
- pub const fn is_boolean_literal(&self) -> bool {
- matches!(self, Type::BooleanLiteral(..))
- }
-
- pub const fn is_literal_string(&self) -> bool {
+ pub(crate) const fn is_literal_string(&self) -> bool {
matches!(self, Type::LiteralString)
}
- pub fn string_literal(db: &'db dyn Db, string: &str) -> Self {
+ pub(crate) fn string_literal(db: &'db dyn Db, string: &str) -> Self {
Self::StringLiteral(StringLiteralType::new(db, string))
}
- pub fn bytes_literal(db: &'db dyn Db, bytes: &[u8]) -> Self {
+ pub(crate) fn bytes_literal(db: &'db dyn Db, bytes: &[u8]) -> Self {
Self::BytesLiteral(BytesLiteralType::new(db, bytes))
}
@@ -1052,18 +995,18 @@ impl<'db> Type<'db> {
}
#[must_use]
- pub fn negate(&self, db: &'db dyn Db) -> Type<'db> {
+ pub(crate) fn negate(&self, db: &'db dyn Db) -> Type<'db> {
IntersectionBuilder::new(db).add_negative(*self).build()
}
#[must_use]
- pub fn negate_if(&self, db: &'db dyn Db, yes: bool) -> Type<'db> {
+ pub(crate) fn negate_if(&self, db: &'db dyn Db, yes: bool) -> Type<'db> {
if yes { self.negate(db) } else { *self }
}
/// Returns the fallback instance type that a literal is an instance of, or `None` if the type
/// is not a literal.
- pub fn literal_fallback_instance(self, db: &'db dyn Db) -> Option> {
+ pub(crate) fn literal_fallback_instance(self, db: &'db dyn Db) -> Option> {
// There are other literal types that could conceivable be included here: class literals
// falling back to `type[X]`, for instance. For now, there is not much rigorous thought put
// into what's included vs not; this is just an empirical choice that makes our ecosystem
@@ -1090,7 +1033,7 @@ impl<'db> Type<'db> {
/// *has* or *does not have* a default value is relevant to whether two `Callable` types are equivalent.
/// - Converts class-based protocols into synthesized protocols
#[must_use]
- pub fn normalized(self, db: &'db dyn Db) -> Self {
+ pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
self.normalized_impl(db, &TypeTransformer::default())
}
@@ -5323,11 +5266,11 @@ impl<'db> Type<'db> {
}
#[must_use]
- pub fn to_instance(&self, db: &'db dyn Db) -> Option> {
+ pub(crate) fn to_instance(self, db: &'db dyn Db) -> Option> {
match self {
- Type::Dynamic(_) | Type::Never => Some(*self),
+ Type::Dynamic(_) | Type::Never => Some(self),
Type::ClassLiteral(class) => Some(Type::instance(db, class.default_specialization(db))),
- Type::GenericAlias(alias) => Some(Type::instance(db, ClassType::from(*alias))),
+ Type::GenericAlias(alias) => Some(Type::instance(db, ClassType::from(alias))),
Type::SubclassOf(subclass_of_ty) => Some(subclass_of_ty.to_instance(db)),
Type::Union(union) => union.to_instance(db),
// If there is no bound or constraints on a typevar `T`, `T: object` implicitly, which
@@ -5684,7 +5627,7 @@ impl<'db> Type<'db> {
}
/// The type `NoneType` / `None`
- pub fn none(db: &'db dyn Db) -> Type<'db> {
+ pub(crate) fn none(db: &'db dyn Db) -> Type<'db> {
KnownClass::NoneType.to_instance(db)
}
@@ -5694,7 +5637,7 @@ impl<'db> Type<'db> {
/// Note: the return type of `type(obj)` is subtly different from this.
/// See `Self::dunder_class` for more details.
#[must_use]
- pub fn to_meta_type(&self, db: &'db dyn Db) -> Type<'db> {
+ pub(crate) fn to_meta_type(self, db: &'db dyn Db) -> Type<'db> {
match self {
Type::Never => Type::Never,
Type::NominalInstance(instance) => instance.to_meta_type(db),
@@ -5730,9 +5673,9 @@ impl<'db> Type<'db> {
Type::TypeVar(_) => KnownClass::Type.to_instance(db),
Type::ClassLiteral(class) => class.metaclass(db),
- Type::GenericAlias(alias) => ClassType::from(*alias).metaclass(db),
+ Type::GenericAlias(alias) => ClassType::from(alias).metaclass(db),
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
- SubclassOfInner::Dynamic(_) => *self,
+ SubclassOfInner::Dynamic(_) => self,
SubclassOfInner::Class(class) => SubclassOfType::from(
db,
SubclassOfInner::try_from_type(db, class.metaclass(db))
@@ -5741,7 +5684,7 @@ impl<'db> Type<'db> {
},
Type::StringLiteral(_) | Type::LiteralString => KnownClass::Str.to_class_literal(db),
- Type::Dynamic(dynamic) => SubclassOfType::from(db, SubclassOfInner::Dynamic(*dynamic)),
+ Type::Dynamic(dynamic) => SubclassOfType::from(db, SubclassOfInner::Dynamic(dynamic)),
// TODO intersections
Type::Intersection(_) => SubclassOfType::from(
db,
@@ -5762,7 +5705,7 @@ impl<'db> Type<'db> {
/// this returns `type[dict[str, object]]` instead, because inhabitants of a `TypedDict` are
/// instances of `dict` at runtime.
#[must_use]
- pub fn dunder_class(self, db: &'db dyn Db) -> Type<'db> {
+ pub(crate) fn dunder_class(self, db: &'db dyn Db) -> Type<'db> {
if self.is_typed_dict() {
return KnownClass::Dict
.to_specialized_class_type(db, [KnownClass::Str.to_instance(db), Type::object(db)])
@@ -5775,7 +5718,7 @@ impl<'db> Type<'db> {
}
#[must_use]
- pub fn apply_optional_specialization(
+ pub(crate) fn apply_optional_specialization(
self,
db: &'db dyn Db,
specialization: Option>,
@@ -5794,7 +5737,7 @@ impl<'db> Type<'db> {
/// different operation that is performed explicitly (via a subscript operation), or implicitly
/// via a call to the generic object.
#[salsa::tracked(heap_size=ruff_memory_usage::heap_size)]
- pub fn apply_specialization(
+ pub(crate) fn apply_specialization(
self,
db: &'db dyn Db,
specialization: Specialization<'db>,
@@ -6040,7 +5983,7 @@ impl<'db> Type<'db> {
}
Type::Union(union) => {
- for element in union.iter(db) {
+ for element in union.elements(db) {
element.find_legacy_typevars(db, binding_context, typevars);
}
}
@@ -6110,7 +6053,7 @@ impl<'db> Type<'db> {
/// When not available, this should fall back to the value of `[Type::repr]`.
/// Note: this method is used in the builtins `format`, `print`, `str.format` and `f-strings`.
#[must_use]
- pub fn str(&self, db: &'db dyn Db) -> Type<'db> {
+ pub(crate) fn str(&self, db: &'db dyn Db) -> Type<'db> {
match self {
Type::IntLiteral(_) | Type::BooleanLiteral(_) => self.repr(db),
Type::StringLiteral(_) | Type::LiteralString => *self,
@@ -6135,7 +6078,7 @@ impl<'db> Type<'db> {
/// Return the string representation of this type as it would be provided by the `__repr__`
/// method at runtime.
#[must_use]
- pub fn repr(&self, db: &'db dyn Db) -> Type<'db> {
+ pub(crate) fn repr(&self, db: &'db dyn Db) -> Type<'db> {
match self {
Type::IntLiteral(number) => Type::string_literal(db, &number.to_string()),
Type::BooleanLiteral(true) => Type::string_literal(db, "True"),
@@ -9112,8 +9055,8 @@ impl<'db> UnionType<'db> {
/// Apply a transformation function to all elements of the union,
/// and create a new union from the resulting set of types.
- pub fn map(
- &self,
+ pub(crate) fn map(
+ self,
db: &'db dyn Db,
transform_fn: impl FnMut(&Type<'db>) -> Type<'db>,
) -> Type<'db> {
@@ -9147,10 +9090,6 @@ impl<'db> UnionType<'db> {
Self::from_elements(db, self.elements(db).iter().filter(filter_fn))
}
- pub fn iter(&self, db: &'db dyn Db) -> Iter<'_, Type<'db>> {
- self.elements(db).iter()
- }
-
pub(crate) fn map_with_boundness(
self,
db: &'db dyn Db,
@@ -9373,7 +9312,7 @@ impl<'db> IntersectionType<'db> {
/// Returns an iterator over the positive elements of the intersection. If
/// there are no positive elements, returns a single `object` type.
- fn positive_elements_or_object(&self, db: &'db dyn Db) -> impl Iterator
- > {
+ fn positive_elements_or_object(self, db: &'db dyn Db) -> impl Iterator
- > {
if self.positive(db).is_empty() {
Either::Left(std::iter::once(Type::object(db)))
} else {
@@ -9466,11 +9405,11 @@ impl<'db> IntersectionType<'db> {
}
}
- pub fn iter_positive(&self, db: &'db dyn Db) -> impl Iterator
- > {
+ pub fn iter_positive(self, db: &'db dyn Db) -> impl Iterator
- > {
self.positive(db).iter().copied()
}
- pub fn has_one_element(&self, db: &'db dyn Db) -> bool {
+ pub(crate) fn has_one_element(self, db: &'db dyn Db) -> bool {
(self.positive(db).len() + self.negative(db).len()) == 1
}
@@ -9550,7 +9489,7 @@ pub struct EnumLiteralType<'db> {
impl get_size2::GetSize for EnumLiteralType<'_> {}
impl<'db> EnumLiteralType<'db> {
- pub fn enum_class_instance(self, db: &'db dyn Db) -> Type<'db> {
+ pub(crate) fn enum_class_instance(self, db: &'db dyn Db) -> Type<'db> {
self.enum_class(db).to_non_generic_instance(db)
}
}
@@ -9956,18 +9895,18 @@ fn walk_typeis_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
impl get_size2::GetSize for TypeIsType<'_> {}
impl<'db> TypeIsType<'db> {
- pub fn place_name(self, db: &'db dyn Db) -> Option {
+ pub(crate) fn place_name(self, db: &'db dyn Db) -> Option {
let (scope, place) = self.place_info(db)?;
let table = place_table(db, scope);
Some(format!("{}", table.place(place)))
}
- pub fn unbound(db: &'db dyn Db, ty: Type<'db>) -> Type<'db> {
+ pub(crate) fn unbound(db: &'db dyn Db, ty: Type<'db>) -> Type<'db> {
Type::TypeIs(Self::new(db, ty, None))
}
- pub fn bound(
+ pub(crate) fn bound(
db: &'db dyn Db,
return_type: Type<'db>,
scope: ScopeId<'db>,
@@ -9977,22 +9916,23 @@ impl<'db> TypeIsType<'db> {
}
#[must_use]
- pub fn bind(self, db: &'db dyn Db, scope: ScopeId<'db>, place: ScopedPlaceId) -> Type<'db> {
+ pub(crate) fn bind(
+ self,
+ db: &'db dyn Db,
+ scope: ScopeId<'db>,
+ place: ScopedPlaceId,
+ ) -> Type<'db> {
Self::bound(db, self.return_type(db), scope, place)
}
#[must_use]
- pub fn with_type(self, db: &'db dyn Db, ty: Type<'db>) -> Type<'db> {
+ pub(crate) fn with_type(self, db: &'db dyn Db, ty: Type<'db>) -> Type<'db> {
Type::TypeIs(Self::new(db, ty, self.place_info(db)))
}
- pub fn is_bound(&self, db: &'db dyn Db) -> bool {
+ pub(crate) fn is_bound(self, db: &'db dyn Db) -> bool {
self.place_info(db).is_some()
}
-
- pub fn is_unbound(&self, db: &'db dyn Db) -> bool {
- self.place_info(db).is_none()
- }
}
// Make sure that the `Type` enum does not grow unexpectedly.
diff --git a/crates/ty_python_semantic/src/types/call/arguments.rs b/crates/ty_python_semantic/src/types/call/arguments.rs
index 0da96bcf4874c..b200f3fc8af14 100644
--- a/crates/ty_python_semantic/src/types/call/arguments.rs
+++ b/crates/ty_python_semantic/src/types/call/arguments.rs
@@ -257,7 +257,7 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option>> {
None
}
- Type::Union(union) => Some(union.iter(db).copied().collect()),
+ Type::Union(union) => Some(union.elements(db).to_vec()),
// We don't handle `type[A | B]` here because it's already stored in the expanded form
// i.e., `type[A] | type[B]` which is handled by the `Type::Union` case.
_ => None,
diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs
index 8b628fd375528..e0619e8343698 100644
--- a/crates/ty_python_semantic/src/types/generics.rs
+++ b/crates/ty_python_semantic/src/types/generics.rs
@@ -221,7 +221,7 @@ impl<'db> GenericContext<'db> {
// TODO: This should be a new type variant where only these exact types are
// assignable, and not subclasses of them, nor a union of them.
parameter = parameter
- .with_annotated_type(UnionType::from_elements(db, constraints.iter(db)));
+ .with_annotated_type(UnionType::from_elements(db, constraints.elements(db)));
}
None => {}
}
@@ -816,10 +816,11 @@ impl<'db> SpecializationBuilder<'db> {
// and add a mapping between that typevar and the actual type. (Note that we've
// already handled above the case where the actual is assignable to a _non-typevar_
// union element.)
- let mut bound_typevars = formal.iter(self.db).filter_map(|ty| match ty {
- Type::TypeVar(bound_typevar) => Some(*bound_typevar),
- _ => None,
- });
+ let mut bound_typevars =
+ formal.elements(self.db).iter().filter_map(|ty| match ty {
+ Type::TypeVar(bound_typevar) => Some(*bound_typevar),
+ _ => None,
+ });
let bound_typevar = bound_typevars.next();
let additional_bound_typevars = bound_typevars.next();
if let (Some(bound_typevar), None) = (bound_typevar, additional_bound_typevars) {
@@ -849,7 +850,7 @@ impl<'db> SpecializationBuilder<'db> {
self.add_type_mapping(bound_typevar, ty);
}
Some(TypeVarBoundOrConstraints::Constraints(constraints)) => {
- for constraint in constraints.iter(self.db) {
+ for constraint in constraints.elements(self.db) {
if ty.is_assignable_to(self.db, *constraint) {
self.add_type_mapping(bound_typevar, *constraint);
return Ok(());
From 47d44e5f7b158e6f9d1c438b50635d190fcb044c Mon Sep 17 00:00:00 2001
From: gkowzan
Date: Mon, 18 Aug 2025 01:35:37 +0200
Subject: [PATCH 020/160] Fix description of global config file discovery
strategy (#19143) (#19188)
Contrary to docs, ruff uses etcetera's base strategy rather than the
native strategy.
---
docs/configuration.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/configuration.md b/docs/configuration.md
index 533c04c71dcd8..0b79a20de9437 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -270,7 +270,7 @@ There are a few exceptions to these rules:
1. If no config file is found in the filesystem hierarchy, Ruff will fall back to using
a default configuration. If a user-specific configuration file exists
at `${config_dir}/ruff/pyproject.toml`, that file will be used instead of the default
- configuration, with `${config_dir}` being determined via [`etcetera`'s native strategy](https://docs.rs/etcetera/latest/etcetera/#native-strategy),
+ configuration, with `${config_dir}` being determined via [`etcetera`'s base strategy](https://docs.rs/etcetera/latest/etcetera/#native-strategy),
and all relative paths being again resolved relative to the _current working directory_.
1. Any config-file-supported settings that are provided on the command-line (e.g., via
`--select`) will override the settings in _every_ resolved configuration file.
From 510a07dee2a10510d89342988e0cd5d091892e66 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Aug 2025 08:44:00 +0200
Subject: [PATCH 021/160] Update PyO3/maturin-action action to v1.49.4 (#19955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
.github/workflows/build-binaries.yml | 16 ++++++++--------
.github/workflows/ci.yaml | 2 +-
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/build-binaries.yml b/.github/workflows/build-binaries.yml
index 8b8d9d128e447..573513079994e 100644
--- a/.github/workflows/build-binaries.yml
+++ b/.github/workflows/build-binaries.yml
@@ -49,7 +49,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build sdist"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
command: sdist
args: --out dist
@@ -79,7 +79,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels - x86_64"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: x86_64
args: --release --locked --out dist
@@ -121,7 +121,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels - aarch64"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: aarch64
args: --release --locked --out dist
@@ -177,7 +177,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.platform.target }}
args: --release --locked --out dist
@@ -230,7 +230,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.target }}
manylinux: auto
@@ -306,7 +306,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.platform.target }}
manylinux: auto
@@ -372,7 +372,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.target }}
manylinux: musllinux_1_2
@@ -437,7 +437,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
target: ${{ matrix.platform.target }}
manylinux: musllinux_1_2
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index aa6e5646b1852..9ac4c7b62b59e 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -715,7 +715,7 @@ jobs:
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
- uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
+ uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
args: --out dist
- name: "Test wheel"
From 48772c04d7186ffbbf4b4a1989d476f596c5ee57 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Aug 2025 08:53:10 +0200
Subject: [PATCH 022/160] Update Rust crate anyhow to v1.0.99 (#19956)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 9ae86d5acf69b..fd12c083cf402 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,9 +128,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.98"
+version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
[[package]]
name = "approx"
From a5339a52c3d308ae72335861c5b7839a29ade37e Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Aug 2025 08:53:31 +0200
Subject: [PATCH 023/160] Update Rust crate libc to v0.2.175 (#19960)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index fd12c083cf402..dfe07fe717e03 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1764,9 +1764,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
-version = "0.2.174"
+version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
+checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libcst"
From c8d155b2b91cd5cdb5610dd139f1ce589f65a63c Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Aug 2025 08:53:51 +0200
Subject: [PATCH 024/160] Update Rust crate clap to v4.5.45 (#19958)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
Cargo.lock | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index dfe07fe717e03..504a42c17337a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -408,9 +408,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.43"
+version = "4.5.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f"
+checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
dependencies = [
"clap_builder",
"clap_derive",
@@ -418,9 +418,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.43"
+version = "4.5.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65"
+checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
dependencies = [
"anstream",
"anstyle",
@@ -461,9 +461,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.41"
+version = "4.5.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
+checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
dependencies = [
"heck",
"proc-macro2",
From d423191d94d2c73faad7ab6a87eb62a2829f94a9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Aug 2025 08:54:09 +0200
Subject: [PATCH 025/160] Update Rust crate bitflags to v2.9.2 (#19957)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
Cargo.lock | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 504a42c17337a..e310958413383 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -257,9 +257,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.9.1"
+version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29"
[[package]]
name = "bitvec"
@@ -1241,7 +1241,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"ignore",
"walkdir",
]
@@ -1521,7 +1521,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"inotify-sys",
"libc",
]
@@ -1809,7 +1809,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"libc",
"redox_syscall",
]
@@ -2014,7 +2014,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"cfg-if",
"cfg_aliases",
"libc",
@@ -2026,7 +2026,7 @@ version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"cfg-if",
"cfg_aliases",
"libc",
@@ -2054,7 +2054,7 @@ version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"fsevent-sys",
"inotify",
"kqueue",
@@ -2666,7 +2666,7 @@ version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
]
[[package]]
@@ -2749,7 +2749,7 @@ dependencies = [
"argfile",
"assert_fs",
"bincode 2.0.1",
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"cachedir",
"clap",
"clap_complete_command",
@@ -3000,7 +3000,7 @@ version = "0.12.9"
dependencies = [
"aho-corasick",
"anyhow",
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"clap",
"colored 3.0.0",
"fern",
@@ -3106,7 +3106,7 @@ name = "ruff_python_ast"
version = "0.0.0"
dependencies = [
"aho-corasick",
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"compact_str",
"get-size2",
"is-macro",
@@ -3194,7 +3194,7 @@ dependencies = [
name = "ruff_python_literal"
version = "0.0.0"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"itertools 0.14.0",
"ruff_python_ast",
"unic-ucd-category",
@@ -3205,7 +3205,7 @@ name = "ruff_python_parser"
version = "0.0.0"
dependencies = [
"anyhow",
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"bstr",
"compact_str",
"get-size2",
@@ -3230,7 +3230,7 @@ dependencies = [
name = "ruff_python_semantic"
version = "0.0.0"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"insta",
"is-macro",
"ruff_cache",
@@ -3251,7 +3251,7 @@ dependencies = [
name = "ruff_python_stdlib"
version = "0.0.0"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"unicode-ident",
]
@@ -3428,7 +3428,7 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"errno",
"libc",
"linux-raw-sys",
@@ -4238,7 +4238,7 @@ dependencies = [
name = "ty_ide"
version = "0.0.0"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"insta",
"itertools 0.14.0",
"regex",
@@ -4297,7 +4297,7 @@ name = "ty_python_semantic"
version = "0.0.0"
dependencies = [
"anyhow",
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"bitvec",
"camino",
"colored 3.0.0",
@@ -4350,7 +4350,7 @@ name = "ty_server"
version = "0.0.0"
dependencies = [
"anyhow",
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"crossbeam",
"dunce",
"insta",
@@ -4393,7 +4393,7 @@ name = "ty_test"
version = "0.0.0"
dependencies = [
"anyhow",
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
"camino",
"colored 3.0.0",
"insta",
@@ -5143,7 +5143,7 @@ version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
- "bitflags 2.9.1",
+ "bitflags 2.9.2",
]
[[package]]
From 76c933d10ea1ae01d9d21444d585d87872307fbe Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Aug 2025 08:54:23 +0200
Subject: [PATCH 026/160] Update dependency ruff to v0.12.9 (#19954)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
docs/requirements-insiders.txt | 2 +-
docs/requirements.txt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/requirements-insiders.txt b/docs/requirements-insiders.txt
index e0c9c0272a2f1..3da4b69557420 100644
--- a/docs/requirements-insiders.txt
+++ b/docs/requirements-insiders.txt
@@ -1,5 +1,5 @@
PyYAML==6.0.2
-ruff==0.12.8
+ruff==0.12.9
mkdocs==1.6.1
mkdocs-material @ git+ssh://git@github.com/astral-sh/mkdocs-material-insiders.git@39da7a5e761410349e9a1b8abf593b0cdd5453ff
mkdocs-redirects==1.2.2
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 88c24df27949e..baf3c32b4fe48 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,5 +1,5 @@
PyYAML==6.0.2
-ruff==0.12.8
+ruff==0.12.9
mkdocs==1.6.1
mkdocs-material==9.5.38
mkdocs-redirects==1.2.2
From 7d8f7c20da394cf9590953c9311d3c5e03743956 Mon Sep 17 00:00:00 2001
From: Micha Reiser
Date: Mon, 18 Aug 2025 09:16:53 +0200
Subject: [PATCH 027/160] [ty] Log server version at info level (#19961)
---
crates/ty_server/src/server.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crates/ty_server/src/server.rs b/crates/ty_server/src/server.rs
index 5819789fe517c..46ee9c210d4db 100644
--- a/crates/ty_server/src/server.rs
+++ b/crates/ty_server/src/server.rs
@@ -80,7 +80,7 @@ impl Server {
);
let version = ruff_db::program_version().unwrap_or("Unknown");
- tracing::debug!("Version: {version}");
+ tracing::info!("Version: {version}");
connection.initialize_finish(
id,
From c7af595fc13c99e1f68ed18f4d0fd0647cf953cc Mon Sep 17 00:00:00 2001
From: Micha Reiser
Date: Mon, 18 Aug 2025 09:20:49 +0200
Subject: [PATCH 028/160] [ty] Use debug builds for conformance tests and run
them single threaded (#19938)
---
.github/workflows/typing_conformance.yaml | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/typing_conformance.yaml b/.github/workflows/typing_conformance.yaml
index 8f76462173d03..660163fea738e 100644
--- a/.github/workflows/typing_conformance.yaml
+++ b/.github/workflows/typing_conformance.yaml
@@ -54,6 +54,9 @@ jobs:
- name: Compute diagnostic diff
shell: bash
+ env:
+ # TODO: Remove this once we fixed the remaining panics in the conformance suite.
+ TY_MAX_PARALLELISM: 1
run: |
RUFF_DIR="$GITHUB_WORKSPACE/ruff"
@@ -63,15 +66,15 @@ jobs:
echo "new commit"
git rev-list --format=%s --max-count=1 "$GITHUB_SHA"
- cargo build --release --bin ty
- mv target/release/ty ty-new
+ cargo build --bin ty
+ mv target/debug/ty ty-new
MERGE_BASE="$(git merge-base "$GITHUB_SHA" "origin/$GITHUB_BASE_REF")"
git checkout -b old_commit "$MERGE_BASE"
echo "old commit (merge base)"
git rev-list --format=%s --max-count=1 old_commit
- cargo build --release --bin ty
- mv target/release/ty ty-old
+ cargo build --bin ty
+ mv target/debug/ty ty-old
)
(
From 083bb85d9dc3cd13a2d1dd8bff0cc2c1df6be315 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Mon, 18 Aug 2025 07:31:07 +0000
Subject: [PATCH 029/160] Update actions/checkout to v5.0.0 (#19952)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Micha Reiser
---
.github/workflows/release.yml | 8 ++++----
dist-workspace.toml | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1ae4d8fb71d77..218f07b9a8d19 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -61,7 +61,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- - uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
persist-credentials: false
submodules: recursive
@@ -124,7 +124,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
steps:
- - uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
persist-credentials: false
submodules: recursive
@@ -175,7 +175,7 @@ jobs:
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
- - uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
persist-credentials: false
submodules: recursive
@@ -251,7 +251,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- - uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
persist-credentials: false
submodules: recursive
diff --git a/dist-workspace.toml b/dist-workspace.toml
index 499bbd0766e52..ebbf36ab20626 100644
--- a/dist-workspace.toml
+++ b/dist-workspace.toml
@@ -70,7 +70,7 @@ install-path = ["$XDG_BIN_HOME/", "$XDG_DATA_HOME/../bin", "~/.local/bin"]
global = "depot-ubuntu-latest-4"
[dist.github-action-commits]
-"actions/checkout" = "09d2acae674a48949e3602304ab46fd20ae0c42f" # v4
+"actions/checkout" = "08c6903cd8c0fde910a37f88322edcfb5dd907a8" # v5.0.0
"actions/upload-artifact" = "6027e3dd177782cd8ab9af838c04fd81a07f1d47" # v4.6.2
"actions/download-artifact" = "634f93cb2916e3fdff6788551b99b062d0335ce0" # v5.0.0
"actions/attest-build-provenance" = "c074443f1aee8d4aeeae555aebba3282517141b2" #v2.2.3
From 4ac2b2c22283c9f8eb7f7fd945ab1c5f08098ab4 Mon Sep 17 00:00:00 2001
From: Alex Waygood
Date: Mon, 18 Aug 2025 11:30:52 +0100
Subject: [PATCH 030/160] [ty] Have `SemanticIndex::place_table()` and
`SemanticIndex::use_def_map` return references (#19944)
---
.../ty_python_semantic/src/semantic_index.rs | 56 +++++++++----------
.../src/types/ide_support.rs | 15 ++---
crates/ty_python_semantic/src/types/infer.rs | 39 ++++++-------
3 files changed, 52 insertions(+), 58 deletions(-)
diff --git a/crates/ty_python_semantic/src/semantic_index.rs b/crates/ty_python_semantic/src/semantic_index.rs
index 71ab64f736a5a..2c770ee0a67b2 100644
--- a/crates/ty_python_semantic/src/semantic_index.rs
+++ b/crates/ty_python_semantic/src/semantic_index.rs
@@ -70,8 +70,7 @@ pub(crate) fn place_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc SemanticIndex<'db> {
/// Use the Salsa cached [`place_table()`] query if you only need the
/// place table for a single scope.
#[track_caller]
- pub(super) fn place_table(&self, scope_id: FileScopeId) -> Arc {
- self.place_tables[scope_id].clone()
+ pub(super) fn place_table(&self, scope_id: FileScopeId) -> &PlaceTable {
+ &self.place_tables[scope_id]
}
/// Returns the use-def map for a specific scope.
@@ -261,8 +259,8 @@ impl<'db> SemanticIndex<'db> {
/// Use the Salsa cached [`use_def_map()`] query if you only need the
/// use-def map for a single scope.
#[track_caller]
- pub(super) fn use_def_map(&self, scope_id: FileScopeId) -> Arc> {
- self.use_def_maps[scope_id].clone()
+ pub(super) fn use_def_map(&self, scope_id: FileScopeId) -> &UseDefMap<'db> {
+ &self.use_def_maps[scope_id]
}
#[track_caller]
@@ -907,7 +905,7 @@ y = 2
);
let class_table = index.place_table(class_scope_id);
- assert_eq!(names(&class_table), vec!["x"]);
+ assert_eq!(names(class_table), vec!["x"]);
let use_def = index.use_def_map(class_scope_id);
let binding = use_def
@@ -929,7 +927,7 @@ y = 2
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["func", "y"]);
+ assert_eq!(names(global_table), vec!["func", "y"]);
let [(function_scope_id, function_scope)] = index
.child_scopes(FileScopeId::global())
@@ -944,7 +942,7 @@ y = 2
);
let function_table = index.place_table(function_scope_id);
- assert_eq!(names(&function_table), vec!["x"]);
+ assert_eq!(names(function_table), vec!["x"]);
let use_def = index.use_def_map(function_scope_id);
let binding = use_def
@@ -976,7 +974,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
let function_table = index.place_table(function_scope_id);
assert_eq!(
- names(&function_table),
+ names(function_table),
vec!["a", "b", "c", "d", "args", "kwargs"],
);
@@ -1021,7 +1019,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
let lambda_table = index.place_table(lambda_scope_id);
assert_eq!(
- names(&lambda_table),
+ names(lambda_table),
vec!["a", "b", "c", "d", "args", "kwargs"],
);
@@ -1062,7 +1060,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["iter1"]);
+ assert_eq!(names(global_table), vec!["iter1"]);
let [(comprehension_scope_id, comprehension_scope)] = index
.child_scopes(FileScopeId::global())
@@ -1081,7 +1079,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
let comprehension_symbol_table = index.place_table(comprehension_scope_id);
- assert_eq!(names(&comprehension_symbol_table), vec!["x", "y"]);
+ assert_eq!(names(comprehension_symbol_table), vec!["x", "y"]);
let use_def = index.use_def_map(comprehension_scope_id);
for name in ["x", "y"] {
@@ -1159,7 +1157,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["iter1"]);
+ assert_eq!(names(global_table), vec!["iter1"]);
let [(comprehension_scope_id, comprehension_scope)] = index
.child_scopes(FileScopeId::global())
@@ -1178,7 +1176,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
let comprehension_symbol_table = index.place_table(comprehension_scope_id);
- assert_eq!(names(&comprehension_symbol_table), vec!["y", "iter2"]);
+ assert_eq!(names(comprehension_symbol_table), vec!["y", "iter2"]);
let [(inner_comprehension_scope_id, inner_comprehension_scope)] = index
.child_scopes(comprehension_scope_id)
@@ -1197,7 +1195,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
let inner_comprehension_symbol_table = index.place_table(inner_comprehension_scope_id);
- assert_eq!(names(&inner_comprehension_symbol_table), vec!["x"]);
+ assert_eq!(names(inner_comprehension_symbol_table), vec!["x"]);
}
#[test]
@@ -1212,7 +1210,7 @@ with item1 as x, item2 as y:
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["item1", "x", "item2", "y"]);
+ assert_eq!(names(global_table), vec!["item1", "x", "item2", "y"]);
let use_def = index.use_def_map(FileScopeId::global());
for name in ["x", "y"] {
@@ -1235,7 +1233,7 @@ with context() as (x, y):
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["context", "x", "y"]);
+ assert_eq!(names(global_table), vec!["context", "x", "y"]);
let use_def = index.use_def_map(FileScopeId::global());
for name in ["x", "y"] {
@@ -1260,7 +1258,7 @@ def func():
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["func"]);
+ assert_eq!(names(global_table), vec!["func"]);
let [
(func_scope1_id, func_scope_1),
(func_scope2_id, func_scope_2),
@@ -1285,8 +1283,8 @@ def func():
let func1_table = index.place_table(func_scope1_id);
let func2_table = index.place_table(func_scope2_id);
- assert_eq!(names(&func1_table), vec!["x"]);
- assert_eq!(names(&func2_table), vec!["y"]);
+ assert_eq!(names(func1_table), vec!["x"]);
+ assert_eq!(names(func2_table), vec!["y"]);
let use_def = index.use_def_map(FileScopeId::global());
let binding = use_def
@@ -1308,7 +1306,7 @@ def func[T]():
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["func"]);
+ assert_eq!(names(global_table), vec!["func"]);
let [(ann_scope_id, ann_scope)] = index
.child_scopes(FileScopeId::global())
@@ -1323,7 +1321,7 @@ def func[T]():
"func"
);
let ann_table = index.place_table(ann_scope_id);
- assert_eq!(names(&ann_table), vec!["T"]);
+ assert_eq!(names(ann_table), vec!["T"]);
let [(func_scope_id, func_scope)] =
index.child_scopes(ann_scope_id).collect::>()[..]
@@ -1336,7 +1334,7 @@ def func[T]():
"func"
);
let func_table = index.place_table(func_scope_id);
- assert_eq!(names(&func_table), vec!["x"]);
+ assert_eq!(names(func_table), vec!["x"]);
}
#[test]
@@ -1352,7 +1350,7 @@ class C[T]:
let index = semantic_index(&db, file);
let global_table = index.place_table(FileScopeId::global());
- assert_eq!(names(&global_table), vec!["C"]);
+ assert_eq!(names(global_table), vec!["C"]);
let [(ann_scope_id, ann_scope)] = index
.child_scopes(FileScopeId::global())
@@ -1364,7 +1362,7 @@ class C[T]:
assert_eq!(ann_scope.kind(), ScopeKind::TypeParams);
assert_eq!(ann_scope_id.to_scope_id(&db, file).name(&db, &module), "C");
let ann_table = index.place_table(ann_scope_id);
- assert_eq!(names(&ann_table), vec!["T"]);
+ assert_eq!(names(ann_table), vec!["T"]);
assert!(
ann_table
.symbol_by_name("T")
@@ -1383,7 +1381,7 @@ class C[T]:
class_scope_id.to_scope_id(&db, file).name(&db, &module),
"C"
);
- assert_eq!(names(&index.place_table(class_scope_id)), vec!["x"]);
+ assert_eq!(names(index.place_table(class_scope_id)), vec!["x"]);
}
#[test]
diff --git a/crates/ty_python_semantic/src/types/ide_support.rs b/crates/ty_python_semantic/src/types/ide_support.rs
index 36a139145c301..f96401bd2f862 100644
--- a/crates/ty_python_semantic/src/types/ide_support.rs
+++ b/crates/ty_python_semantic/src/types/ide_support.rs
@@ -307,8 +307,7 @@ impl<'db> AllMembers<'db> {
let file = class_body_scope.file(db);
let index = semantic_index(db, file);
for function_scope_id in attribute_scopes(db, class_body_scope) {
- let place_table = index.place_table(function_scope_id);
- for place_expr in place_table.members() {
+ for place_expr in index.place_table(function_scope_id).members() {
let Some(name) = place_expr.as_instance_attribute() else {
continue;
};
@@ -411,8 +410,9 @@ pub fn definition_kind_for_name<'db>(
let symbol_id = place_table.symbol_id(name_str)?;
// Get the use-def map and look up definitions for this place
- let use_def_map = index.use_def_map(file_scope);
- let declarations = use_def_map.all_reachable_symbol_declarations(symbol_id);
+ let declarations = index
+ .use_def_map(file_scope)
+ .all_reachable_symbol_declarations(symbol_id);
// Find the first valid definition and return its kind
for declaration in declarations {
@@ -662,9 +662,10 @@ pub fn definitions_for_attribute<'db>(
let index = semantic_index(db, file);
for function_scope_id in attribute_scopes(db, class_scope) {
- let place_table = index.place_table(function_scope_id);
-
- if let Some(place_id) = place_table.member_id_by_instance_attribute_name(name_str) {
+ if let Some(place_id) = index
+ .place_table(function_scope_id)
+ .member_id_by_instance_attribute_name(name_str)
+ {
let use_def = index.use_def_map(function_scope_id);
// Check declarations first
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index c819d1d3486e9..83c7212d25b14 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -1848,7 +1848,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let mut bound_ty = ty;
let global_use_def_map = self.index.use_def_map(FileScopeId::global());
- let nonlocal_use_def_map;
let place_id = binding.place(self.db());
let place = place_table.place(place_id);
@@ -1908,9 +1907,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}
// We found the closest definition. Note that (as in `infer_place_load`) this does
// *not* need to be a binding. It could be just a declaration, e.g. `x: int`.
- nonlocal_use_def_map = self.index.use_def_map(enclosing_scope_file_id);
- declarations =
- nonlocal_use_def_map.end_of_scope_symbol_declarations(enclosing_symbol_id);
+ declarations = self
+ .index
+ .use_def_map(enclosing_scope_file_id)
+ .end_of_scope_symbol_declarations(enclosing_symbol_id);
is_local = false;
break;
}
@@ -2107,8 +2107,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
.or_fall_back_to(self.db(), || {
// Fallback to bindings declared on `types.ModuleType` if it's a global symbol
let scope = self.scope().file_scope_id(self.db());
- let place_table = self.index.place_table(scope);
- let place = place_table.place(declaration.place(self.db()));
+ let place = self
+ .index
+ .place_table(scope)
+ .place(declaration.place(self.db()));
if let PlaceExprRef::Symbol(symbol) = &place {
if scope.is_global() {
module_type_implicit_global_symbol(self.db(), symbol.name())
@@ -2501,8 +2503,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
invalid.ty,
);
}
- let use_def = self.index.use_def_map(scope_id);
- if use_def.can_implicitly_return_none(self.db())
+ if self
+ .index
+ .use_def_map(scope_id)
+ .can_implicitly_return_none(self.db())
&& !Type::none(self.db()).is_assignable_to(self.db(), expected_ty)
{
let no_return = self.return_types_and_ranges.is_empty();
@@ -5169,20 +5173,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let module_ty = Type::module_literal(self.db(), self.file(), module);
- // The indirection of having `star_import_info` as a separate variable
- // is required in order to make the borrow checker happy.
- let star_import_info = definition
- .kind(self.db())
- .as_star_import()
- .map(|star_import| {
- let place_table = self
- .index
- .place_table(self.scope().file_scope_id(self.db()));
- (star_import, place_table)
- });
-
- let name = if let Some((star_import, symbol_table)) = star_import_info.as_ref() {
- symbol_table.symbol(star_import.symbol_id()).name()
+ let name = if let Some(star_import) = definition.kind(self.db()).as_star_import() {
+ self.index
+ .place_table(self.scope().file_scope_id(self.db()))
+ .symbol(star_import.symbol_id())
+ .name()
} else {
&alias.name.id
};
From 67529edad6452c1f6eb646c8e5f6fb88caf012ae Mon Sep 17 00:00:00 2001
From: Micha Reiser
Date: Mon, 18 Aug 2025 12:35:40 +0200
Subject: [PATCH 031/160] [ty] Short-circuit inlayhints request if disabled in
settings (#19963)
---
crates/ty_ide/src/inlay_hints.rs | 7 +++++++
crates/ty_server/src/server/api/requests/inlay_hints.rs | 8 ++++----
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/crates/ty_ide/src/inlay_hints.rs b/crates/ty_ide/src/inlay_hints.rs
index f9f109aa1dd53..1004f5b4d58aa 100644
--- a/crates/ty_ide/src/inlay_hints.rs
+++ b/crates/ty_ide/src/inlay_hints.rs
@@ -85,6 +85,13 @@ pub struct InlayHintSettings {
/// foo("x="1)
/// ```
pub call_argument_names: bool,
+ // Add any new setting that enables additional inlays to `any_enabled`.
+}
+
+impl InlayHintSettings {
+ pub fn any_enabled(&self) -> bool {
+ self.variable_types || self.call_argument_names
+ }
}
impl Default for InlayHintSettings {
diff --git a/crates/ty_server/src/server/api/requests/inlay_hints.rs b/crates/ty_server/src/server/api/requests/inlay_hints.rs
index 2d903d1a88fee..3c5e44d2644f2 100644
--- a/crates/ty_server/src/server/api/requests/inlay_hints.rs
+++ b/crates/ty_server/src/server/api/requests/inlay_hints.rs
@@ -29,9 +29,9 @@ impl BackgroundDocumentRequestHandler for InlayHintRequestHandler {
_client: &Client,
params: InlayHintParams,
) -> crate::server::Result