Compare commits

..

2 Commits

Author SHA1 Message Date
Brent Westbrook
59c6cb521d Bump 0.14.6 (#21558) 2025-11-21 09:00:56 -05:00
Alex Waygood
54dba15088 [ty] Improve debug messages when imports fail (#21555) 2025-11-21 13:45:57 +00:00
14 changed files with 102 additions and 59 deletions

View File

@@ -1,5 +1,48 @@
# Changelog
## 0.14.6
Released on 2025-11-21.
### Preview features
- \[`flake8-bandit`\] Support new PySNMP API paths (`S508`, `S509`) ([#21374](https://github.com/astral-sh/ruff/pull/21374))
### Bug fixes
- Adjust own-line comment placement between branches ([#21185](https://github.com/astral-sh/ruff/pull/21185))
- Avoid syntax error when formatting attribute expressions with outer parentheses, parenthesized value, and trailing comment on value ([#20418](https://github.com/astral-sh/ruff/pull/20418))
- Fix panic when formatting comments in unary expressions ([#21501](https://github.com/astral-sh/ruff/pull/21501))
- Respect `fmt: skip` for compound statements on a single line ([#20633](https://github.com/astral-sh/ruff/pull/20633))
- \[`refurb`\] Fix `FURB103` autofix ([#21454](https://github.com/astral-sh/ruff/pull/21454))
- \[`ruff`\] Fix false positive for complex conversion specifiers in `logging-eager-conversion` (`RUF065`) ([#21464](https://github.com/astral-sh/ruff/pull/21464))
### Rule changes
- \[`ruff`\] Avoid false positive on `ClassVar` reassignment (`RUF012`) ([#21478](https://github.com/astral-sh/ruff/pull/21478))
### CLI
- Render hyperlinks for lint errors ([#21514](https://github.com/astral-sh/ruff/pull/21514))
- Add a `ruff analyze` option to skip over imports in `TYPE_CHECKING` blocks ([#21472](https://github.com/astral-sh/ruff/pull/21472))
### Documentation
- Limit `eglot-format` hook to eglot-managed Python buffers ([#21459](https://github.com/astral-sh/ruff/pull/21459))
- Mention `force-exclude` in "Configuration > Python file discovery" ([#21500](https://github.com/astral-sh/ruff/pull/21500))
### Contributors
- [@ntBre](https://github.com/ntBre)
- [@dylwil3](https://github.com/dylwil3)
- [@gauthsvenkat](https://github.com/gauthsvenkat)
- [@MichaReiser](https://github.com/MichaReiser)
- [@thamer](https://github.com/thamer)
- [@Ruchir28](https://github.com/Ruchir28)
- [@thejcannon](https://github.com/thejcannon)
- [@danparizher](https://github.com/danparizher)
- [@chirizxc](https://github.com/chirizxc)
## 0.14.5
Released on 2025-11-13.

6
Cargo.lock generated
View File

@@ -2859,7 +2859,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.14.5"
version = "0.14.6"
dependencies = [
"anyhow",
"argfile",
@@ -3117,7 +3117,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.14.5"
version = "0.14.6"
dependencies = [
"aho-corasick",
"anyhow",
@@ -3472,7 +3472,7 @@ dependencies = [
[[package]]
name = "ruff_wasm"
version = "0.14.5"
version = "0.14.6"
dependencies = [
"console_error_panic_hook",
"console_log",

View File

@@ -147,8 +147,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
# For a specific version.
curl -LsSf https://astral.sh/ruff/0.14.5/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.14.5/install.ps1 | iex"
curl -LsSf https://astral.sh/ruff/0.14.6/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.14.6/install.ps1 | iex"
```
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
@@ -181,7 +181,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.5
rev: v0.14.6
hooks:
# Run the linter.
- id: ruff-check

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff"
version = "0.14.5"
version = "0.14.6"
publish = true
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_linter"
version = "0.14.5"
version = "0.14.6"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_wasm"
version = "0.14.5"
version = "0.14.6"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -389,8 +389,9 @@ ListOrTupleLegacy = Union[list[T], tuple[T, ...]]
MyCallable = Callable[P, T]
AnnotatedType = Annotated[T, "tag"]
reveal_type(MyList) # revealed: <class 'list[T]'>
reveal_type(MyDict) # revealed: <class 'dict[T, U]'>
# TODO: Consider displaying this as `<class 'list[T]'>`, … instead? (and similar for some others below)
reveal_type(MyList) # revealed: <class 'list[typing.TypeVar]'>
reveal_type(MyDict) # revealed: <class 'dict[typing.TypeVar, typing.TypeVar]'>
reveal_type(MyType) # revealed: GenericAlias
reveal_type(IntAndType) # revealed: <class 'tuple[int, typing.TypeVar]'>
reveal_type(Pair) # revealed: <class 'tuple[typing.TypeVar, typing.TypeVar]'>
@@ -495,9 +496,9 @@ def _(
my_callable: MyCallable,
):
# TODO: Should be `list[Unknown]`
reveal_type(my_list) # revealed: list[T]
reveal_type(my_list) # revealed: list[typing.TypeVar]
# TODO: Should be `dict[Unknown, Unknown]`
reveal_type(my_dict) # revealed: dict[T, U]
reveal_type(my_dict) # revealed: dict[typing.TypeVar, typing.TypeVar]
# TODO: Should be `(...) -> Unknown`
reveal_type(my_callable) # revealed: (...) -> typing.TypeVar
```
@@ -522,7 +523,7 @@ reveal_mro(Derived1)
GenericBaseAlias = GenericBase[T]
# TODO: No error here
# error: [non-subscriptable] "Cannot subscript object of type `<class 'GenericBase[T]'>` with no `__class_getitem__` method"
# error: [non-subscriptable] "Cannot subscript object of type `<class 'GenericBase[typing.TypeVar]'>` with no `__class_getitem__` method"
class Derived2(GenericBaseAlias[int]):
pass
```

View File

@@ -40,6 +40,8 @@ error[unresolved-import]: Cannot resolve imported module `....foo`
2 |
3 | stat = add(10, 15)
|
help: The module can be resolved if the number of leading dots is reduced
help: Did you mean `...foo`?
info: Searched in the following paths during module resolution:
info: 1. /src (first-party code)
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)

View File

@@ -7197,8 +7197,6 @@ impl<'db> Type<'db> {
instance.apply_type_mapping_impl(db, type_mapping, tcx, visitor)
},
Type::NewTypeInstance(_) if matches!(type_mapping, TypeMapping::BindLegacyTypevars(_)) => self,
Type::NewTypeInstance(newtype) => visitor.visit(self, || {
Type::NewTypeInstance(newtype.map_base_class_type(db, |class_type| {
class_type.apply_type_mapping_impl(db, type_mapping, tcx, visitor)
@@ -7277,8 +7275,6 @@ impl<'db> Type<'db> {
// TODO(jelle): Materialize should be handled differently, since TypeIs is invariant
Type::TypeIs(type_is) => type_is.with_type(db, type_is.return_type(db).apply_type_mapping(db, type_mapping, tcx)),
Type::TypeAlias(_) if matches!(type_mapping, TypeMapping::BindLegacyTypevars(_)) => self,
Type::TypeAlias(alias) => {
// Do not call `value_type` here. `value_type` does the specialization internally, so `apply_type_mapping` is performed without `visitor` inheritance.
// In the case of recursive type aliases, this leads to infinite recursion.

View File

@@ -101,14 +101,14 @@ use crate::types::typed_dict::{
};
use crate::types::visitor::any_over_type;
use crate::types::{
BindingContext, CallDunderError, CallableBinding, CallableType, ClassLiteral, ClassType,
DataclassParams, DynamicType, InternedType, IntersectionBuilder, IntersectionType, KnownClass,
CallDunderError, CallableBinding, CallableType, ClassLiteral, ClassType, DataclassParams,
DynamicType, InternedType, IntersectionBuilder, IntersectionType, KnownClass,
KnownInstanceType, LintDiagnosticGuard, MemberLookupPolicy, MetaclassCandidate,
PEP695TypeAliasType, Parameter, ParameterForm, Parameters, SpecialFormType, SubclassOfType,
TrackedConstraintSet, Truthiness, Type, TypeAliasType, TypeAndQualifiers, TypeContext,
TypeMapping, TypeQualifiers, TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation,
TypeVarIdentity, TypeVarInstance, TypeVarKind, TypeVarVariance, TypedDictType, UnionBuilder,
UnionType, UnionTypeInstance, binding_type, todo_type,
TypeQualifiers, TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation, TypeVarIdentity,
TypeVarInstance, TypeVarKind, TypeVarVariance, TypedDictType, UnionBuilder, UnionType,
UnionTypeInstance, binding_type, todo_type,
};
use crate::types::{ClassBase, add_inferred_python_version_hint_to_diagnostic};
use crate::unpack::{EvaluationMode, UnpackPosition};
@@ -5799,9 +5799,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
return;
};
let mut diagnostic = builder.into_diagnostic(format_args!(
"Cannot resolve imported module `{}{}`",
".".repeat(level as usize),
module.unwrap_or_default()
"Cannot resolve imported module `{}`",
format_import_from_module(level, module)
));
if level == 0 {
@@ -5832,6 +5831,30 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}
}
}
} else {
if let Some(better_level) = (0..level).rev().find(|reduced_level| {
let Ok(module_name) = ModuleName::from_identifier_parts(
self.db(),
self.file(),
module,
*reduced_level,
) else {
return false;
};
resolve_module(self.db(), &module_name).is_some()
}) {
diagnostic
.help("The module can be resolved if the number of leading dots is reduced");
diagnostic.help(format_args!(
"Did you mean `{}`?",
format_import_from_module(better_level, module)
));
diagnostic.set_concise_message(format_args!(
"Cannot resolve imported module `{}` - did you mean `{}`?",
format_import_from_module(level, module),
format_import_from_module(better_level, module)
));
}
}
// Add search paths information to the diagnostic
@@ -6039,7 +6062,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
}
Err(ModuleNameResolutionError::UnknownCurrentModule) => {
tracing::debug!(
"Relative module resolution `{}` failed; could not resolve file `{}` to a module",
"Relative module resolution `{}` failed: could not resolve file `{}` to a module \
(try adjusting configured search paths?)",
format_import_from_module(*level, module),
self.file().path(self.db())
);
@@ -11046,7 +11070,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
value_ty,
generic_context,
specialize,
true,
)
}
@@ -11071,7 +11094,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
value_ty,
generic_context,
specialize,
false,
)
}
@@ -11081,30 +11103,12 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
value_ty: Type<'db>,
generic_context: GenericContext<'db>,
specialize: impl FnOnce(&[Option<Type<'db>>]) -> Type<'db>,
bind_legacy_typevars: bool,
) -> Type<'db> {
let slice_node = subscript.slice.as_ref();
let db = self.db();
let do_bind_legacy_typevars = |ty: Type<'db>| {
if bind_legacy_typevars {
ty.apply_type_mapping(
db,
&TypeMapping::BindLegacyTypevars(BindingContext::Synthetic),
TypeContext::default(),
)
} else {
ty
}
};
let call_argument_types = match slice_node {
ast::Expr::Tuple(tuple) => {
let arguments = CallArguments::positional(
tuple
.elts
.iter()
.map(|elt| do_bind_legacy_typevars(self.infer_type_expression(elt))),
tuple.elts.iter().map(|elt| self.infer_type_expression(elt)),
);
self.store_expression_type(
slice_node,
@@ -11112,11 +11116,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
);
arguments
}
_ => CallArguments::positional([do_bind_legacy_typevars(
self.infer_type_expression(slice_node),
)]),
_ => CallArguments::positional([self.infer_type_expression(slice_node)]),
};
let binding = Binding::single(value_ty, generic_context.signature(self.db()));
let bindings = match Bindings::from(binding)
.match_parameters(self.db(), &call_argument_types)

View File

@@ -80,7 +80,7 @@ You can add the following configuration to `.gitlab-ci.yml` to run a `ruff forma
stage: build
interruptible: true
image:
name: ghcr.io/astral-sh/ruff:0.14.5-alpine
name: ghcr.io/astral-sh/ruff:0.14.6-alpine
before_script:
- cd $CI_PROJECT_DIR
- ruff --version
@@ -106,7 +106,7 @@ Ruff can be used as a [pre-commit](https://pre-commit.com) hook via [`ruff-pre-c
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.5
rev: v0.14.6
hooks:
# Run the linter.
- id: ruff-check
@@ -119,7 +119,7 @@ To enable lint fixes, add the `--fix` argument to the lint hook:
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.5
rev: v0.14.6
hooks:
# Run the linter.
- id: ruff-check
@@ -133,7 +133,7 @@ To avoid running on Jupyter Notebooks, remove `jupyter` from the list of allowed
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.5
rev: v0.14.6
hooks:
# Run the linter.
- id: ruff-check

View File

@@ -369,7 +369,7 @@ This tutorial has focused on Ruff's command-line interface, but Ruff can also be
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.5
rev: v0.14.6
hooks:
# Run the linter.
- id: ruff

View File

@@ -4,7 +4,7 @@ build-backend = "maturin"
[project]
name = "ruff"
version = "0.14.5"
version = "0.14.6"
description = "An extremely fast Python linter and code formatter, written in Rust."
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
readme = "README.md"

View File

@@ -1,6 +1,6 @@
[project]
name = "scripts"
version = "0.14.5"
version = "0.14.6"
description = ""
authors = ["Charles Marsh <charlie.r.marsh@gmail.com>"]