Skip to content

Commit

Permalink
Merge branch 'main' into dcreager/class-match
Browse files Browse the repository at this point in the history
* main:
  [`ruff`] Avoid reporting when `ndigits` is possibly negative (`RUF057`) (#15234)
  Attribute panics to the mdtests that cause them (#15241)
  Show errors for attempted fixes only when passed `--verbose` (#15237)
  [`RUF`] Add rule to detect empty literal in deque call (`RUF025`) (#15104)
  TD003: remove issue code length restriction (#15175)
  Preserve multiline implicit concatenated strings in docstring positions (#15126)
  [`pyflakes`] Ignore errors in `@no_type_check` string annotations (`F722`, `F821`) (#15215)
  style(AIR302): rename removed_airflow_plugin_extension as check_airflow_plugin_extension (#15233)
  [`pylint`] Re-implement `unreachable` (`PLW0101`) (#10891)
  refactor(AIR303): move duplicate qualified_name.to_string() to Diagnostic argument (#15220)
  Misc. clean up to rounding rules (#15231)
  Avoid syntax error when removing int over multiple lines (#15230)
  Migrate renovate config (#15228)
  Remove `Type::tuple` in favor of `TupleType::from_elements` (#15218)
  • Loading branch information
dcreager committed Jan 3, 2025
2 parents dcc2646 + 842f882 commit 0374a77
Show file tree
Hide file tree
Showing 74 changed files with 8,389 additions and 1,866 deletions.
10 changes: 5 additions & 5 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
groupName: "Artifact GitHub Actions dependencies",
matchManagers: ["github-actions"],
matchDatasources: ["gitea-tags", "github-tags"],
matchPackagePatterns: ["actions/.*-artifact"],
matchPackageNames: ["actions/.*-artifact"],
description: "Weekly update of artifact-related GitHub Actions dependencies",
},
{
Expand All @@ -61,7 +61,7 @@
{
// Disable updates of `zip-rs`; intentionally pinned for now due to ownership change
// See: https://github.com/astral-sh/uv/issues/3642
matchPackagePatterns: ["zip"],
matchPackageNames: ["zip"],
matchManagers: ["cargo"],
enabled: false,
},
Expand All @@ -70,7 +70,7 @@
// with `mkdocs-material-insider`.
// See: https://squidfunk.github.io/mkdocs-material/insiders/upgrade/
matchManagers: ["pip_requirements"],
matchPackagePatterns: ["mkdocs-material"],
matchPackageNames: ["mkdocs-material"],
enabled: false,
},
{
Expand All @@ -87,13 +87,13 @@
{
groupName: "Monaco",
matchManagers: ["npm"],
matchPackagePatterns: ["monaco"],
matchPackageNames: ["monaco"],
description: "Weekly update of the Monaco editor",
},
{
groupName: "strum",
matchManagers: ["cargo"],
matchPackagePatterns: ["strum"],
matchPackageNames: ["strum"],
description: "Weekly update of strum dependencies",
},
{
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 13 additions & 19 deletions crates/red_knot_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,13 +705,6 @@ impl<'db> Type<'db> {
Self::BytesLiteral(BytesLiteralType::new(db, bytes))
}

pub fn tuple<T: Into<Type<'db>>>(
db: &'db dyn Db,
elements: impl IntoIterator<Item = T>,
) -> Self {
TupleType::from_elements(db, elements)
}

#[must_use]
pub fn negate(&self, db: &'db dyn Db) -> Type<'db> {
IntersectionBuilder::new(db).add_negative(*self).build()
Expand Down Expand Up @@ -2118,15 +2111,16 @@ impl<'db> Type<'db> {
Type::Union(UnionType::new(db, elements))
};

let version_info_elements = &[
Type::IntLiteral(python_version.major.into()),
Type::IntLiteral(python_version.minor.into()),
int_instance_ty,
release_level_ty,
int_instance_ty,
];

Self::tuple(db, version_info_elements)
TupleType::from_elements(
db,
[
Type::IntLiteral(python_version.major.into()),
Type::IntLiteral(python_version.minor.into()),
int_instance_ty,
release_level_ty,
int_instance_ty,
],
)
}

/// Given a type that is assumed to represent an instance of a class,
Expand Down Expand Up @@ -3435,8 +3429,8 @@ impl<'db> Class<'db> {
/// The member resolves to a member on the class itself or any of its proper superclasses.
pub(crate) fn class_member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
if name == "__mro__" {
let tuple_elements: Vec<Type<'db>> = self.iter_mro(db).map(Type::from).collect();
return Type::tuple(db, &tuple_elements).into();
let tuple_elements = self.iter_mro(db).map(Type::from);
return TupleType::from_elements(db, tuple_elements).into();
}

for superclass in self.iter_mro(db) {
Expand Down Expand Up @@ -3846,7 +3840,7 @@ pub(crate) mod tests {
}
Ty::Tuple(tys) => {
let elements = tys.into_iter().map(|ty| ty.into_type(db));
Type::tuple(db, elements)
TupleType::from_elements(db, elements)
}
Ty::SubclassOfAny => Type::subclass_of_base(ClassBase::Any),
Ty::SubclassOfUnknown => Type::subclass_of_base(ClassBase::Unknown),
Expand Down
15 changes: 8 additions & 7 deletions crates/red_knot_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2672,10 +2672,12 @@ impl<'db> TypeInferenceBuilder<'db> {
parenthesized: _,
} = tuple;

let element_types: Vec<Type<'db>> =
elts.iter().map(|elt| self.infer_expression(elt)).collect();
// Collecting all elements is necessary to infer all sub-expressions even if some
// element types are `Never` (which leads `from_elements` to return early without
// consuming the whole iterator).
let element_types: Vec<_> = elts.iter().map(|elt| self.infer_expression(elt)).collect();

Type::tuple(self.db(), &element_types)
TupleType::from_elements(self.db(), element_types)
}

fn infer_list_expression(&mut self, list: &ast::ExprList) -> Type<'db> {
Expand Down Expand Up @@ -4239,8 +4241,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let (start, stop, step) = slice_ty.as_tuple(self.db());

if let Ok(new_elements) = elements.py_slice(start, stop, step) {
let new_elements: Vec<_> = new_elements.copied().collect();
Type::tuple(self.db(), &new_elements)
TupleType::from_elements(self.db(), new_elements)
} else {
report_slice_step_size_zero(&self.context, value_node.into());
Type::Unknown
Expand Down Expand Up @@ -4842,7 +4843,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let ty = if return_todo {
todo_type!("full tuple[...] support")
} else {
Type::tuple(self.db(), &element_types)
TupleType::from_elements(self.db(), element_types)
};

// Here, we store the type for the inner `int, str` tuple-expression,
Expand All @@ -4857,7 +4858,7 @@ impl<'db> TypeInferenceBuilder<'db> {
if element_could_alter_type_of_whole_tuple(single_element, single_element_ty) {
todo_type!("full tuple[...] support")
} else {
Type::tuple(self.db(), [single_element_ty])
TupleType::from_elements(self.db(), std::iter::once(single_element_ty))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/red_knot_python_semantic/src/types/unpacker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl<'db> Unpacker<'db> {
// with each individual character, instead of just an array of
// `LiteralString`, but there would be a cost and it's not clear that
// it's worth it.
Type::tuple(
TupleType::from_elements(
self.db(),
std::iter::repeat(Type::LiteralString)
.take(string_literal_ty.python_len(self.db())),
Expand Down
18 changes: 16 additions & 2 deletions crates/red_knot_test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use red_knot_python_semantic::types::check_types;
use red_knot_python_semantic::Program;
use ruff_db::diagnostic::{Diagnostic, ParseDiagnostic};
use ruff_db::files::{system_path_to_file, File, Files};
use ruff_db::panic::catch_unwind;
use ruff_db::parsed::parsed_module;
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
use ruff_db::testing::{setup_logging, setup_logging_with_filter};
use ruff_source_file::LineIndex;
use ruff_source_file::{LineIndex, OneIndexed};
use ruff_text_size::TextSize;
use salsa::Setter;

Expand Down Expand Up @@ -136,7 +137,20 @@ fn run_test(db: &mut db::Db, test: &parser::MarkdownTest) -> Result<(), Failures
})
.collect();

let type_diagnostics = check_types(db, test_file.file);
let type_diagnostics = match catch_unwind(|| check_types(db, test_file.file)) {
Ok(type_diagnostics) => type_diagnostics,
Err(info) => {
let mut by_line = matcher::FailuresByLine::default();
by_line.push(
OneIndexed::from_zero_indexed(0),
info.info.split('\n').map(String::from).collect(),
);
return Some(FileFailures {
backtick_offset: test_file.backtick_offset,
by_line,
});
}
};
diagnostics.extend(type_diagnostics.into_iter().map(|diagnostic| {
let diagnostic: Box<dyn Diagnostic> = Box::new((*diagnostic).clone());
diagnostic
Expand Down
2 changes: 1 addition & 1 deletion crates/red_knot_test/src/matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl FailuresByLine {
})
}

fn push(&mut self, line_number: OneIndexed, messages: Vec<String>) {
pub(super) fn push(&mut self, line_number: OneIndexed, messages: Vec<String>) {
let start = self.failures.len();
self.failures.extend(messages);
self.lines.push(LineFailures {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
Regression test that makes sure we do not short-circuit here after
determining that the overall type will be `Never` and still infer
a type for the second tuple element `2`.
Relevant discussion:
https://github.com/astral-sh/ruff/pull/15218#discussion_r1900811073
"""

from typing_extensions import Never


def never() -> Never:
return never()


(never(), 2)
2 changes: 1 addition & 1 deletion crates/ruff/src/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use log::{debug, error, warn};
use rayon::prelude::*;
use rustc_hash::FxHashMap;

use ruff_db::panic::catch_unwind;
use ruff_diagnostics::Diagnostic;
use ruff_linter::message::Message;
use ruff_linter::package::PackageRoot;
Expand All @@ -27,7 +28,6 @@ use ruff_workspace::resolver::{
use crate::args::ConfigArguments;
use crate::cache::{Cache, PackageCacheMap, PackageCaches};
use crate::diagnostics::Diagnostics;
use crate::panic::catch_unwind;

/// Run the linter over a collection of files.
#[allow(clippy::too_many_arguments)]
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff/src/commands/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use rustc_hash::FxHashSet;
use thiserror::Error;
use tracing::debug;

use ruff_db::panic::{catch_unwind, PanicError};
use ruff_diagnostics::SourceMap;
use ruff_linter::fs;
use ruff_linter::logging::{DisplayParseError, LogLevel};
Expand All @@ -32,7 +33,6 @@ use ruff_workspace::FormatterSettings;

use crate::args::{ConfigArguments, FormatArguments, FormatRange};
use crate::cache::{Cache, FileCacheKey, PackageCacheMap, PackageCaches};
use crate::panic::{catch_unwind, PanicError};
use crate::resolve::resolve;
use crate::{resolve_default_files, ExitStatus};

Expand Down
1 change: 0 additions & 1 deletion crates/ruff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub mod args;
mod cache;
mod commands;
mod diagnostics;
mod panic;
mod printer;
pub mod resolve;
mod stdin;
Expand Down
64 changes: 64 additions & 0 deletions crates/ruff/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2126,3 +2126,67 @@ unfixable = ["RUF"]

Ok(())
}

#[test]
fn verbose_show_failed_fix_errors() {
let mut cmd = RuffCheck::default()
.args(["--select", "UP006", "--preview", "-v"])
.build();

insta::with_settings!(
{
// the logs have timestamps we need to remove
filters => vec![(
r"\[[\d:-]+]",
""
)]
},{
assert_cmd_snapshot!(cmd
.pass_stdin("import typing\nCallable = 'abc'\ndef g() -> typing.Callable: ..."),
@r###"
success: false
exit_code: 1
----- stdout -----
-:3:12: UP006 Use `collections.abc.Callable` instead of `typing.Callable` for type annotation
|
1 | import typing
2 | Callable = 'abc'
3 | def g() -> typing.Callable: ...
| ^^^^^^^^^^^^^^^ UP006
|
= help: Replace with `collections.abc.Callable`
Found 1 error.
----- stderr -----
[ruff::resolve][DEBUG] Isolated mode, not reading any pyproject.toml
[ruff_diagnostics::diagnostic][DEBUG] Failed to create fix for NonPEP585Annotation: Unable to insert `Callable` into scope due to name conflict
"###); }
);
}

#[test]
fn no_verbose_hide_failed_fix_errors() {
let mut cmd = RuffCheck::default()
.args(["--select", "UP006", "--preview"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin("import typing\nCallable = 'abc'\ndef g() -> typing.Callable: ..."),
@r###"
success: false
exit_code: 1
----- stdout -----
-:3:12: UP006 Use `collections.abc.Callable` instead of `typing.Callable` for type annotation
|
1 | import typing
2 | Callable = 'abc'
3 | def g() -> typing.Callable: ...
| ^^^^^^^^^^^^^^^ UP006
|
= help: Replace with `collections.abc.Callable`
Found 1 error.
----- stderr -----
"###);
}
1 change: 1 addition & 0 deletions crates/ruff_db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod diagnostic;
pub mod display;
pub mod file_revision;
pub mod files;
pub mod panic;
pub mod parsed;
pub mod source;
pub mod system;
Expand Down
8 changes: 4 additions & 4 deletions crates/ruff/src/panic.rs → crates/ruff_db/src/panic.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[derive(Default, Debug)]
pub(crate) struct PanicError {
pub(crate) info: String,
pub(crate) backtrace: Option<std::backtrace::Backtrace>,
pub struct PanicError {
pub info: String,
pub backtrace: Option<std::backtrace::Backtrace>,
}

impl std::fmt::Display for PanicError {
Expand All @@ -21,7 +21,7 @@ thread_local! {

/// [`catch_unwind`](std::panic::catch_unwind) wrapper that sets a custom [`set_hook`](std::panic::set_hook)
/// to extract the backtrace. The original panic-hook gets restored before returning.
pub(crate) fn catch_unwind<F, R>(f: F) -> Result<R, PanicError>
pub fn catch_unwind<F, R>(f: F) -> Result<R, PanicError>
where
F: FnOnce() -> R + std::panic::UnwindSafe,
{
Expand Down
6 changes: 3 additions & 3 deletions crates/ruff_diagnostics/src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Result;
use log::error;
use log::debug;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -56,7 +56,7 @@ impl Diagnostic {
pub fn try_set_fix(&mut self, func: impl FnOnce() -> Result<Fix>) {
match func() {
Ok(fix) => self.fix = Some(fix),
Err(err) => error!("Failed to create fix for {}: {}", self.kind.name, err),
Err(err) => debug!("Failed to create fix for {}: {}", self.kind.name, err),
}
}

Expand All @@ -67,7 +67,7 @@ impl Diagnostic {
match func() {
Ok(None) => {}
Ok(Some(fix)) => self.fix = Some(fix),
Err(err) => error!("Failed to create fix for {}: {}", self.kind.name, err),
Err(err) => debug!("Failed to create fix for {}: {}", self.kind.name, err),
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/ruff_linter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ license = { workspace = true }
[dependencies]
ruff_cache = { workspace = true }
ruff_diagnostics = { workspace = true, features = ["serde"] }
ruff_index = { workspace = true }
ruff_notebook = { workspace = true }
ruff_macros = { workspace = true }
ruff_python_ast = { workspace = true, features = ["serde", "cache"] }
Expand Down
Loading

0 comments on commit 0374a77

Please sign in to comment.