diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 51ee9bd072266..a69e50dfed4d1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,9 +26,9 @@ repos: hooks: - id: mdformat additional_dependencies: - - mdformat-mkdocs - - mdformat-admon - - mdformat-footnote + - mdformat-mkdocs<4.0.0 + - mdformat-admon==2.0.6 + - mdformat-footnote==0.1.1 exclude: | (?x)^( docs/formatter/black\.md @@ -59,7 +59,7 @@ repos: - black==24.10.0 - repo: https://github.com/crate-ci/typos - rev: v1.28.2 + rev: v1.28.3 hooks: - id: typos @@ -73,7 +73,7 @@ repos: pass_filenames: false # This makes it a lot faster - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.8.2 + rev: v0.8.3 hooks: - id: ruff-format - id: ruff diff --git a/Cargo.lock b/Cargo.lock index 40b862c96ab6a..07b4b3957f444 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -220,9 +220,9 @@ checksum = "7f839cdf7e2d3198ac6ca003fd8ebc61715755f41c1cad15ff13df67531e00ed" [[package]] name = "bstr" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" dependencies = [ "memchr", "regex-automata 0.4.8", @@ -314,9 +314,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -465,12 +465,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -923,9 +923,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fern" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ff9c9d5fb3e6da8ac2f77ab76fe7e8087d512ce095200f8f29ac5b656cf6dc" +checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29" dependencies = [ "log", ] @@ -1521,9 +1521,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libcst" @@ -2161,7 +2161,7 @@ dependencies = [ "newtype-uuid", "quick-xml", "strip-ansi-escapes", - "thiserror 2.0.6", + "thiserror 2.0.7", "uuid", ] @@ -2314,7 +2314,7 @@ dependencies = [ "static_assertions", "tempfile", "test-case", - "thiserror 2.0.6", + "thiserror 2.0.7", "tracing", ] @@ -2411,7 +2411,7 @@ dependencies = [ "rustc-hash 2.1.0", "salsa", "serde", - "thiserror 2.0.6", + "thiserror 2.0.7", "toml", "tracing", ] @@ -2564,7 +2564,7 @@ dependencies = [ "strum", "tempfile", "test-case", - "thiserror 2.0.6", + "thiserror 2.0.7", "tikv-jemallocator", "toml", "tracing", @@ -2634,7 +2634,7 @@ dependencies = [ "salsa", "serde", "tempfile", - "thiserror 2.0.6", + "thiserror 2.0.7", "tracing", "tracing-subscriber", "tracing-tree", @@ -2786,7 +2786,7 @@ dependencies = [ "strum", "strum_macros", "test-case", - "thiserror 2.0.6", + "thiserror 2.0.7", "toml", "typed-arena", "unicode-normalization", @@ -2820,7 +2820,7 @@ dependencies = [ "serde_json", "serde_with", "test-case", - "thiserror 2.0.6", + "thiserror 2.0.7", "uuid", ] @@ -2892,7 +2892,7 @@ dependencies = [ "similar", "smallvec", "static_assertions", - "thiserror 2.0.6", + "thiserror 2.0.7", "tracing", ] @@ -3025,7 +3025,7 @@ dependencies = [ "serde", "serde_json", "shellexpand", - "thiserror 2.0.6", + "thiserror 2.0.7", "tracing", "tracing-subscriber", ] @@ -3280,9 +3280,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -3300,9 +3300,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -3623,11 +3623,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" dependencies = [ - "thiserror-impl 2.0.6", + "thiserror-impl 2.0.7", ] [[package]] @@ -3643,9 +3643,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" dependencies = [ "proc-macro2", "quote", diff --git a/crates/red_knot_python_semantic/resources/mdtest/annotations/annotated.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/annotated.md index 6601eda871864..71b06a24f280b 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/annotations/annotated.md +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/annotated.md @@ -29,10 +29,24 @@ It is invalid to parameterize `Annotated` with less than two arguments. ```py from typing_extensions import Annotated -# TODO: This should be an error +# error: [invalid-type-form] "`Annotated` requires at least two arguments when used in an annotation or type expression" def _(x: Annotated): reveal_type(x) # revealed: Unknown +def _(flag: bool): + if flag: + X = Annotated + else: + X = bool + + # error: [invalid-type-form] "`Annotated` requires at least two arguments when used in an annotation or type expression" + def f(y: X): + reveal_type(y) # revealed: Unknown | bool + +# error: [invalid-type-form] "`Annotated` requires at least two arguments when used in an annotation or type expression" +def _(x: Annotated | bool): + reveal_type(x) # revealed: Unknown | bool + # error: [invalid-type-form] def _(x: Annotated[()]): reveal_type(x) # revealed: Unknown diff --git a/crates/red_knot_python_semantic/resources/mdtest/literal/literal.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/literal.md similarity index 91% rename from crates/red_knot_python_semantic/resources/mdtest/literal/literal.md rename to crates/red_knot_python_semantic/resources/mdtest/annotations/literal.md index 0f9acaf3b52e4..ca7fff5731133 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/literal/literal.md +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/literal.md @@ -91,3 +91,13 @@ a1: Literal[26] def f(): reveal_type(a1) # revealed: Literal[26] ``` + +## Invalid + +```py +from typing import Literal + +# error: [invalid-type-form] "`Literal` requires at least one argument when used in a type expression" +def _(x: Literal): + reveal_type(x) # revealed: Unknown +``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md b/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md index b029221bce7a1..a1a3daebd5030 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md +++ b/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md @@ -3,6 +3,6 @@ ```py import builtins -x = builtins.copyright -reveal_type(x) # revealed: Literal[copyright] +x = builtins.chr +reveal_type(x) # revealed: Literal[chr] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md b/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md index 7be6c7531b31c..fd51fb2318c6a 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md +++ b/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md @@ -10,10 +10,10 @@ def returns_bool() -> bool: return True if returns_bool(): - copyright = 1 + chr = 1 def f(): - reveal_type(copyright) # revealed: Literal[copyright] | Literal[1] + reveal_type(chr) # revealed: Literal[chr] | Literal[1] ``` ## Conditionally global or builtin, with annotation @@ -25,8 +25,8 @@ def returns_bool() -> bool: return True if returns_bool(): - copyright: int = 1 + chr: int = 1 def f(): - reveal_type(copyright) # revealed: Literal[copyright] | int + reveal_type(chr) # revealed: Literal[chr] | int ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_of/any.md b/crates/red_knot_python_semantic/resources/mdtest/type_of/dynamic.md similarity index 67% rename from crates/red_knot_python_semantic/resources/mdtest/type_of/any.md rename to crates/red_knot_python_semantic/resources/mdtest/type_of/dynamic.md index b04db115091c3..9bc257ddaee56 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_of/any.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_of/dynamic.md @@ -1,13 +1,20 @@ # `type[Any]` +This file contains tests for non-fully-static `type[]` types, such as `type[Any]` and +`type[Unknown]`. + ## Simple ```py -def f(x: type[Any]): +def f(x: type[Any], y: type[str]): reveal_type(x) # revealed: type[Any] # TODO: could be ` & Any` reveal_type(x.__repr__) # revealed: Any + # type[str] and type[Any] are assignable to each other + a: type[str] = x + b: type[Any] = y + class A: ... x: type[Any] = object @@ -70,3 +77,26 @@ def test(x: Any, y: SomethingUnknown): reveal_type(y.__class__) # revealed: type[Unknown] reveal_type(y.__class__.__class__.__class__.__class__) # revealed: type[Unknown] ``` + +## `type[Unknown]` has similar properties to `type[Any]` + +```py +import abc +from typing import Any +from does_not_exist import SomethingUnknown # error: [unresolved-import] + +has_unknown_type = SomethingUnknown.__class__ +reveal_type(has_unknown_type) # revealed: type[Unknown] + +def test(x: type[str], y: type[Any]): + """Both `type[Any]` and `type[Unknown]` are assignable to all `type[]` types""" + a: type[Any] = x + b: type[str] = y + c: type[Any] = has_unknown_type + d: type[str] = has_unknown_type + +def test2(a: type[Any]): + """`type[Any]` and `type[Unknown]` are also assignable to all instances of `type` subclasses""" + b: abc.ABCMeta = a + b: abc.ABCMeta = has_unknown_type +``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index c16bc7dc14b24..72db00d9bece8 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -28,7 +28,7 @@ use crate::stdlib::{ use crate::symbol::{Boundness, Symbol}; use crate::types::call::{CallDunderResult, CallOutcome}; use crate::types::class_base::ClassBase; -use crate::types::diagnostic::TypeCheckDiagnosticsBuilder; +use crate::types::diagnostic::{TypeCheckDiagnosticsBuilder, INVALID_TYPE_FORM}; use crate::types::mro::{Mro, MroError, MroIterator}; use crate::types::narrow::narrowing_constraint; use crate::{Db, FxOrderSet, Module, Program, PythonVersion}; @@ -769,34 +769,10 @@ impl<'db> Type<'db> { Type::subclass_of(class).is_subtype_of(db, target) } - // As the `unreachable!()` message says, non-fully-static `SubclassOf` types such as - // `type[Any]`,` type[Unknown]` and `type[Todo]` should all be handled right at the top of this function. - ( - Type::SubclassOf(SubclassOfType { - base: ClassBase::Any | ClassBase::Unknown | ClassBase::Todo(_), - }), - _, - ) - | ( - _, - Type::SubclassOf(SubclassOfType { - base: ClassBase::Any | ClassBase::Unknown | ClassBase::Todo(_), - }), - ) => unreachable!( - "Non-fully-static types should be handled at the top of this function!" - ), - - // For example, `type[bool]` describes all possible runtime subclasses of the class `bool`, - // and `type[int]` describes all possible runtime subclasses of the class `int`. - // The first set is a subset of the second set, because `bool` is itself a subclass of `int`. - ( - Type::SubclassOf(SubclassOfType { - base: ClassBase::Class(self_class), - }), - Type::SubclassOf(SubclassOfType { - base: ClassBase::Class(target_class), - }), - ) => self_class.is_subclass_of(db, target_class), + // This branch asks: given two types `type[T]` and `type[S]`, is `type[T]` a subtype of `type[S]`? + (Type::SubclassOf(self_subclass_ty), Type::SubclassOf(target_subclass_ty)) => { + self_subclass_ty.is_subtype_of(db, target_subclass_ty) + } // `type[str]` (== `SubclassOf("str")` in red-knot) describes all possible runtime subclasses // of the class object `str`. It is a subtype of `type` (== `Instance("type")`) because `str` @@ -878,26 +854,26 @@ impl<'db> Type<'db> { } ( Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), Type::SubclassOf(_), ) => true, ( Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), - Type::Instance(target), - ) if target.class.is_known(db, KnownClass::Type) => true, + Type::Instance(_), + ) if target.is_assignable_to(db, KnownClass::Type.to_instance(db)) => true, ( - Type::Instance(class), + Type::Instance(_), Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), - ) if class.class.is_known(db, KnownClass::Type) => true, + ) if self.is_assignable_to(db, KnownClass::Type.to_instance(db)) => true, ( Type::ClassLiteral(_) | Type::SubclassOf(_), Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), ) => true, // TODO other types containing gradual forms (e.g. generics containing Any/Unknown) @@ -1046,9 +1022,8 @@ impl<'db> Type<'db> { | Type::SliceLiteral(..) | Type::StringLiteral(..) | Type::LiteralString, - ) => true, - - ( + ) + | ( Type::ClassLiteral(..) | Type::ModuleLiteral(..) | Type::BooleanLiteral(..) @@ -1076,8 +1051,14 @@ impl<'db> Type<'db> { (Type::SubclassOf(_), Type::SubclassOf(_)) => false, - (Type::SubclassOf(_), Type::Instance(_)) | (Type::Instance(_), Type::SubclassOf(_)) => { - false + (Type::SubclassOf(_), Type::Instance(instance)) + | (Type::Instance(instance), Type::SubclassOf(_)) => { + // TODO this should be `true` if the instance is of a final type which is not a + // subclass of type. (With non-final types, we never know whether a subclass might + // multiply-inherit `type` or a subclass of it, and thus not be disjoint with + // `type[...]`.) Until we support finality, hardcode None, which is known to be + // final. + matches!(instance.class.known(db), Some(KnownClass::NoneType)) } ( @@ -1085,6 +1066,7 @@ impl<'db> Type<'db> { Type::BooleanLiteral(..) | Type::IntLiteral(..) | Type::StringLiteral(..) + | Type::LiteralString | Type::BytesLiteral(..) | Type::SliceLiteral(..) | Type::FunctionLiteral(..) @@ -1094,6 +1076,7 @@ impl<'db> Type<'db> { Type::BooleanLiteral(..) | Type::IntLiteral(..) | Type::StringLiteral(..) + | Type::LiteralString | Type::BytesLiteral(..) | Type::SliceLiteral(..) | Type::FunctionLiteral(..) @@ -1174,10 +1157,15 @@ impl<'db> Type<'db> { Some(KnownClass::Slice | KnownClass::Object) ), - (Type::ClassLiteral(..), Type::Instance(InstanceType { class })) - | (Type::Instance(InstanceType { class }), Type::ClassLiteral(..)) => { - !matches!(class.known(db), Some(KnownClass::Type | KnownClass::Object)) - } + ( + Type::ClassLiteral(ClassLiteralType { class: class_a }), + Type::Instance(InstanceType { class: class_b }), + ) + | ( + Type::Instance(InstanceType { class: class_b }), + Type::ClassLiteral(ClassLiteralType { class: class_a }), + ) => !class_a.is_instance_of(db, class_b), + (Type::FunctionLiteral(..), Type::Instance(InstanceType { class })) | (Type::Instance(InstanceType { class }), Type::FunctionLiteral(..)) => !matches!( class.known(db), @@ -1912,29 +1900,63 @@ impl<'db> Type<'db> { /// `Type::ClassLiteral(builtins.int)`, that is, it is the `int` class itself. As a type /// expression, it names the type `Type::Instance(builtins.int)`, that is, all objects whose /// `__class__` is `int`. - #[must_use] - pub fn in_type_expression(&self, db: &'db dyn Db) -> Type<'db> { + pub fn in_type_expression( + &self, + db: &'db dyn Db, + ) -> Result, InvalidTypeExpressionError<'db>> { match self { // In a type expression, a bare `type` is interpreted as "instance of `type`", which is // equivalent to `type[object]`. - Type::ClassLiteral(_) | Type::SubclassOf(_) => self.to_instance(db), + Type::ClassLiteral(_) | Type::SubclassOf(_) => Ok(self.to_instance(db)), // We treat `typing.Type` exactly the same as `builtins.type`: - Type::KnownInstance(KnownInstanceType::Type) => KnownClass::Type.to_instance(db), - Type::KnownInstance(KnownInstanceType::Tuple) => KnownClass::Tuple.to_instance(db), - Type::Union(union) => union.map(db, |element| element.in_type_expression(db)), - Type::Unknown => Type::Unknown, + Type::KnownInstance(KnownInstanceType::Type) => Ok(KnownClass::Type.to_instance(db)), + Type::KnownInstance(KnownInstanceType::Tuple) => Ok(KnownClass::Tuple.to_instance(db)), + Type::Union(union) => { + let mut builder = UnionBuilder::new(db); + let mut invalid_expressions = smallvec::SmallVec::default(); + for element in union.elements(db) { + match element.in_type_expression(db) { + Ok(type_expr) => builder = builder.add(type_expr), + Err(InvalidTypeExpressionError { + fallback_type, + invalid_expressions: new_invalid_expressions, + }) => { + invalid_expressions.extend(new_invalid_expressions); + builder = builder.add(fallback_type); + } + } + } + if invalid_expressions.is_empty() { + Ok(builder.build()) + } else { + Err(InvalidTypeExpressionError { + fallback_type: builder.build(), + invalid_expressions, + }) + } + } + Type::Unknown => Ok(Type::Unknown), // TODO map this to a new `Type::TypeVar` variant - Type::KnownInstance(KnownInstanceType::TypeVar(_)) => *self, - Type::KnownInstance(KnownInstanceType::TypeAliasType(alias)) => alias.value_ty(db), + Type::KnownInstance(KnownInstanceType::TypeVar(_)) => Ok(*self), + Type::KnownInstance(KnownInstanceType::TypeAliasType(alias)) => Ok(alias.value_ty(db)), Type::KnownInstance(KnownInstanceType::Never | KnownInstanceType::NoReturn) => { - Type::Never + Ok(Type::Never) } - Type::KnownInstance(KnownInstanceType::LiteralString) => Type::LiteralString, - Type::KnownInstance(KnownInstanceType::Any) => Type::Any, + Type::KnownInstance(KnownInstanceType::LiteralString) => Ok(Type::LiteralString), + Type::KnownInstance(KnownInstanceType::Any) => Ok(Type::Any), // TODO: Should emit a diagnostic - Type::KnownInstance(KnownInstanceType::Annotated) => Type::Unknown, - Type::Todo(_) => *self, - _ => todo_type!("Unsupported or invalid type in a type expression"), + Type::KnownInstance(KnownInstanceType::Annotated) => Err(InvalidTypeExpressionError { + invalid_expressions: smallvec::smallvec![InvalidTypeExpression::BareAnnotated], + fallback_type: Type::Unknown, + }), + Type::KnownInstance(KnownInstanceType::Literal) => Err(InvalidTypeExpressionError { + invalid_expressions: smallvec::smallvec![InvalidTypeExpression::BareLiteral], + fallback_type: Type::Unknown, + }), + Type::Todo(_) => Ok(*self), + _ => Ok(todo_type!( + "Unsupported or invalid type in a type expression" + )), } } @@ -2063,6 +2085,54 @@ impl<'db> From> for Symbol<'db> { } } +/// Error struct providing information on type(s) that were deemed to be invalid +/// in a type expression context, and the type we should therefore fallback to +/// for the problematic type expression. +#[derive(Debug, PartialEq, Eq)] +pub struct InvalidTypeExpressionError<'db> { + fallback_type: Type<'db>, + invalid_expressions: smallvec::SmallVec<[InvalidTypeExpression; 1]>, +} + +impl<'db> InvalidTypeExpressionError<'db> { + fn into_fallback_type( + self, + diagnostics: &mut TypeCheckDiagnosticsBuilder, + node: &ast::Expr, + ) -> Type<'db> { + let InvalidTypeExpressionError { + fallback_type, + invalid_expressions, + } = self; + for error in invalid_expressions { + diagnostics.add_lint( + &INVALID_TYPE_FORM, + node.into(), + format_args!("{}", error.reason()), + ); + } + fallback_type + } +} + +/// Enumeration of various types that are invalid in type-expression contexts +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum InvalidTypeExpression { + /// `x: Annotated` is invalid as an annotation + BareAnnotated, + /// `x: Literal` is invalid as an annotation + BareLiteral, +} + +impl InvalidTypeExpression { + const fn reason(self) -> &'static str { + match self { + Self::BareAnnotated => "`Annotated` requires at least two arguments when used in an annotation or type expression", + Self::BareLiteral => "`Literal` requires at least one argument when used in a type expression", + } + } +} + /// Non-exhaustive enumeration of known classes (e.g. `builtins.int`, `typing.Any`, ...) to allow /// for easier syntax when interacting with very common classes. /// @@ -3159,6 +3229,22 @@ impl<'db> SubclassOfType<'db> { fn member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> { Type::from(self.base).member(db, name) } + + fn is_subtype_of(self, db: &'db dyn Db, other: SubclassOfType<'db>) -> bool { + match (self.base, other.base) { + // Non-fully-static types do not participate in subtyping + (ClassBase::Any | ClassBase::Unknown | ClassBase::Todo(_), _) + | (_, ClassBase::Any | ClassBase::Unknown | ClassBase::Todo(_)) => false, + + // For example, `type[bool]` describes all possible runtime subclasses of the class `bool`, + // and `type[int]` describes all possible runtime subclasses of the class `int`. + // The first set is a subset of the second set, because `bool` is itself a subclass of `int`. + (ClassBase::Class(self_class), ClassBase::Class(other_class)) => { + // N.B. The subclass relation is fully static + self_class.is_subclass_of(db, other_class) + } + } + } } /// A type representing the set of runtime objects which are instances of a certain class. @@ -3169,6 +3255,7 @@ pub struct InstanceType<'db> { impl<'db> InstanceType<'db> { fn is_subtype_of(self, db: &'db dyn Db, other: InstanceType<'db>) -> bool { + // N.B. The subclass relation is fully static self.class.is_subclass_of(db, other.class) } } @@ -3382,7 +3469,9 @@ pub(crate) mod tests { }, Tuple(Vec), SubclassOfAny, + SubclassOfUnknown, SubclassOfBuiltinClass(&'static str), + SubclassOfAbcClass(&'static str), StdlibModule(CoreStdlibModule), SliceLiteral(i32, i32, i32), } @@ -3429,12 +3518,19 @@ pub(crate) mod tests { Type::tuple(db, elements) } Ty::SubclassOfAny => Type::subclass_of_base(ClassBase::Any), + Ty::SubclassOfUnknown => Type::subclass_of_base(ClassBase::Unknown), Ty::SubclassOfBuiltinClass(s) => Type::subclass_of( builtins_symbol(db, s) .expect_type() .expect_class_literal() .class, ), + Ty::SubclassOfAbcClass(s) => Type::subclass_of( + core_module_symbol(db, CoreStdlibModule::Abc, s) + .expect_type() + .expect_class_literal() + .class, + ), Ty::StdlibModule(module) => { let module = resolve_module(db, &module.name()).unwrap(); Type::ModuleLiteral(ModuleLiteralType::new(db, module.file(), module)) @@ -3503,6 +3599,10 @@ pub(crate) mod tests { #[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfBuiltinClass("object"))] #[test_case(Ty::BuiltinInstance("type"), Ty::BuiltinInstance("type"))] #[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)] + #[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::SubclassOfUnknown)] + #[test_case(Ty::SubclassOfUnknown, Ty::SubclassOfBuiltinClass("str"))] + #[test_case(Ty::SubclassOfAny, Ty::AbcInstance("ABCMeta"))] + #[test_case(Ty::SubclassOfUnknown, Ty::AbcInstance("ABCMeta"))] fn is_assignable_to(from: Ty, to: Ty) { let db = setup_db(); assert!(from.into_type(&db).is_assignable_to(&db, to.into_type(&db))); @@ -3578,6 +3678,7 @@ pub(crate) mod tests { Ty::KnownClassInstance(KnownClass::ModuleType) )] #[test_case(Ty::SliceLiteral(1, 2, 3), Ty::BuiltinInstance("slice"))] + #[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::Intersection{pos: vec![], neg: vec![Ty::None]})] fn is_subtype_of(from: Ty, to: Ty) { let db = setup_db(); assert!(from.into_type(&db).is_subtype_of(&db, to.into_type(&db))); @@ -3744,6 +3845,8 @@ pub(crate) mod tests { #[test_case(Ty::Tuple(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]), Ty::Tuple(vec![Ty::IntLiteral(1)]))] #[test_case(Ty::Tuple(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]), Ty::Tuple(vec![Ty::IntLiteral(1), Ty::IntLiteral(3)]))] #[test_case(Ty::Tuple(vec![]), Ty::BuiltinClassLiteral("object"))] + #[test_case(Ty::SubclassOfBuiltinClass("object"), Ty::None)] + #[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::LiteralString)] fn is_disjoint_from(a: Ty, b: Ty) { let db = setup_db(); let a = a.into_type(&db); @@ -3773,6 +3876,7 @@ pub(crate) mod tests { #[test_case(Ty::Tuple(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]), Ty::Tuple(vec![Ty::IntLiteral(1), Ty::BuiltinInstance("int")]))] #[test_case(Ty::BuiltinClassLiteral("str"), Ty::BuiltinInstance("type"))] #[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)] + #[test_case(Ty::AbcClassLiteral("ABC"), Ty::AbcInstance("ABCMeta"))] fn is_not_disjoint_from(a: Ty, b: Ty) { let db = setup_db(); let a = a.into_type(&db); diff --git a/crates/red_knot_python_semantic/src/types/class_base.rs b/crates/red_knot_python_semantic/src/types/class_base.rs index 404fd7e3b0c95..850b1996e85ab 100644 --- a/crates/red_knot_python_semantic/src/types/class_base.rs +++ b/crates/red_knot_python_semantic/src/types/class_base.rs @@ -125,7 +125,7 @@ impl<'db> ClassBase<'db> { } } - pub(super) fn into_class_literal_type(self) -> Option> { + pub(super) fn into_class(self) -> Option> { match self { Self::Class(class) => Some(class), _ => None, diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index b94d05f32ecf6..00bd2f4f4e42b 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -4499,9 +4499,12 @@ impl<'db> TypeInferenceBuilder<'db> { // https://typing.readthedocs.io/en/latest/spec/annotations.html#grammar-token-expression-grammar-type_expression match expression { ast::Expr::Name(name) => match name.ctx { - ast::ExprContext::Load => { - self.infer_name_expression(name).in_type_expression(self.db) - } + ast::ExprContext::Load => self + .infer_name_expression(name) + .in_type_expression(self.db) + .unwrap_or_else(|error| { + error.into_fallback_type(&mut self.diagnostics, expression) + }), ast::ExprContext::Invalid => Type::Unknown, ast::ExprContext::Store | ast::ExprContext::Del => todo_type!(), }, @@ -4509,7 +4512,10 @@ impl<'db> TypeInferenceBuilder<'db> { ast::Expr::Attribute(attribute_expression) => match attribute_expression.ctx { ast::ExprContext::Load => self .infer_attribute_expression(attribute_expression) - .in_type_expression(self.db), + .in_type_expression(self.db) + .unwrap_or_else(|error| { + error.into_fallback_type(&mut self.diagnostics, expression) + }), ast::ExprContext::Invalid => Type::Unknown, ast::ExprContext::Store | ast::ExprContext::Del => todo_type!(), }, @@ -5706,9 +5712,9 @@ mod tests { fn builtin_symbol_vendored_stdlib() -> anyhow::Result<()> { let mut db = setup_db(); - db.write_file("/src/a.py", "c = copyright")?; + db.write_file("/src/a.py", "c = chr")?; - assert_public_ty(&db, "/src/a.py", "c", "Literal[copyright]"); + assert_public_ty(&db, "/src/a.py", "c", "Literal[chr]"); Ok(()) } diff --git a/crates/red_knot_python_semantic/src/types/mro.rs b/crates/red_knot_python_semantic/src/types/mro.rs index 908e259670fb2..2f447f1582d3d 100644 --- a/crates/red_knot_python_semantic/src/types/mro.rs +++ b/crates/red_knot_python_semantic/src/types/mro.rs @@ -117,7 +117,7 @@ impl<'db> Mro<'db> { for (index, base) in valid_bases .iter() .enumerate() - .filter_map(|(index, base)| Some((index, base.into_class_literal_type()?))) + .filter_map(|(index, base)| Some((index, base.into_class()?))) { if !seen_bases.insert(base) { duplicate_bases.push((index, base)); diff --git a/crates/red_knot_python_semantic/src/types/property_tests.rs b/crates/red_knot_python_semantic/src/types/property_tests.rs index 381bffa7afde4..83f49ea22039a 100644 --- a/crates/red_knot_python_semantic/src/types/property_tests.rs +++ b/crates/red_knot_python_semantic/src/types/property_tests.rs @@ -65,9 +65,16 @@ fn arbitrary_core_type(g: &mut Gen) -> Ty { Ty::BuiltinClassLiteral("bool"), Ty::BuiltinClassLiteral("object"), Ty::BuiltinInstance("type"), + Ty::AbcInstance("ABC"), + Ty::AbcInstance("ABCMeta"), Ty::SubclassOfAny, Ty::SubclassOfBuiltinClass("object"), Ty::SubclassOfBuiltinClass("str"), + Ty::SubclassOfBuiltinClass("type"), + Ty::AbcClassLiteral("ABC"), + Ty::AbcClassLiteral("ABCMeta"), + Ty::SubclassOfAbcClass("ABC"), + Ty::SubclassOfAbcClass("ABCMeta"), ]) .unwrap() .clone() diff --git a/crates/red_knot_test/src/parser.rs b/crates/red_knot_test/src/parser.rs index f26f8c0cb64fa..9da1da87375cd 100644 --- a/crates/red_knot_test/src/parser.rs +++ b/crates/red_knot_test/src/parser.rs @@ -7,7 +7,8 @@ use rustc_hash::{FxHashMap, FxHashSet}; use ruff_index::{newtype_index, IndexVec}; use ruff_python_trivia::Cursor; -use ruff_text_size::{TextLen, TextSize}; +use ruff_source_file::LineRanges; +use ruff_text_size::{TextLen, TextRange, TextSize}; use crate::config::MarkdownTestConfig; @@ -156,8 +157,14 @@ static HEADER_RE: LazyLock = /// Matches a code block fenced by triple backticks, possibly with language and `key=val` /// configuration items following the opening backticks (in the "tag string" of the code block). static CODE_RE: LazyLock = LazyLock::new(|| { - Regex::new(r"^```(?(?-u:\w)+)?(?(?: +\S+)*)\s*\n(?(?:.|\n)*?)\n?```\s*\n?") - .unwrap() + Regex::new( + r"(?x) + ^```(?(?-u:\w)+)?(?(?:\x20+\S+)*)\s*\n + (?(?:.|\n)*?)\n? + (?```|\z) + ", + ) + .unwrap() }); #[derive(Debug)] @@ -202,6 +209,7 @@ struct Parser<'s> { /// The unparsed remainder of the Markdown source. cursor: Cursor<'s>, + source: &'s str, source_len: TextSize, /// Stack of ancestor sections. @@ -225,6 +233,7 @@ impl<'s> Parser<'s> { }); Self { sections, + source, files: IndexVec::default(), cursor: Cursor::new(source), source_len: source.text_len(), @@ -328,6 +337,13 @@ impl<'s> Parser<'s> { // We never pop the implicit root section. let section = self.stack.top(); + if captures.name("end").unwrap().is_empty() { + let code_block_start = self.cursor.token_len(); + let line = self.source.count_lines(TextRange::up_to(code_block_start)) + 1; + + return Err(anyhow::anyhow!("Unterminated code block at line {line}.")); + } + let mut config: FxHashMap<&'s str, &'s str> = FxHashMap::default(); if let Some(config_match) = captures.name("config") { @@ -664,6 +680,38 @@ mod tests { assert_eq!(file.code, "x = 10"); } + #[test] + fn unterminated_code_block_1() { + let source = dedent( + " + ``` + x = 1 + ", + ); + let err = super::parse("file.md", &source).expect_err("Should fail to parse"); + assert_eq!(err.to_string(), "Unterminated code block at line 2."); + } + + #[test] + fn unterminated_code_block_2() { + let source = dedent( + " + ## A well-fenced block + + ``` + y = 2 + ``` + + ## A not-so-well-fenced block + + ``` + x = 1 + ", + ); + let err = super::parse("file.md", &source).expect_err("Should fail to parse"); + assert_eq!(err.to_string(), "Unterminated code block at line 10."); + } + #[test] fn no_header_inside_test() { let source = dedent( diff --git a/crates/red_knot_vendored/vendor/typeshed/source_commit.txt b/crates/red_knot_vendored/vendor/typeshed/source_commit.txt index 0ce48b8cf5454..58a8994202c46 100644 --- a/crates/red_knot_vendored/vendor/typeshed/source_commit.txt +++ b/crates/red_knot_vendored/vendor/typeshed/source_commit.txt @@ -1 +1 @@ -0a2da01946a406ede42e9c66f416a7e7758991d6 +fc11e835108394728930059c8db5b436209bc957 diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/VERSIONS b/crates/red_knot_vendored/vendor/typeshed/stdlib/VERSIONS index 7ff14c55d3a8b..3c6898dc1a777 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/VERSIONS +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/VERSIONS @@ -57,6 +57,7 @@ _msi: 3.0-3.12 _multibytecodec: 3.0- _operator: 3.4- _osx_support: 3.0- +_pickle: 3.0- _posixsubprocess: 3.2- _py_abc: 3.7- _pydecimal: 3.5- diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/_dummy_threading.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/_dummy_threading.pyi index 21d1d1921c0eb..1b66fb414d7aa 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/_dummy_threading.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/_dummy_threading.pyi @@ -1,11 +1,23 @@ -import sys -from _thread import _excepthook, _ExceptHookArgs +from _threading_local import local as local from _typeshed import ProfileFunction, TraceFunction -from collections.abc import Callable, Iterable, Mapping -from types import TracebackType -from typing import Any, TypeVar - -_T = TypeVar("_T") +from threading import ( + TIMEOUT_MAX as TIMEOUT_MAX, + Barrier as Barrier, + BoundedSemaphore as BoundedSemaphore, + BrokenBarrierError as BrokenBarrierError, + Condition as Condition, + Event as Event, + ExceptHookArgs as ExceptHookArgs, + Lock as Lock, + RLock as RLock, + Semaphore as Semaphore, + Thread as Thread, + ThreadError as ThreadError, + Timer as Timer, + _DummyThread as _DummyThread, + _RLock as _RLock, + excepthook as excepthook, +) __all__ = [ "get_ident", @@ -42,123 +54,3 @@ def main_thread() -> Thread: ... def settrace(func: TraceFunction) -> None: ... def setprofile(func: ProfileFunction | None) -> None: ... def stack_size(size: int | None = None) -> int: ... - -TIMEOUT_MAX: float - -class ThreadError(Exception): ... - -class local: - def __getattribute__(self, name: str) -> Any: ... - def __setattr__(self, name: str, value: Any) -> None: ... - def __delattr__(self, name: str) -> None: ... - -class Thread: - name: str - daemon: bool - @property - def ident(self) -> int | None: ... - def __init__( - self, - group: None = None, - target: Callable[..., object] | None = None, - name: str | None = None, - args: Iterable[Any] = (), - kwargs: Mapping[str, Any] | None = None, - *, - daemon: bool | None = None, - ) -> None: ... - def start(self) -> None: ... - def run(self) -> None: ... - def join(self, timeout: float | None = None) -> None: ... - def getName(self) -> str: ... - def setName(self, name: str) -> None: ... - @property - def native_id(self) -> int | None: ... # only available on some platforms - def is_alive(self) -> bool: ... - if sys.version_info < (3, 9): - def isAlive(self) -> bool: ... - - def isDaemon(self) -> bool: ... - def setDaemon(self, daemonic: bool) -> None: ... - -class _DummyThread(Thread): ... - -class Lock: - def __enter__(self) -> bool: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> bool | None: ... - def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ... - def release(self) -> None: ... - def locked(self) -> bool: ... - -class _RLock: - def __enter__(self) -> bool: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> bool | None: ... - def acquire(self, blocking: bool = True, timeout: float = -1) -> bool: ... - def release(self) -> None: ... - -RLock = _RLock - -class Condition: - def __init__(self, lock: Lock | _RLock | None = None) -> None: ... - def __enter__(self) -> bool: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> bool | None: ... - def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ... - def release(self) -> None: ... - def wait(self, timeout: float | None = None) -> bool: ... - def wait_for(self, predicate: Callable[[], _T], timeout: float | None = None) -> _T: ... - def notify(self, n: int = 1) -> None: ... - def notify_all(self) -> None: ... - def notifyAll(self) -> None: ... - -class Semaphore: - def __init__(self, value: int = 1) -> None: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> bool | None: ... - def acquire(self, blocking: bool = True, timeout: float | None = None) -> bool: ... - def __enter__(self, blocking: bool = True, timeout: float | None = None) -> bool: ... - if sys.version_info >= (3, 9): - def release(self, n: int = ...) -> None: ... - else: - def release(self) -> None: ... - -class BoundedSemaphore(Semaphore): ... - -class Event: - def is_set(self) -> bool: ... - def set(self) -> None: ... - def clear(self) -> None: ... - def wait(self, timeout: float | None = None) -> bool: ... - -excepthook = _excepthook -ExceptHookArgs = _ExceptHookArgs - -class Timer(Thread): - def __init__( - self, - interval: float, - function: Callable[..., object], - args: Iterable[Any] | None = None, - kwargs: Mapping[str, Any] | None = None, - ) -> None: ... - def cancel(self) -> None: ... - -class Barrier: - @property - def parties(self) -> int: ... - @property - def n_waiting(self) -> int: ... - @property - def broken(self) -> bool: ... - def __init__(self, parties: int, action: Callable[[], None] | None = None, timeout: float | None = None) -> None: ... - def wait(self, timeout: float | None = None) -> int: ... - def reset(self) -> None: ... - def abort(self) -> None: ... - -class BrokenBarrierError(RuntimeError): ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/_pickle.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/_pickle.pyi new file mode 100644 index 0000000000000..5566f0f65d6e2 --- /dev/null +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/_pickle.pyi @@ -0,0 +1,108 @@ +import sys +from _typeshed import ReadableBuffer, SupportsWrite +from collections.abc import Callable, Iterable, Iterator, Mapping +from pickle import PickleBuffer as PickleBuffer +from typing import Any, Protocol, type_check_only +from typing_extensions import TypeAlias + +class _ReadableFileobj(Protocol): + def read(self, n: int, /) -> bytes: ... + def readline(self) -> bytes: ... + +_BufferCallback: TypeAlias = Callable[[PickleBuffer], Any] | None + +_ReducedType: TypeAlias = ( + str + | tuple[Callable[..., Any], tuple[Any, ...]] + | tuple[Callable[..., Any], tuple[Any, ...], Any] + | tuple[Callable[..., Any], tuple[Any, ...], Any, Iterator[Any] | None] + | tuple[Callable[..., Any], tuple[Any, ...], Any, Iterator[Any] | None, Iterator[Any] | None] +) + +def dump( + obj: Any, + file: SupportsWrite[bytes], + protocol: int | None = None, + *, + fix_imports: bool = True, + buffer_callback: _BufferCallback = None, +) -> None: ... +def dumps( + obj: Any, protocol: int | None = None, *, fix_imports: bool = True, buffer_callback: _BufferCallback = None +) -> bytes: ... +def load( + file: _ReadableFileobj, + *, + fix_imports: bool = True, + encoding: str = "ASCII", + errors: str = "strict", + buffers: Iterable[Any] | None = (), +) -> Any: ... +def loads( + data: ReadableBuffer, + /, + *, + fix_imports: bool = True, + encoding: str = "ASCII", + errors: str = "strict", + buffers: Iterable[Any] | None = (), +) -> Any: ... + +class PickleError(Exception): ... +class PicklingError(PickleError): ... +class UnpicklingError(PickleError): ... + +@type_check_only +class PicklerMemoProxy: + def clear(self, /) -> None: ... + def copy(self, /) -> dict[int, tuple[int, Any]]: ... + +class Pickler: + fast: bool + dispatch_table: Mapping[type, Callable[[Any], _ReducedType]] + reducer_override: Callable[[Any], Any] + bin: bool # undocumented + def __init__( + self, + file: SupportsWrite[bytes], + protocol: int | None = None, + *, + fix_imports: bool = True, + buffer_callback: _BufferCallback = None, + ) -> None: ... + @property + def memo(self) -> PicklerMemoProxy: ... + @memo.setter + def memo(self, value: PicklerMemoProxy | dict[int, tuple[int, Any]]) -> None: ... + def dump(self, obj: Any, /) -> None: ... + def clear_memo(self) -> None: ... + if sys.version_info >= (3, 13): + def persistent_id(self, obj: Any, /) -> Any: ... + else: + persistent_id: Callable[[Any], Any] + +@type_check_only +class UnpicklerMemoProxy: + def clear(self, /) -> None: ... + def copy(self, /) -> dict[int, tuple[int, Any]]: ... + +class Unpickler: + def __init__( + self, + file: _ReadableFileobj, + *, + fix_imports: bool = True, + encoding: str = "ASCII", + errors: str = "strict", + buffers: Iterable[Any] | None = (), + ) -> None: ... + @property + def memo(self) -> UnpicklerMemoProxy: ... + @memo.setter + def memo(self, value: UnpicklerMemoProxy | dict[int, tuple[int, Any]]) -> None: ... + def load(self) -> Any: ... + def find_class(self, module_name: str, global_name: str, /) -> Any: ... + if sys.version_info >= (3, 13): + def persistent_load(self, pid: Any, /) -> Any: ... + else: + persistent_load: Callable[[Any], Any] diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/_sitebuiltins.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/_sitebuiltins.pyi index 49e88a196825e..eb6c811294216 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/_sitebuiltins.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/_sitebuiltins.pyi @@ -1,3 +1,4 @@ +import sys from collections.abc import Iterable from typing import ClassVar, Literal, NoReturn @@ -5,7 +6,7 @@ class Quitter: name: str eof: str def __init__(self, name: str, eof: str) -> None: ... - def __call__(self, code: int | None = None) -> NoReturn: ... + def __call__(self, code: sys._ExitCode = None) -> NoReturn: ... class _Printer: MAXLINES: ClassVar[Literal[23]] @@ -13,4 +14,4 @@ class _Printer: def __call__(self) -> None: ... class _Helper: - def __call__(self, request: object) -> None: ... + def __call__(self, request: object = ...) -> None: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/_socket.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/_socket.pyi index 36bc5c31c646e..4cf71cbcadfa8 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/_socket.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/_socket.pyi @@ -78,8 +78,10 @@ if sys.platform == "win32": SO_EXCLUSIVEADDRUSE: int if sys.platform != "win32": SO_REUSEPORT: int + if sys.platform != "darwin" or sys.version_info >= (3, 13): + SO_BINDTODEVICE: int + if sys.platform != "win32" and sys.platform != "darwin": - SO_BINDTODEVICE: int SO_DOMAIN: int SO_MARK: int SO_PASSCRED: int diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/_tkinter.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/_tkinter.pyi index 63b1e7ca7cb46..4206a2114f954 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/_tkinter.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/_tkinter.pyi @@ -113,16 +113,31 @@ TK_VERSION: Final[str] class TkttType: def deletetimerhandler(self): ... -def create( - screenName: str | None = None, - baseName: str = "", - className: str = "Tk", - interactive: bool = False, - wantobjects: bool = False, - wantTk: bool = True, - sync: bool = False, - use: str | None = None, - /, -): ... +if sys.version_info >= (3, 13): + def create( + screenName: str | None = None, + baseName: str = "", + className: str = "Tk", + interactive: bool = False, + wantobjects: int = 0, + wantTk: bool = True, + sync: bool = False, + use: str | None = None, + /, + ): ... + +else: + def create( + screenName: str | None = None, + baseName: str = "", + className: str = "Tk", + interactive: bool = False, + wantobjects: bool = False, + wantTk: bool = True, + sync: bool = False, + use: str | None = None, + /, + ): ... + def getbusywaitinterval(): ... def setbusywaitinterval(new_val, /): ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/argparse.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/argparse.pyi index 2526322ac8f6d..365617077f090 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/argparse.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/argparse.pyi @@ -182,30 +182,30 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def add_subparsers( self: _ArgumentParserT, *, - title: str = ..., - description: str | None = ..., - prog: str = ..., + title: str = "subcommands", + description: str | None = None, + prog: str | None = None, action: type[Action] = ..., option_string: str = ..., - dest: str | None = ..., - required: bool = ..., - help: str | None = ..., - metavar: str | None = ..., + dest: str | None = None, + required: bool = False, + help: str | None = None, + metavar: str | None = None, ) -> _SubParsersAction[_ArgumentParserT]: ... @overload def add_subparsers( self, *, - title: str = ..., - description: str | None = ..., - prog: str = ..., + title: str = "subcommands", + description: str | None = None, + prog: str | None = None, parser_class: type[_ArgumentParserT], action: type[Action] = ..., option_string: str = ..., - dest: str | None = ..., - required: bool = ..., - help: str | None = ..., - metavar: str | None = ..., + dest: str | None = None, + required: bool = False, + help: str | None = None, + metavar: str | None = None, ) -> _SubParsersAction[_ArgumentParserT]: ... def print_usage(self, file: IO[str] | None = None) -> None: ... def print_help(self, file: IO[str] | None = None) -> None: ... @@ -237,7 +237,13 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): # undocumented def _get_optional_actions(self) -> list[Action]: ... def _get_positional_actions(self) -> list[Action]: ... - def _parse_known_args(self, arg_strings: list[str], namespace: Namespace) -> tuple[Namespace, list[str]]: ... + if sys.version_info >= (3, 12): + def _parse_known_args( + self, arg_strings: list[str], namespace: Namespace, intermixed: bool + ) -> tuple[Namespace, list[str]]: ... + else: + def _parse_known_args(self, arg_strings: list[str], namespace: Namespace) -> tuple[Namespace, list[str]]: ... + def _read_args_from_files(self, arg_strings: list[str]) -> list[str]: ... def _match_argument(self, action: Action, arg_strings_pattern: str) -> int: ... def _match_arguments_partial(self, actions: Sequence[Action], arg_strings_pattern: str) -> list[int]: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/proactor_events.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/proactor_events.pyi index 957fdd6ce2559..909d671df289d 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/proactor_events.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/proactor_events.pyi @@ -62,3 +62,4 @@ class _ProactorSocketTransport(_ProactorReadPipeTransport, _ProactorBaseWritePip class BaseProactorEventLoop(base_events.BaseEventLoop): def __init__(self, proactor: Any) -> None: ... + async def sock_recv(self, sock: socket, n: int) -> bytes: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/selector_events.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/selector_events.pyi index 430f2dd405cd6..18c5df033e2f6 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/selector_events.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/asyncio/selector_events.pyi @@ -1,4 +1,5 @@ import selectors +from socket import socket from . import base_events @@ -6,3 +7,4 @@ __all__ = ("BaseSelectorEventLoop",) class BaseSelectorEventLoop(base_events.BaseEventLoop): def __init__(self, selector: selectors.BaseSelector | None = None) -> None: ... + async def sock_recv(self, sock: socket, n: int) -> bytes: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/builtins.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/builtins.pyi index 4c7467fc84c81..ad10ba9dff4cf 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/builtins.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/builtins.pyi @@ -1,5 +1,6 @@ # ruff: noqa: PYI036 # This is the module declaring BaseException import _ast +import _sitebuiltins import _typeshed import sys import types @@ -46,7 +47,6 @@ from typing import ( # noqa: Y022 Mapping, MutableMapping, MutableSequence, - NoReturn, Protocol, Sequence, SupportsAbs, @@ -1362,8 +1362,10 @@ def compile( *, _feature_version: int = -1, ) -> Any: ... -def copyright() -> None: ... -def credits() -> None: ... + +copyright: _sitebuiltins._Printer +credits: _sitebuiltins._Printer + def delattr(obj: object, name: str, /) -> None: ... def dir(o: object = ..., /) -> list[str]: ... @overload @@ -1418,7 +1420,7 @@ else: /, ) -> None: ... -def exit(code: sys._ExitCode = None) -> NoReturn: ... +exit: _sitebuiltins.Quitter class filter(Generic[_T]): @overload @@ -1452,7 +1454,9 @@ def getattr(o: object, name: str, default: _T, /) -> Any | _T: ... def globals() -> dict[str, Any]: ... def hasattr(obj: object, name: str, /) -> bool: ... def hash(obj: object, /) -> int: ... -def help(request: object = ...) -> None: ... + +help: _sitebuiltins._Helper + def hex(number: int | SupportsIndex, /) -> str: ... def id(obj: object, /) -> int: ... def input(prompt: object = "", /) -> str: ... @@ -1478,7 +1482,9 @@ else: def isinstance(obj: object, class_or_tuple: _ClassInfo, /) -> bool: ... def issubclass(cls: type, class_or_tuple: _ClassInfo, /) -> bool: ... def len(obj: Sized, /) -> int: ... -def license() -> None: ... + +license: _sitebuiltins._Printer + def locals() -> dict[str, Any]: ... class map(Generic[_S]): @@ -1721,7 +1727,8 @@ def pow(base: _SupportsPow3[_E, _M, _T_co], exp: _E, mod: _M) -> _T_co: ... def pow(base: _SupportsSomeKindOfPow, exp: float, mod: None = None) -> Any: ... @overload def pow(base: _SupportsSomeKindOfPow, exp: complex, mod: None = None) -> complex: ... -def quit(code: sys._ExitCode = None) -> NoReturn: ... + +quit: _sitebuiltins.Quitter class reversed(Generic[_T]): @overload diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/codeop.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/codeop.pyi index 6a51b7786384c..cfe52e9b35de7 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/codeop.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/codeop.pyi @@ -1,3 +1,4 @@ +import sys from types import CodeType __all__ = ["compile_command", "Compile", "CommandCompiler"] @@ -6,7 +7,10 @@ def compile_command(source: str, filename: str = "", symbol: str = "singl class Compile: flags: int - def __call__(self, source: str, filename: str, symbol: str) -> CodeType: ... + if sys.version_info >= (3, 13): + def __call__(self, source: str, filename: str, symbol: str, flags: int = 0) -> CodeType: ... + else: + def __call__(self, source: str, filename: str, symbol: str) -> CodeType: ... class CommandCompiler: compiler: Compile diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/concurrent/futures/process.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/concurrent/futures/process.pyi index a1de3d679b236..97dc261be7ed8 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/concurrent/futures/process.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/concurrent/futures/process.pyi @@ -72,9 +72,19 @@ class _CallItem: class _SafeQueue(Queue[Future[Any]]): pending_work_items: dict[int, _WorkItem[Any]] - shutdown_lock: Lock + if sys.version_info < (3, 12): + shutdown_lock: Lock thread_wakeup: _ThreadWakeup - if sys.version_info >= (3, 9): + if sys.version_info >= (3, 12): + def __init__( + self, + max_size: int | None = 0, + *, + ctx: BaseContext, + pending_work_items: dict[int, _WorkItem[Any]], + thread_wakeup: _ThreadWakeup, + ) -> None: ... + elif sys.version_info >= (3, 9): def __init__( self, max_size: int | None = 0, diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/ctypes/__init__.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/ctypes/__init__.pyi index 3e0e7c45bf156..a15dd3615c0c0 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/ctypes/__init__.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/ctypes/__init__.pyi @@ -47,7 +47,7 @@ class ArgumentError(Exception): ... class CDLL: _func_flags_: ClassVar[int] - _func_restype_: ClassVar[_CDataType] + _func_restype_: ClassVar[type[_CDataType]] _name: str _handle: int _FuncPtr: type[_FuncPointer] @@ -202,7 +202,10 @@ if sys.platform == "win32": class HRESULT(_SimpleCData[int]): ... # TODO undocumented if sys.version_info >= (3, 12): - c_time_t: type[c_int32 | c_int64] # alias for one or the other at runtime + # At runtime, this is an alias for either c_int32 or c_int64, + # which are themselves an alias for one of c_short, c_int, c_long, or c_longlong + # This covers all our bases. + c_time_t: type[c_int32 | c_int64 | c_short | c_int | c_long | c_longlong] class py_object(_CanCastTo, _SimpleCData[_T]): ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/fractions.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/fractions.pyi index fbcfa868cc1bb..33bc766df15d9 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/fractions.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/fractions.pyi @@ -27,11 +27,11 @@ class Fraction(Rational): @overload def __new__(cls, numerator: int | Rational = 0, denominator: int | Rational | None = None) -> Self: ... @overload - def __new__(cls, value: float | Decimal | str, /) -> Self: ... + def __new__(cls, numerator: float | Decimal | str) -> Self: ... if sys.version_info >= (3, 14): @overload - def __new__(cls, value: _ConvertibleToIntegerRatio) -> Self: ... + def __new__(cls, numerator: _ConvertibleToIntegerRatio) -> Self: ... @classmethod def from_float(cls, f: float) -> Self: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/gzip.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/gzip.pyi index 9b32008dcbf65..b7fb40fbd82ee 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/gzip.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/gzip.pyi @@ -2,8 +2,8 @@ import _compression import sys import zlib from _typeshed import ReadableBuffer, SizedBuffer, StrOrBytesPath -from io import FileIO -from typing import Final, Literal, Protocol, TextIO, overload +from io import FileIO, TextIOWrapper +from typing import Final, Literal, Protocol, overload from typing_extensions import TypeAlias __all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"] @@ -57,13 +57,13 @@ def open( ) -> GzipFile: ... @overload def open( - filename: StrOrBytesPath, + filename: StrOrBytesPath | _ReadableFileobj | _WritableFileobj, mode: _OpenTextMode, compresslevel: int = 9, encoding: str | None = None, errors: str | None = None, newline: str | None = None, -) -> TextIO: ... +) -> TextIOWrapper: ... @overload def open( filename: StrOrBytesPath | _ReadableFileobj | _WritableFileobj, @@ -72,7 +72,7 @@ def open( encoding: str | None = None, errors: str | None = None, newline: str | None = None, -) -> GzipFile | TextIO: ... +) -> GzipFile | TextIOWrapper: ... class _PaddedFile: file: _ReadableFileobj diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/multiprocessing/reduction.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/multiprocessing/reduction.pyi index 473e90936d71a..942e92ce530ec 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/multiprocessing/reduction.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/multiprocessing/reduction.pyi @@ -1,12 +1,12 @@ import pickle import sys +from _pickle import _ReducedType from _typeshed import HasFileno, SupportsWrite, Unused from abc import ABCMeta from builtins import type as Type # alias to avoid name clash from collections.abc import Callable from copyreg import _DispatchTableType from multiprocessing import connection -from pickle import _ReducedType from socket import socket from typing import Any, Final diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/optparse.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/optparse.pyi index d6db7a06f291a..6096ac4a2a1d9 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/optparse.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/optparse.pyi @@ -182,6 +182,8 @@ class Values: def ensure_value(self, attr: str, value): ... def read_file(self, filename: str, mode: str = "careful") -> None: ... def read_module(self, modname: str, mode: str = "careful") -> None: ... + # __getattr__ doesn't exist, but anything passed as a default to __init__ + # is set on the instance. def __getattr__(self, name: str): ... def __setattr__(self, name: str, value, /) -> None: ... def __eq__(self, other: object) -> bool: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/os/__init__.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/os/__init__.pyi index 98260b14e7ed4..64691b514a484 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/os/__init__.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/os/__init__.pyi @@ -231,6 +231,7 @@ if sys.platform == "linux" and sys.version_info >= (3, 12): "CLONE_NEWNET", "CLONE_NEWNS", "CLONE_NEWPID", + "CLONE_NEWTIME", "CLONE_NEWUSER", "CLONE_NEWUTS", "CLONE_SIGHAND", diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/pickle.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/pickle.pyi index 9bea92ef1c9eb..5e398f2d49217 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/pickle.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/pickle.pyi @@ -1,7 +1,20 @@ +from _pickle import ( + PickleError as PickleError, + Pickler as Pickler, + PicklingError as PicklingError, + Unpickler as Unpickler, + UnpicklingError as UnpicklingError, + _BufferCallback, + _ReadableFileobj, + _ReducedType, + dump as dump, + dumps as dumps, + load as load, + loads as loads, +) from _typeshed import ReadableBuffer, SupportsWrite -from collections.abc import Callable, Iterable, Iterator, Mapping -from typing import Any, ClassVar, Protocol, SupportsBytes, SupportsIndex, final -from typing_extensions import TypeAlias +from collections.abc import Callable, Iterable, Mapping +from typing import Any, ClassVar, SupportsBytes, SupportsIndex, final __all__ = [ "PickleBuffer", @@ -93,10 +106,6 @@ DEFAULT_PROTOCOL: int bytes_types: tuple[type[Any], ...] # undocumented -class _ReadableFileobj(Protocol): - def read(self, n: int, /) -> bytes: ... - def readline(self) -> bytes: ... - @final class PickleBuffer: def __init__(self, buffer: ReadableBuffer) -> None: ... @@ -105,84 +114,6 @@ class PickleBuffer: def __buffer__(self, flags: int, /) -> memoryview: ... def __release_buffer__(self, buffer: memoryview, /) -> None: ... -_BufferCallback: TypeAlias = Callable[[PickleBuffer], Any] | None - -def dump( - obj: Any, - file: SupportsWrite[bytes], - protocol: int | None = None, - *, - fix_imports: bool = True, - buffer_callback: _BufferCallback = None, -) -> None: ... -def dumps( - obj: Any, protocol: int | None = None, *, fix_imports: bool = True, buffer_callback: _BufferCallback = None -) -> bytes: ... -def load( - file: _ReadableFileobj, - *, - fix_imports: bool = True, - encoding: str = "ASCII", - errors: str = "strict", - buffers: Iterable[Any] | None = (), -) -> Any: ... -def loads( - data: ReadableBuffer, - /, - *, - fix_imports: bool = True, - encoding: str = "ASCII", - errors: str = "strict", - buffers: Iterable[Any] | None = (), -) -> Any: ... - -class PickleError(Exception): ... -class PicklingError(PickleError): ... -class UnpicklingError(PickleError): ... - -_ReducedType: TypeAlias = ( - str - | tuple[Callable[..., Any], tuple[Any, ...]] - | tuple[Callable[..., Any], tuple[Any, ...], Any] - | tuple[Callable[..., Any], tuple[Any, ...], Any, Iterator[Any] | None] - | tuple[Callable[..., Any], tuple[Any, ...], Any, Iterator[Any] | None, Iterator[Any] | None] -) - -class Pickler: - fast: bool - dispatch_table: Mapping[type, Callable[[Any], _ReducedType]] - bin: bool # undocumented - dispatch: ClassVar[dict[type, Callable[[Unpickler, Any], None]]] # undocumented, _Pickler only - - def __init__( - self, - file: SupportsWrite[bytes], - protocol: int | None = None, - *, - fix_imports: bool = True, - buffer_callback: _BufferCallback = None, - ) -> None: ... - def reducer_override(self, obj: Any) -> Any: ... - def dump(self, obj: Any, /) -> None: ... - def clear_memo(self) -> None: ... - def persistent_id(self, obj: Any) -> Any: ... - -class Unpickler: - dispatch: ClassVar[dict[int, Callable[[Unpickler], None]]] # undocumented, _Unpickler only - - def __init__( - self, - file: _ReadableFileobj, - *, - fix_imports: bool = True, - encoding: str = "ASCII", - errors: str = "strict", - buffers: Iterable[Any] | None = (), - ) -> None: ... - def load(self) -> Any: ... - def find_class(self, module_name: str, global_name: str, /) -> Any: ... - def persistent_load(self, pid: Any) -> Any: ... - MARK: bytes STOP: bytes POP: bytes @@ -266,6 +197,36 @@ READONLY_BUFFER: bytes def encode_long(x: int) -> bytes: ... # undocumented def decode_long(data: Iterable[SupportsIndex] | SupportsBytes | ReadableBuffer) -> int: ... # undocumented -# pure-Python implementations -_Pickler = Pickler # undocumented -_Unpickler = Unpickler # undocumented +# undocumented pure-Python implementations +class _Pickler: + fast: bool + dispatch_table: Mapping[type, Callable[[Any], _ReducedType]] + bin: bool # undocumented + dispatch: ClassVar[dict[type, Callable[[Unpickler, Any], None]]] # undocumented, _Pickler only + reducer_override: Callable[[Any], Any] + def __init__( + self, + file: SupportsWrite[bytes], + protocol: int | None = None, + *, + fix_imports: bool = True, + buffer_callback: _BufferCallback = None, + ) -> None: ... + def dump(self, obj: Any) -> None: ... + def clear_memo(self) -> None: ... + def persistent_id(self, obj: Any) -> Any: ... + +class _Unpickler: + dispatch: ClassVar[dict[int, Callable[[Unpickler], None]]] # undocumented, _Unpickler only + def __init__( + self, + file: _ReadableFileobj, + *, + fix_imports: bool = True, + encoding: str = "ASCII", + errors: str = "strict", + buffers: Iterable[Any] | None = None, + ) -> None: ... + def load(self) -> Any: ... + def find_class(self, module: str, name: str) -> Any: ... + def persistent_load(self, pid: Any) -> Any: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/pickletools.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/pickletools.pyi index 542172814926c..cdade08d39a87 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/pickletools.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/pickletools.pyi @@ -1,3 +1,4 @@ +import sys from collections.abc import Callable, Iterator, MutableMapping from typing import IO, Any from typing_extensions import TypeAlias @@ -40,7 +41,13 @@ def read_uint8(f: IO[bytes]) -> int: ... uint8: ArgumentDescriptor -def read_stringnl(f: IO[bytes], decode: bool = True, stripquotes: bool = True) -> bytes | str: ... +if sys.version_info >= (3, 12): + def read_stringnl( + f: IO[bytes], decode: bool = True, stripquotes: bool = True, *, encoding: str = "latin-1" + ) -> bytes | str: ... + +else: + def read_stringnl(f: IO[bytes], decode: bool = True, stripquotes: bool = True) -> bytes | str: ... stringnl: ArgumentDescriptor diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/select.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/select.pyi index 6d4c8d8f4c157..67203905ab66d 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/select.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/select.pyi @@ -10,7 +10,8 @@ if sys.platform != "win32": POLLERR: int POLLHUP: int POLLIN: int - POLLMSG: int + if sys.platform == "linux": + POLLMSG: int POLLNVAL: int POLLOUT: int POLLPRI: int @@ -77,7 +78,8 @@ if sys.platform != "linux" and sys.platform != "win32": KQ_EV_ONESHOT: int KQ_EV_SYSFLAGS: int KQ_FILTER_AIO: int - KQ_FILTER_NETDEV: int + if sys.platform != "darwin": + KQ_FILTER_NETDEV: int KQ_FILTER_PROC: int KQ_FILTER_READ: int KQ_FILTER_SIGNAL: int diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/selectors.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/selectors.pyi index a857d0e242ab5..7dad0c13bf2a6 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/selectors.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/selectors.pyi @@ -53,7 +53,7 @@ if sys.platform == "linux": class DevpollSelector(_PollLikeSelector): def fileno(self) -> int: ... -if sys.platform != "win32": +if sys.platform != "win32" and sys.platform != "linux": class KqueueSelector(_BaseSelectorImpl): def fileno(self) -> int: ... def select(self, timeout: float | None = None) -> list[tuple[SelectorKey, _EventMask]]: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/socket.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/socket.pyi index e42bba757fc36..ab22cced0bb53 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/socket.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/socket.pyi @@ -367,7 +367,6 @@ if sys.platform != "win32" and sys.platform != "darwin": IP_TRANSPARENT as IP_TRANSPARENT, IPX_TYPE as IPX_TYPE, SCM_CREDENTIALS as SCM_CREDENTIALS, - SO_BINDTODEVICE as SO_BINDTODEVICE, SO_DOMAIN as SO_DOMAIN, SO_MARK as SO_MARK, SO_PASSCRED as SO_PASSCRED, @@ -396,7 +395,6 @@ if sys.platform != "win32" and sys.platform != "darwin": __all__ += [ "IP_TRANSPARENT", "SCM_CREDENTIALS", - "SO_BINDTODEVICE", "SO_DOMAIN", "SO_MARK", "SO_PASSCRED", @@ -517,6 +515,11 @@ if sys.platform != "win32": "IPV6_RTHDRDSTOPTS", ] + if sys.platform != "darwin" or sys.version_info >= (3, 13): + from _socket import SO_BINDTODEVICE as SO_BINDTODEVICE + + __all__ += ["SO_BINDTODEVICE"] + if sys.platform != "darwin" and sys.platform != "linux": if sys.platform != "win32" or sys.version_info >= (3, 9): from _socket import BDADDR_ANY as BDADDR_ANY, BDADDR_LOCAL as BDADDR_LOCAL, BTPROTO_RFCOMM as BTPROTO_RFCOMM @@ -1046,7 +1049,6 @@ class AddressFamily(IntEnum): AF_INET = 2 AF_INET6 = 10 AF_APPLETALK = 5 - AF_DECnet = ... AF_IPX = 4 AF_SNA = 22 AF_UNSPEC = 0 @@ -1096,7 +1098,7 @@ class AddressFamily(IntEnum): AF_INET = AddressFamily.AF_INET AF_INET6 = AddressFamily.AF_INET6 AF_APPLETALK = AddressFamily.AF_APPLETALK -AF_DECnet = AddressFamily.AF_DECnet +AF_DECnet: Literal[12] AF_IPX = AddressFamily.AF_IPX AF_SNA = AddressFamily.AF_SNA AF_UNSPEC = AddressFamily.AF_UNSPEC diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/sys/__init__.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/sys/__init__.pyi index c4b1adca9bc6b..fb1e24f3e864e 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/sys/__init__.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/sys/__init__.pyi @@ -73,7 +73,7 @@ if sys.version_info >= (3, 10): __stdin__: Final[TextIOWrapper | None] # Contains the original value of stdin __stdout__: Final[TextIOWrapper | None] # Contains the original value of stdout __stderr__: Final[TextIOWrapper | None] # Contains the original value of stderr -tracebacklimit: int +tracebacklimit: int | None version: str api_version: int warnoptions: Any diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/tarfile.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/tarfile.pyi index a7135d8150ee9..a717c280a423d 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/tarfile.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/tarfile.pyi @@ -1,7 +1,7 @@ import bz2 import io import sys -from _typeshed import StrOrBytesPath, StrPath, SupportsRead +from _typeshed import ReadableBuffer, StrOrBytesPath, StrPath, SupportsRead, WriteableBuffer from builtins import list as _list # aliases to avoid name clashes with fields named "type" or "list" from collections.abc import Callable, Iterable, Iterator, Mapping from gzip import _ReadableFileobj as _GzipReadableFileobj, _WritableFileobj as _GzipWritableFileobj @@ -226,15 +226,29 @@ def open( errorlevel: int | None = ..., preset: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | None = ..., ) -> TarFile: ... - -# TODO: Temporary fallback for modes containing pipe characters. These don't -# work with mypy 1.10, but this should be fixed with mypy 1.11. -# https://github.com/python/typeshed/issues/12182 @overload def open( - name: StrOrBytesPath | None = None, + name: StrOrBytesPath | ReadableBuffer | None = None, + *, + mode: Literal["r|*", "r|", "r|gz", "r|bz2", "r|xz"], + fileobj: IO[bytes] | None = None, + bufsize: int = 10240, + format: int | None = ..., + tarinfo: type[TarInfo] | None = ..., + dereference: bool | None = ..., + ignore_zeros: bool | None = ..., + encoding: str | None = ..., + errors: str = ..., + pax_headers: Mapping[str, str] | None = ..., + debug: int | None = ..., + errorlevel: int | None = ..., + preset: int | None = ..., +) -> TarFile: ... +@overload +def open( + name: StrOrBytesPath | WriteableBuffer | None = None, *, - mode: str, + mode: Literal["w|", "w|gz", "w|bz2", "w|xz"], fileobj: IO[bytes] | None = None, bufsize: int = 10240, format: int | None = ..., @@ -557,7 +571,7 @@ class TarInfo: self, *, name: str = ..., - mtime: int = ..., + mtime: float = ..., mode: int = ..., linkname: str = ..., uid: int = ..., diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi index d6a234d67919c..a9ec97c45b40b 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/tkinter/__init__.pyi @@ -403,6 +403,9 @@ class Misc: # after_idle is essentially partialmethod(after, "idle") def after_idle(self, func: Callable[[Unpack[_Ts]], object], *args: Unpack[_Ts]) -> str: ... def after_cancel(self, id: str) -> None: ... + if sys.version_info >= (3, 13): + def after_info(self, id: str | None = None) -> tuple[str, ...]: ... + def bell(self, displayof: Literal[0] | Misc | None = 0) -> None: ... def clipboard_get(self, *, displayof: Misc = ..., type: str = ...) -> str: ... def clipboard_clear(self, *, displayof: Misc = ...) -> None: ... @@ -659,6 +662,38 @@ class YView: @overload def yview_scroll(self, number: _ScreenUnits, what: Literal["pixels"]) -> None: ... +if sys.platform == "darwin": + @type_check_only + class _WmAttributes(TypedDict): + alpha: float + fullscreen: bool + modified: bool + notify: bool + titlepath: str + topmost: bool + transparent: bool + type: str # Present, but not actually used on darwin + +elif sys.platform == "win32": + @type_check_only + class _WmAttributes(TypedDict): + alpha: float + transparentcolor: str + disabled: bool + fullscreen: bool + toolwindow: bool + topmost: bool + +else: + # X11 + @type_check_only + class _WmAttributes(TypedDict): + alpha: float + topmost: bool + zoomed: bool + fullscreen: bool + type: str + class Wm: @overload def wm_aspect(self, minNumer: int, minDenom: int, maxNumer: int, maxDenom: int) -> None: ... @@ -667,12 +702,144 @@ class Wm: self, minNumer: None = None, minDenom: None = None, maxNumer: None = None, maxDenom: None = None ) -> tuple[int, int, int, int] | None: ... aspect = wm_aspect + if sys.version_info >= (3, 13): + @overload + def wm_attributes(self, *, return_python_dict: Literal[False] = False) -> tuple[Any, ...]: ... + @overload + def wm_attributes(self, *, return_python_dict: Literal[True]) -> _WmAttributes: ... + + else: + @overload + def wm_attributes(self) -> tuple[Any, ...]: ... + + @overload + def wm_attributes(self, option: Literal["-alpha"], /) -> float: ... @overload - def wm_attributes(self) -> tuple[Any, ...]: ... + def wm_attributes(self, option: Literal["-fullscreen"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["-topmost"], /) -> bool: ... + if sys.platform == "darwin": + @overload + def wm_attributes(self, option: Literal["-modified"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["-notify"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["-titlepath"], /) -> str: ... + @overload + def wm_attributes(self, option: Literal["-transparent"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["-type"], /) -> str: ... + elif sys.platform == "win32": + @overload + def wm_attributes(self, option: Literal["-transparentcolor"], /) -> str: ... + @overload + def wm_attributes(self, option: Literal["-disabled"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["-toolwindow"], /) -> bool: ... + else: + # X11 + @overload + def wm_attributes(self, option: Literal["-zoomed"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["-type"], /) -> str: ... + if sys.version_info >= (3, 13): + @overload + def wm_attributes(self, option: Literal["alpha"], /) -> float: ... + @overload + def wm_attributes(self, option: Literal["fullscreen"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["topmost"], /) -> bool: ... + if sys.platform == "darwin": + @overload + def wm_attributes(self, option: Literal["modified"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["notify"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["titlepath"], /) -> str: ... + @overload + def wm_attributes(self, option: Literal["transparent"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["type"], /) -> str: ... + elif sys.platform == "win32": + @overload + def wm_attributes(self, option: Literal["transparentcolor"], /) -> str: ... + @overload + def wm_attributes(self, option: Literal["disabled"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["toolwindow"], /) -> bool: ... + else: + # X11 + @overload + def wm_attributes(self, option: Literal["zoomed"], /) -> bool: ... + @overload + def wm_attributes(self, option: Literal["type"], /) -> str: ... + @overload def wm_attributes(self, option: str, /): ... @overload - def wm_attributes(self, option: str, value, /, *__other_option_value_pairs: Any) -> None: ... + def wm_attributes(self, option: Literal["-alpha"], value: float, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-fullscreen"], value: bool, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-topmost"], value: bool, /) -> Literal[""]: ... + if sys.platform == "darwin": + @overload + def wm_attributes(self, option: Literal["-modified"], value: bool, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-notify"], value: bool, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-titlepath"], value: str, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-transparent"], value: bool, /) -> Literal[""]: ... + elif sys.platform == "win32": + @overload + def wm_attributes(self, option: Literal["-transparentcolor"], value: str, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-disabled"], value: bool, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-toolwindow"], value: bool, /) -> Literal[""]: ... + else: + # X11 + @overload + def wm_attributes(self, option: Literal["-zoomed"], value: bool, /) -> Literal[""]: ... + @overload + def wm_attributes(self, option: Literal["-type"], value: str, /) -> Literal[""]: ... + + @overload + def wm_attributes(self, option: str, value, /, *__other_option_value_pairs: Any) -> Literal[""]: ... + if sys.version_info >= (3, 13): + if sys.platform == "darwin": + @overload + def wm_attributes( + self, + *, + alpha: float = ..., + fullscreen: bool = ..., + modified: bool = ..., + notify: bool = ..., + titlepath: str = ..., + topmost: bool = ..., + transparent: bool = ..., + ) -> None: ... + elif sys.platform == "win32": + @overload + def wm_attributes( + self, + *, + alpha: float = ..., + transparentcolor: str = ..., + disabled: bool = ..., + fullscreen: bool = ..., + toolwindow: bool = ..., + topmost: bool = ..., + ) -> None: ... + else: + # X11 + @overload + def wm_attributes( + self, *, alpha: float = ..., topmost: bool = ..., zoomed: bool = ..., fullscreen: bool = ..., type: str = ... + ) -> None: ... + attributes = wm_attributes def wm_client(self, name: str | None = None) -> str: ... client = wm_client diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/token.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/token.pyi index 668987d7c2bfd..741ce5b035b77 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/token.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/token.pyi @@ -76,7 +76,7 @@ if sys.version_info >= (3, 10): __all__ += ["SOFT_KEYWORD"] if sys.version_info >= (3, 12): - __all__ += ["EXCLAMATION", "FSTRING_END", "FSTRING_MIDDLE", "FSTRING_START"] + __all__ += ["EXCLAMATION", "FSTRING_END", "FSTRING_MIDDLE", "FSTRING_START", "EXACT_TOKEN_TYPES"] ENDMARKER: int NAME: int diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/tokenize.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/tokenize.pyi index 7e9a945cdc46d..7b68f791a8c04 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/tokenize.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/tokenize.pyi @@ -88,7 +88,7 @@ if sys.version_info >= (3, 10): __all__ += ["SOFT_KEYWORD"] if sys.version_info >= (3, 12): - __all__ += ["EXCLAMATION", "FSTRING_END", "FSTRING_MIDDLE", "FSTRING_START"] + __all__ += ["EXCLAMATION", "FSTRING_END", "FSTRING_MIDDLE", "FSTRING_START", "EXACT_TOKEN_TYPES"] if sys.version_info >= (3, 13): __all__ += ["TokenError", "open"] diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/traceback.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/traceback.pyi index 1c4a59de66aa2..e36081acfa03d 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/traceback.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/traceback.pyi @@ -115,6 +115,8 @@ if sys.version_info >= (3, 11): class TracebackException: __cause__: TracebackException __context__: TracebackException + if sys.version_info >= (3, 11): + exceptions: list[TracebackException] | None __suppress_context__: bool stack: StackSummary filename: str diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi index 8f0d4fbb6a024..741e7b8a31674 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi @@ -757,7 +757,7 @@ class MutableMapping(Mapping[_KT, _VT]): Text = str -TYPE_CHECKING: bool +TYPE_CHECKING: Final[bool] # In stubs, the arguments of the IO class are marked as positional-only. # This differs from runtime, but better reflects the fact that in reality diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/weakref.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/weakref.pyi index 853caf3e8abb2..4203756c718d7 100644 --- a/crates/red_knot_vendored/vendor/typeshed/stdlib/weakref.pyi +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/weakref.pyi @@ -172,11 +172,11 @@ class WeakKeyDictionary(MutableMapping[_KT, _VT]): @overload def __ior__(self, other: Iterable[tuple[_KT, _VT]]) -> Self: ... -class finalize: # TODO: This is a good candidate for to be a `Generic[_P, _T]` class - def __init__(self, obj: object, func: Callable[_P, Any], /, *args: _P.args, **kwargs: _P.kwargs) -> None: ... +class finalize(Generic[_P, _T]): + def __init__(self, obj: _T, func: Callable[_P, Any], /, *args: _P.args, **kwargs: _P.kwargs) -> None: ... def __call__(self, _: Any = None) -> Any | None: ... - def detach(self) -> tuple[Any, Any, tuple[Any, ...], dict[str, Any]] | None: ... - def peek(self) -> tuple[Any, Any, tuple[Any, ...], dict[str, Any]] | None: ... + def detach(self) -> tuple[_T, Callable[_P, Any], tuple[Any, ...], dict[str, Any]] | None: ... + def peek(self) -> tuple[_T, Callable[_P, Any], tuple[Any, ...], dict[str, Any]] | None: ... @property def alive(self) -> bool: ... atexit: bool diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/xml/sax/expatreader.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/xml/sax/expatreader.pyi new file mode 100644 index 0000000000000..0f7bda5872c0f --- /dev/null +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/xml/sax/expatreader.pyi @@ -0,0 +1,53 @@ +import sys +from _typeshed import Unused +from xml.sax import xmlreader + +version: str +AttributesImpl = xmlreader.AttributesImpl +AttributesNSImpl = xmlreader.AttributesNSImpl + +class _ClosedParser: ... + +class ExpatLocator(xmlreader.Locator): + def __init__(self, parser: ExpatParser) -> None: ... + def getColumnNumber(self) -> int: ... + def getLineNumber(self) -> int: ... + def getPublicId(self): ... + def getSystemId(self): ... + +class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator): + def __init__(self, namespaceHandling: int = 0, bufsize: int = 65516) -> None: ... + def parse(self, source) -> None: ... + def prepareParser(self, source) -> None: ... + def setContentHandler(self, handler) -> None: ... + def getFeature(self, name: str): ... + def setFeature(self, name: str, state) -> None: ... + def getProperty(self, name: str): ... + def setProperty(self, name: str, value) -> None: ... + if sys.version_info >= (3, 9): + def feed(self, data, isFinal: bool = False) -> None: ... + else: + def feed(self, data, isFinal: int = 0) -> None: ... + + def flush(self) -> None: ... + def close(self) -> None: ... + def reset(self) -> None: ... + def getColumnNumber(self) -> int | None: ... + def getLineNumber(self) -> int: ... + def getPublicId(self): ... + def getSystemId(self): ... + def start_element(self, name: str, attrs: xmlreader.AttributesImpl) -> None: ... + def end_element(self, name: str) -> None: ... + def start_element_ns(self, name: str, attrs) -> None: ... + def end_element_ns(self, name: str) -> None: ... + def processing_instruction(self, target: str, data: str) -> None: ... + def character_data(self, data: str) -> None: ... + def start_namespace_decl(self, prefix: str | None, uri: str) -> None: ... + def end_namespace_decl(self, prefix: str | None) -> None: ... + def start_doctype_decl(self, name: str, sysid: str | None, pubid: str | None, has_internal_subset: Unused) -> None: ... + def unparsed_entity_decl(self, name, base, sysid, pubid, notation_name) -> None: ... + def notation_decl(self, name, base, sysid, pubid) -> None: ... + def external_entity_ref(self, context, base, sysid, pubid): ... + def skipped_entity_handler(self, name: str, is_pe: bool) -> None: ... + +def create_parser(namespaceHandling: int = 0, bufsize: int = 65516) -> ExpatParser: ... diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/zipfile/_path.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/zipfile/_path/__init__.pyi similarity index 100% rename from crates/red_knot_vendored/vendor/typeshed/stdlib/zipfile/_path.pyi rename to crates/red_knot_vendored/vendor/typeshed/stdlib/zipfile/_path/__init__.pyi diff --git a/crates/red_knot_vendored/vendor/typeshed/stdlib/zipfile/_path/glob.pyi b/crates/red_knot_vendored/vendor/typeshed/stdlib/zipfile/_path/glob.pyi new file mode 100644 index 0000000000000..f25ae71725c02 --- /dev/null +++ b/crates/red_knot_vendored/vendor/typeshed/stdlib/zipfile/_path/glob.pyi @@ -0,0 +1,22 @@ +import sys +from collections.abc import Iterator +from re import Match + +if sys.version_info >= (3, 13): + class Translator: + def __init__(self, seps: str = ...) -> None: ... + def translate(self, pattern: str) -> str: ... + def extend(self, pattern: str) -> str: ... + def match_dirs(self, pattern: str) -> str: ... + def translate_core(self, pattern: str) -> str: ... + def replace(self, match: Match[str]) -> str: ... + def restrict_rglob(self, pattern: str) -> None: ... + def star_not_empty(self, pattern: str) -> str: ... + +else: + def translate(pattern: str) -> str: ... + def match_dirs(pattern: str) -> str: ... + def translate_core(pattern: str) -> str: ... + def replace(match: Match[str]) -> str: ... + +def separate(pattern: str) -> Iterator[Match[str]]: ... diff --git a/crates/ruff_linter/resources/test/fixtures/perflint/PERF401.py b/crates/ruff_linter/resources/test/fixtures/perflint/PERF401.py index 553742fe26c0c..a1c071c8ac6db 100644 --- a/crates/ruff_linter/resources/test/fixtures/perflint/PERF401.py +++ b/crates/ruff_linter/resources/test/fixtures/perflint/PERF401.py @@ -237,3 +237,10 @@ def f(): print(a) for a in values: result.append(a + 1) # PERF401 + +def f(): + values = [1, 2, 3] + def g(): + for a in values: + result.append(a + 1) # PERF401 + result = [] diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D403.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D403.py index bd90d60bc84c2..62105959cf259 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D403.py +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D403.py @@ -31,3 +31,13 @@ def single_word(): def single_word_no_dot(): """singleword""" + +def first_word_lots_of_whitespace(): + """ + + + + here is the start of my docstring! + + What do you think? + """ diff --git a/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs b/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs index 4580d23a644d8..b9e8be637dd53 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs @@ -46,7 +46,7 @@ pub(crate) fn definitions(checker: &mut Checker) { Rule::EndsInPeriod, Rule::EndsInPunctuation, Rule::EscapeSequenceInDocstring, - Rule::FirstLineCapitalized, + Rule::FirstWordUncapitalized, Rule::FitsOnOneLine, Rule::IndentWithSpaces, Rule::MultiLineSummaryFirstLine, @@ -277,7 +277,7 @@ pub(crate) fn definitions(checker: &mut Checker) { if checker.enabled(Rule::NoSignature) { pydocstyle::rules::no_signature(checker, &docstring); } - if checker.enabled(Rule::FirstLineCapitalized) { + if checker.enabled(Rule::FirstWordUncapitalized) { pydocstyle::rules::capitalized(checker, &docstring); } if checker.enabled(Rule::DocstringStartsWithThis) { diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 13549898308d6..dcd2ca45d8f82 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -566,7 +566,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pydocstyle, "400") => (RuleGroup::Stable, rules::pydocstyle::rules::EndsInPeriod), (Pydocstyle, "401") => (RuleGroup::Stable, rules::pydocstyle::rules::NonImperativeMood), (Pydocstyle, "402") => (RuleGroup::Stable, rules::pydocstyle::rules::NoSignature), - (Pydocstyle, "403") => (RuleGroup::Stable, rules::pydocstyle::rules::FirstLineCapitalized), + (Pydocstyle, "403") => (RuleGroup::Stable, rules::pydocstyle::rules::FirstWordUncapitalized), (Pydocstyle, "404") => (RuleGroup::Stable, rules::pydocstyle::rules::DocstringStartsWithThis), (Pydocstyle, "405") => (RuleGroup::Stable, rules::pydocstyle::rules::CapitalizeSectionName), (Pydocstyle, "406") => (RuleGroup::Stable, rules::pydocstyle::rules::NewLineAfterSectionName), diff --git a/crates/ruff_linter/src/rules/perflint/rules/manual_list_comprehension.rs b/crates/ruff_linter/src/rules/perflint/rules/manual_list_comprehension.rs index 415f7313d005a..606c759727785 100644 --- a/crates/ruff_linter/src/rules/perflint/rules/manual_list_comprehension.rs +++ b/crates/ruff_linter/src/rules/perflint/rules/manual_list_comprehension.rs @@ -305,15 +305,19 @@ pub(crate) fn manual_list_comprehension(checker: &mut Checker, for_stmt: &ast::S }); // If the binding gets used in between the assignment and the for loop, a list comprehension is no longer safe - let binding_unused_between = list_binding_stmt.is_some_and(|binding_stmt| { - let from_assign_to_loop = TextRange::new(binding_stmt.end(), for_stmt.start()); - // Test if there's any reference to the list symbol between its definition and the for loop. - // if there's at least one, then it's been accessed in the middle somewhere, so it's not safe to change into a list comprehension - !list_binding - .references() - .map(|ref_id| checker.semantic().reference(ref_id).range()) - .any(|text_range| from_assign_to_loop.contains_range(text_range)) - }); + + // If the binding is after the for loop, then it can't be fixed, and this check would panic, + // so we check that they are in the same statement first + let binding_unused_between = assignment_in_same_statement + && list_binding_stmt.is_some_and(|binding_stmt| { + let from_assign_to_loop = TextRange::new(binding_stmt.end(), for_stmt.start()); + // Test if there's any reference to the list symbol between its definition and the for loop. + // if there's at least one, then it's been accessed in the middle somewhere, so it's not safe to change into a list comprehension + !list_binding + .references() + .map(|ref_id| checker.semantic().reference(ref_id).range()) + .any(|text_range| from_assign_to_loop.contains_range(text_range)) + }); // A list extend works in every context, while a list comprehension only works when all the criteria are true let comprehension_type = if binding_is_empty_list diff --git a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF401_PERF401.py.snap b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF401_PERF401.py.snap index e27274aa29e5b..2257cbe8b714a 100644 --- a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF401_PERF401.py.snap +++ b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF401_PERF401.py.snap @@ -1,6 +1,5 @@ --- source: crates/ruff_linter/src/rules/perflint/mod.rs -snapshot_kind: text --- PERF401.py:6:13: PERF401 Use a list comprehension to create a transformed list | @@ -189,5 +188,17 @@ PERF401.py:239:9: PERF401 Use a list comprehension to create a transformed list 238 | for a in values: 239 | result.append(a + 1) # PERF401 | ^^^^^^^^^^^^^^^^^^^^ PERF401 +240 | +241 | def f(): | = help: Replace for loop with list comprehension + +PERF401.py:245:13: PERF401 Use `list.extend` to create a transformed list + | +243 | def g(): +244 | for a in values: +245 | result.append(a + 1) # PERF401 + | ^^^^^^^^^^^^^^^^^^^^ PERF401 +246 | result = [] + | + = help: Replace for loop with list.extend diff --git a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__preview__PERF401_PERF401.py.snap b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__preview__PERF401_PERF401.py.snap index a8c6adde82002..e22129c2309d5 100644 --- a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__preview__PERF401_PERF401.py.snap +++ b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__preview__PERF401_PERF401.py.snap @@ -1,6 +1,5 @@ --- source: crates/ruff_linter/src/rules/perflint/mod.rs -snapshot_kind: text --- PERF401.py:6:13: PERF401 [*] Use a list comprehension to create a transformed list | @@ -448,6 +447,8 @@ PERF401.py:239:9: PERF401 [*] Use a list comprehension to create a transformed l 238 | for a in values: 239 | result.append(a + 1) # PERF401 | ^^^^^^^^^^^^^^^^^^^^ PERF401 +240 | +241 | def f(): | = help: Replace for loop with list comprehension @@ -461,3 +462,25 @@ PERF401.py:239:9: PERF401 [*] Use a list comprehension to create a transformed l 238 |- for a in values: 239 |- result.append(a + 1) # PERF401 237 |+ result = [a + 1 for a in values] # PERF401 +240 238 | +241 239 | def f(): +242 240 | values = [1, 2, 3] + +PERF401.py:245:13: PERF401 [*] Use `list.extend` to create a transformed list + | +243 | def g(): +244 | for a in values: +245 | result.append(a + 1) # PERF401 + | ^^^^^^^^^^^^^^^^^^^^ PERF401 +246 | result = [] + | + = help: Replace for loop with list.extend + +ℹ Unsafe fix +241 241 | def f(): +242 242 | values = [1, 2, 3] +243 243 | def g(): +244 |- for a in values: +245 |- result.append(a + 1) # PERF401 + 244 |+ result.extend(a + 1 for a in values) # PERF401 +246 245 | result = [] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs index 24f6cd90cf13c..a40931bcf9b5a 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs @@ -11,7 +11,7 @@ use crate::checkers::logical_lines::LogicalLinesContext; use super::{LogicalLine, Whitespace}; /// ## What it does -/// Checks for the use of extraneous whitespace after "(". +/// Checks for the use of extraneous whitespace after "(", "[" or "{". /// /// ## Why is this bad? /// [PEP 8] recommends the omission of whitespace in the following cases: @@ -50,7 +50,7 @@ impl AlwaysFixableViolation for WhitespaceAfterOpenBracket { } /// ## What it does -/// Checks for the use of extraneous whitespace before ")". +/// Checks for the use of extraneous whitespace before ")", "]" or "}". /// /// ## Why is this bad? /// [PEP 8] recommends the omission of whitespace in the following cases: diff --git a/crates/ruff_linter/src/rules/pydocstyle/mod.rs b/crates/ruff_linter/src/rules/pydocstyle/mod.rs index 9f387fdebb087..700633ff6955a 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/mod.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/mod.rs @@ -32,8 +32,8 @@ mod tests { #[test_case(Rule::EndsInPeriod, Path::new("D400_415.py"))] #[test_case(Rule::EndsInPunctuation, Path::new("D.py"))] #[test_case(Rule::EndsInPunctuation, Path::new("D400_415.py"))] - #[test_case(Rule::FirstLineCapitalized, Path::new("D.py"))] - #[test_case(Rule::FirstLineCapitalized, Path::new("D403.py"))] + #[test_case(Rule::FirstWordUncapitalized, Path::new("D.py"))] + #[test_case(Rule::FirstWordUncapitalized, Path::new("D403.py"))] #[test_case(Rule::FitsOnOneLine, Path::new("D.py"))] #[test_case(Rule::IndentWithSpaces, Path::new("D.py"))] #[test_case(Rule::UndocumentedMagicMethod, Path::new("D.py"))] diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/capitalized.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/capitalized.rs index dbb861b75b8ab..0c6e7a3154d85 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/capitalized.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/capitalized.rs @@ -10,8 +10,8 @@ use crate::docstrings::Docstring; /// Checks for docstrings that do not start with a capital letter. /// /// ## Why is this bad? -/// The first character in a docstring should be capitalized for, grammatical -/// correctness and consistency. +/// The first non-whitespace character in a docstring should be +/// capitalized for grammatical correctness and consistency. /// /// ## Example /// ```python @@ -30,16 +30,16 @@ use crate::docstrings::Docstring; /// - [NumPy Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html) /// - [Google Python Style Guide - Docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) #[derive(ViolationMetadata)] -pub(crate) struct FirstLineCapitalized { +pub(crate) struct FirstWordUncapitalized { first_word: String, capitalized_word: String, } -impl AlwaysFixableViolation for FirstLineCapitalized { +impl AlwaysFixableViolation for FirstWordUncapitalized { #[derive_message_formats] fn message(&self) -> String { format!( - "First word of the first line should be capitalized: `{}` -> `{}`", + "First word of the docstring should be capitalized: `{}` -> `{}`", self.first_word, self.capitalized_word ) } @@ -59,7 +59,8 @@ pub(crate) fn capitalized(checker: &mut Checker, docstring: &Docstring) { } let body = docstring.body(); - let first_word = body.split_once(' ').map_or_else( + let trim_start_body = body.trim_start(); + let first_word = trim_start_body.split_once(' ').map_or_else( || { // If the docstring is a single word, trim the punctuation marks because // it makes the ASCII test below fail. @@ -91,8 +92,10 @@ pub(crate) fn capitalized(checker: &mut Checker, docstring: &Docstring) { let capitalized_word = uppercase_first_char.to_string() + first_word_chars.as_str(); + let leading_whitespace_len = body.text_len() - trim_start_body.text_len(); + let mut diagnostic = Diagnostic::new( - FirstLineCapitalized { + FirstWordUncapitalized { first_word: first_word.to_string(), capitalized_word: capitalized_word.to_string(), }, @@ -101,7 +104,7 @@ pub(crate) fn capitalized(checker: &mut Checker, docstring: &Docstring) { diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( capitalized_word, - TextRange::at(body.start(), first_word.text_len()), + TextRange::at(body.start() + leading_whitespace_len, first_word.text_len()), ))); checker.diagnostics.push(diagnostic); diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D403_D403.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D403_D403.py.snap index 6faa93a9fa136..86fbe97384caf 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D403_D403.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D403_D403.py.snap @@ -1,8 +1,7 @@ --- source: crates/ruff_linter/src/rules/pydocstyle/mod.rs -snapshot_kind: text --- -D403.py:2:5: D403 [*] First word of the first line should be capitalized: `this` -> `This` +D403.py:2:5: D403 [*] First word of the docstring should be capitalized: `this` -> `This` | 1 | def bad_function(): 2 | """this docstring is not capitalized""" @@ -20,7 +19,7 @@ D403.py:2:5: D403 [*] First word of the first line should be capitalized: `this` 4 4 | def good_function(): 5 5 | """This docstring is capitalized.""" -D403.py:30:5: D403 [*] First word of the first line should be capitalized: `singleword` -> `Singleword` +D403.py:30:5: D403 [*] First word of the docstring should be capitalized: `singleword` -> `Singleword` | 29 | def single_word(): 30 | """singleword.""" @@ -40,11 +39,13 @@ D403.py:30:5: D403 [*] First word of the first line should be capitalized: `sing 32 32 | def single_word_no_dot(): 33 33 | """singleword""" -D403.py:33:5: D403 [*] First word of the first line should be capitalized: `singleword` -> `Singleword` +D403.py:33:5: D403 [*] First word of the docstring should be capitalized: `singleword` -> `Singleword` | 32 | def single_word_no_dot(): 33 | """singleword""" | ^^^^^^^^^^^^^^^^ D403 +34 | +35 | def first_word_lots_of_whitespace(): | = help: Capitalize `singleword` to `Singleword` @@ -54,3 +55,32 @@ D403.py:33:5: D403 [*] First word of the first line should be capitalized: `sing 32 32 | def single_word_no_dot(): 33 |- """singleword""" 33 |+ """Singleword""" +34 34 | +35 35 | def first_word_lots_of_whitespace(): +36 36 | """ + +D403.py:36:5: D403 [*] First word of the docstring should be capitalized: `here` -> `Here` + | +35 | def first_word_lots_of_whitespace(): +36 | """ + | _____^ +37 | | +38 | | +39 | | +40 | | here is the start of my docstring! +41 | | +42 | | What do you think? +43 | | """ + | |_______^ D403 + | + = help: Capitalize `here` to `Here` + +ℹ Safe fix +37 37 | +38 38 | +39 39 | +40 |- here is the start of my docstring! + 40 |+ Here is the start of my docstring! +41 41 | +42 42 | What do you think? +43 43 | """ diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index c2676da8252ec..4904246eedc0a 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -3386,6 +3386,24 @@ pub enum TypeParam { TypeVarTuple(TypeParamTypeVarTuple), } +impl TypeParam { + pub const fn name(&self) -> &Identifier { + match self { + Self::TypeVar(x) => &x.name, + Self::ParamSpec(x) => &x.name, + Self::TypeVarTuple(x) => &x.name, + } + } + + pub fn default(&self) -> Option<&Expr> { + match self { + Self::TypeVar(x) => x.default.as_deref(), + Self::ParamSpec(x) => x.default.as_deref(), + Self::TypeVarTuple(x) => x.default.as_deref(), + } + } +} + /// See also [TypeVar](https://docs.python.org/3/library/ast.html#ast.TypeVar) #[derive(Clone, Debug, PartialEq)] pub struct TypeParamTypeVar { diff --git a/crates/ruff_server/src/session/capabilities.rs b/crates/ruff_server/src/session/capabilities.rs index 001931f9e8bae..911457236d9de 100644 --- a/crates/ruff_server/src/session/capabilities.rs +++ b/crates/ruff_server/src/session/capabilities.rs @@ -37,18 +37,12 @@ impl ResolvedClientCapabilities { .and_then(|workspace_edit| workspace_edit.document_changes) .unwrap_or_default(); - let workspace_refresh = true; - - // TODO(jane): Once the bug involving workspace.diagnostic(s) deserialization has been fixed, - // uncomment this. - /* let workspace_refresh = client_capabilities .workspace .as_ref() - .and_then(|workspace| workspace.diagnostic.as_ref()) + .and_then(|workspace| workspace.diagnostics.as_ref()) .and_then(|diagnostic| diagnostic.refresh_support) .unwrap_or_default(); - */ let pull_diagnostics = client_capabilities .text_document diff --git a/docs/requirements-insiders.txt b/docs/requirements-insiders.txt index 83a6cccf356bc..eb3daf40caaa4 100644 --- a/docs/requirements-insiders.txt +++ b/docs/requirements-insiders.txt @@ -1,5 +1,5 @@ PyYAML==6.0.2 -ruff==0.8.2 +ruff==0.8.3 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 4b19ea659b6ae..605ee17a930a1 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ PyYAML==6.0.2 -ruff==0.8.2 +ruff==0.8.3 mkdocs==1.6.1 mkdocs-material==9.5.38 mkdocs-redirects==1.2.2 diff --git a/playground/api/package-lock.json b/playground/api/package-lock.json index 329eed03adf0c..184ca1e02f362 100644 --- a/playground/api/package-lock.json +++ b/playground/api/package-lock.json @@ -16,7 +16,7 @@ "@cloudflare/workers-types": "^4.20230801.0", "miniflare": "^3.20230801.1", "typescript": "^5.1.6", - "wrangler": "3.93.0" + "wrangler": "3.95.0" } }, "node_modules/@cloudflare/kv-asset-handler": { @@ -118,9 +118,9 @@ } }, "node_modules/@cloudflare/workers-shared": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.10.0.tgz", - "integrity": "sha512-j3EwZBc9ctavmFVOQT1gqztRO/Plx4ZR0LMEEOif+5YoCcuD1P7/NEjlODPMc5a1w+8+7A/H+Ci8Ihd55+x0Zw==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.11.0.tgz", + "integrity": "sha512-A+lQ8xp7992qSeMmuQ0ssL6CPmm+ZmAv6Ddikan0n1jjpMAic+97l7xtVIsswSn9iLMFPYQ9uNN/8Fl0AgARIQ==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { @@ -1453,14 +1453,14 @@ } }, "node_modules/wrangler": { - "version": "3.93.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.93.0.tgz", - "integrity": "sha512-+wfxjOrtm6YgDS+NdJkB6aiBIS3ED97mNRQmfrEShRJW4pVo4sWY6oQ1FsGT+j4tGHplrTbWCE6U5yTgjNW/lw==", + "version": "3.95.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.95.0.tgz", + "integrity": "sha512-3w5852i3FNyDz421K2Qk4v5L8jjwegO5O8E1+VAQmjnm82HFNxpIRUBq0bmM7CTLvOPI/Jjcmj/eAWjQBL7QYg==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", - "@cloudflare/workers-shared": "0.10.0", + "@cloudflare/workers-shared": "0.11.0", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@esbuild-plugins/node-modules-polyfill": "^0.2.2", "blake3-wasm": "^2.1.5", diff --git a/playground/api/package.json b/playground/api/package.json index a061d1405d6d0..dc57e86ed3c4f 100644 --- a/playground/api/package.json +++ b/playground/api/package.json @@ -5,7 +5,7 @@ "@cloudflare/workers-types": "^4.20230801.0", "miniflare": "^3.20230801.1", "typescript": "^5.1.6", - "wrangler": "3.93.0" + "wrangler": "3.95.0" }, "private": true, "scripts": { diff --git a/playground/package-lock.json b/playground/package-lock.json index c2608481fe0dd..c64ab4c417bce 100644 --- a/playground/package-lock.json +++ b/playground/package-lock.json @@ -1219,25 +1219,27 @@ } }, "node_modules/@types/react-dom": { - "version": "19.0.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.1.tgz", - "integrity": "sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==", + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.2.tgz", + "integrity": "sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==", "dev": true, - "dependencies": { - "@types/react": "*" + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.17.0.tgz", - "integrity": "sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.0.tgz", + "integrity": "sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.17.0", - "@typescript-eslint/type-utils": "8.17.0", - "@typescript-eslint/utils": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/type-utils": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1252,24 +1254,21 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.17.0.tgz", - "integrity": "sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.0.tgz", + "integrity": "sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==", "dev": true, + "license": "MITClause", "dependencies": { - "@typescript-eslint/scope-manager": "8.17.0", - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/typescript-estree": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "debug": "^4.3.4" }, "engines": { @@ -1280,22 +1279,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.17.0.tgz", - "integrity": "sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", + "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0" + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1306,13 +1302,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.17.0.tgz", - "integrity": "sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.0.tgz", + "integrity": "sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.17.0", - "@typescript-eslint/utils": "8.17.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/utils": "8.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1324,19 +1321,16 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.17.0.tgz", - "integrity": "sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", + "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1346,13 +1340,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.17.0.tgz", - "integrity": "sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", + "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1367,22 +1362,21 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.17.0.tgz", - "integrity": "sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.0.tgz", + "integrity": "sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.17.0", - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/typescript-estree": "8.17.0" + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1392,21 +1386,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.17.0.tgz", - "integrity": "sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", + "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/types": "8.18.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -1422,6 +1413,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3936,9 +3928,10 @@ } }, "node_modules/monaco-editor": { - "version": "0.52.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.0.tgz", - "integrity": "sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==" + "version": "0.52.2", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz", + "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==", + "license": "MIT" }, "node_modules/ms": { "version": "2.1.3", @@ -4753,6 +4746,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, diff --git a/scripts/generate_mkdocs.py b/scripts/generate_mkdocs.py index 612e3e35232dc..8a38f8c173399 100644 --- a/scripts/generate_mkdocs.py +++ b/scripts/generate_mkdocs.py @@ -157,7 +157,8 @@ def generate_rule_metadata(rule_doc: Path) -> None: "\n".join( [ "---", - f"description: {description}", + "description: |-", + f" {description}", "tags:", f"- {rule_code}", "---",