Compare commits

..

1 Commits

Author SHA1 Message Date
Alex Waygood
1a30934c33 [ty] Cleanup various APIs 2025-10-30 16:52:13 -04:00
235 changed files with 1610 additions and 4339 deletions

View File

@@ -277,8 +277,8 @@ jobs:
run: cargo test -p ty_python_semantic --test mdtest || true
- name: "Run tests"
run: cargo insta test --all-features --unreferenced reject --test-runner nextest
- name: Dogfood ty on py-fuzzer
run: uv run --project=./python/py-fuzzer cargo run -p ty check --project=./python/py-fuzzer
# Dogfood ty on py-fuzzer
- run: uv run --project=./python/py-fuzzer cargo run -p ty check --project=./python/py-fuzzer
# Check for broken links in the documentation.
- run: cargo doc --all --no-deps
env:
@@ -649,7 +649,7 @@ jobs:
- determine_changes
# Only runs on pull requests, since that is the only we way we can find the base version for comparison.
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && github.event_name == 'pull_request' && (needs.determine_changes.outputs.ty == 'true' || needs.determine_changes.outputs.py-fuzzer == 'true') }}
timeout-minutes: ${{ github.repository == 'astral-sh/ruff' && 10 || 20 }}
timeout-minutes: ${{ github.repository == 'astral-sh/ruff' && 5 || 20 }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:

View File

@@ -1,60 +1,5 @@
# Changelog
## 0.14.3
Released on 2025-10-30.
### Preview features
- Respect `--output-format` with `--watch` ([#21097](https://github.com/astral-sh/ruff/pull/21097))
- \[`pydoclint`\] Fix false positive on explicit exception re-raising (`DOC501`, `DOC502`) ([#21011](https://github.com/astral-sh/ruff/pull/21011))
- \[`pyflakes`\] Revert to stable behavior if imports for module lie in alternate branches for `F401` ([#20878](https://github.com/astral-sh/ruff/pull/20878))
- \[`pylint`\] Implement `stop-iteration-return` (`PLR1708`) ([#20733](https://github.com/astral-sh/ruff/pull/20733))
- \[`ruff`\] Add support for additional eager conversion patterns (`RUF065`) ([#20657](https://github.com/astral-sh/ruff/pull/20657))
### Bug fixes
- Fix finding keyword range for clause header after statement ending with semicolon ([#21067](https://github.com/astral-sh/ruff/pull/21067))
- Fix syntax error false positive on nested alternative patterns ([#21104](https://github.com/astral-sh/ruff/pull/21104))
- \[`ISC001`\] Fix panic when string literals are unclosed ([#21034](https://github.com/astral-sh/ruff/pull/21034))
- \[`flake8-django`\] Apply `DJ001` to annotated fields ([#20907](https://github.com/astral-sh/ruff/pull/20907))
- \[`flake8-pyi`\] Fix `PYI034` to not trigger on metaclasses (`PYI034`) ([#20881](https://github.com/astral-sh/ruff/pull/20881))
- \[`flake8-type-checking`\] Fix `TC003` false positive with `future-annotations` ([#21125](https://github.com/astral-sh/ruff/pull/21125))
- \[`pyflakes`\] Fix false positive for `__class__` in lambda expressions within class definitions (`F821`) ([#20564](https://github.com/astral-sh/ruff/pull/20564))
- \[`pyupgrade`\] Fix false positive for `TypeVar` with default on Python \<3.13 (`UP046`,`UP047`) ([#21045](https://github.com/astral-sh/ruff/pull/21045))
### Rule changes
- Add missing docstring sections to the numpy list ([#20931](https://github.com/astral-sh/ruff/pull/20931))
- \[`airflow`\] Extend `airflow.models..Param` check (`AIR311`) ([#21043](https://github.com/astral-sh/ruff/pull/21043))
- \[`airflow`\] Warn that `airflow....DAG.create_dagrun` has been removed (`AIR301`) ([#21093](https://github.com/astral-sh/ruff/pull/21093))
- \[`refurb`\] Preserve digit separators in `Decimal` constructor (`FURB157`) ([#20588](https://github.com/astral-sh/ruff/pull/20588))
### Server
- Avoid sending an unnecessary "clear diagnostics" message for clients supporting pull diagnostics ([#21105](https://github.com/astral-sh/ruff/pull/21105))
### Documentation
- \[`flake8-bandit`\] Fix correct example for `S308` ([#21128](https://github.com/astral-sh/ruff/pull/21128))
### Other changes
- Clearer error message when `line-length` goes beyond threshold ([#21072](https://github.com/astral-sh/ruff/pull/21072))
### Contributors
- [@danparizher](https://github.com/danparizher)
- [@jvacek](https://github.com/jvacek)
- [@ntBre](https://github.com/ntBre)
- [@augustelalande](https://github.com/augustelalande)
- [@prakhar1144](https://github.com/prakhar1144)
- [@TaKO8Ki](https://github.com/TaKO8Ki)
- [@dylwil3](https://github.com/dylwil3)
- [@fatelei](https://github.com/fatelei)
- [@ShaharNaveh](https://github.com/ShaharNaveh)
- [@Lee-W](https://github.com/Lee-W)
## 0.14.2
Released on 2025-10-23.

44
Cargo.lock generated
View File

@@ -243,7 +243,7 @@ dependencies = [
"bitflags 2.9.4",
"cexpr",
"clang-sys",
"itertools 0.13.0",
"itertools 0.10.5",
"log",
"prettyplease",
"proc-macro2",
@@ -633,7 +633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -642,7 +642,7 @@ version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
dependencies = [
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -1007,7 +1007,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.61.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -1093,7 +1093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -1115,12 +1115,13 @@ dependencies = [
[[package]]
name = "etcetera"
version = "0.11.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96"
checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6"
dependencies = [
"cfg-if",
"windows-sys 0.61.0",
"home",
"windows-sys 0.59.0",
]
[[package]]
@@ -1365,6 +1366,15 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
[[package]]
name = "home"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "html-escape"
version = "0.2.13"
@@ -1553,7 +1563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
dependencies = [
"equivalent",
"hashbrown 0.16.0",
"hashbrown 0.15.5",
"serde",
"serde_core",
]
@@ -1680,7 +1690,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -1744,7 +1754,7 @@ dependencies = [
"portable-atomic",
"portable-atomic-util",
"serde",
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -2825,7 +2835,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.14.3"
version = "0.14.2"
dependencies = [
"anyhow",
"argfile",
@@ -3082,7 +3092,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.14.3"
version = "0.14.2"
dependencies = [
"aho-corasick",
"anyhow",
@@ -3437,7 +3447,7 @@ dependencies = [
[[package]]
name = "ruff_wasm"
version = "0.14.3"
version = "0.14.2"
dependencies = [
"console_error_panic_hook",
"console_log",
@@ -3535,7 +3545,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -3931,7 +3941,7 @@ dependencies = [
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.61.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -5011,7 +5021,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.0",
"windows-sys 0.52.0",
]
[[package]]

View File

@@ -5,7 +5,7 @@ resolver = "2"
[workspace.package]
# Please update rustfmt.toml when bumping the Rust edition
edition = "2024"
rust-version = "1.89"
rust-version = "1.88"
homepage = "https://docs.astral.sh/ruff"
documentation = "https://docs.astral.sh/ruff"
repository = "https://github.com/astral-sh/ruff"
@@ -84,7 +84,7 @@ dashmap = { version = "6.0.1" }
dir-test = { version = "0.4.0" }
dunce = { version = "1.0.5" }
drop_bomb = { version = "0.1.5" }
etcetera = { version = "0.11.0" }
etcetera = { version = "0.10.0" }
fern = { version = "0.7.0" }
filetime = { version = "0.2.23" }
getrandom = { version = "0.3.1" }

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.3/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.14.3/install.ps1 | iex"
curl -LsSf https://astral.sh/ruff/0.14.2/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.14.2/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.3
rev: v0.14.2
hooks:
# Run the linter.
- id: ruff-check

View File

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

View File

@@ -7,7 +7,6 @@ use path_absolutize::CWD;
use ruff_db::system::{SystemPath, SystemPathBuf};
use ruff_graph::{Direction, ImportMap, ModuleDb, ModuleImports};
use ruff_linter::package::PackageRoot;
use ruff_linter::source_kind::SourceKind;
use ruff_linter::{warn_user, warn_user_once};
use ruff_python_ast::{PySourceType, SourceType};
use ruff_workspace::resolver::{ResolvedFile, match_exclusion, python_files_in_path};
@@ -128,6 +127,10 @@ pub(crate) fn analyze_graph(
},
Some(language) => PySourceType::from(language),
};
if matches!(source_type, PySourceType::Ipynb) {
debug!("Ignoring Jupyter notebook: {}", path.display());
continue;
}
// Convert to system paths.
let Ok(package) = package.map(SystemPathBuf::from_path_buf).transpose() else {
@@ -144,34 +147,13 @@ pub(crate) fn analyze_graph(
let root = root.clone();
let result = inner_result.clone();
scope.spawn(move |_| {
// Extract source code (handles both .py and .ipynb files)
let source_kind = match SourceKind::from_path(path.as_std_path(), source_type) {
Ok(Some(source_kind)) => source_kind,
Ok(None) => {
debug!("Skipping non-Python notebook: {path}");
return;
}
Err(err) => {
warn!("Failed to read source for {path}: {err}");
return;
}
};
let source_code = source_kind.source_code();
// Identify any imports via static analysis.
let mut imports = ModuleImports::detect(
&db,
source_code,
source_type,
&path,
package.as_deref(),
string_imports,
)
.unwrap_or_else(|err| {
warn!("Failed to generate import map for {path}: {err}");
ModuleImports::default()
});
let mut imports =
ModuleImports::detect(&db, &path, package.as_deref(), string_imports)
.unwrap_or_else(|err| {
warn!("Failed to generate import map for {path}: {err}");
ModuleImports::default()
});
debug!("Discovered {} imports for {}", imports.len(), path);

View File

@@ -370,7 +370,7 @@ pub(crate) fn format_source(
let line_index = LineIndex::from_source_text(unformatted);
let byte_range = range.to_text_range(unformatted, &line_index);
format_range(unformatted, byte_range, options).map(|formatted_range| {
let mut formatted = unformatted.clone();
let mut formatted = unformatted.to_string();
formatted.replace_range(
std::ops::Range::<usize>::from(formatted_range.source_range()),
formatted_range.as_code(),

View File

@@ -653,133 +653,3 @@ fn venv() -> Result<()> {
Ok(())
}
#[test]
fn notebook_basic() -> Result<()> {
let tempdir = TempDir::new()?;
let root = ChildPath::new(tempdir.path());
root.child("ruff").child("__init__.py").write_str("")?;
root.child("ruff")
.child("a.py")
.write_str(indoc::indoc! {r#"
def helper():
pass
"#})?;
// Create a basic notebook with a simple import
root.child("notebook.ipynb").write_str(indoc::indoc! {r#"
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from ruff.a import helper"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"version": "3.12.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
"#})?;
insta::with_settings!({
filters => INSTA_FILTERS.to_vec(),
}, {
assert_cmd_snapshot!(command().current_dir(&root), @r###"
success: true
exit_code: 0
----- stdout -----
{
"notebook.ipynb": [
"ruff/a.py"
],
"ruff/__init__.py": [],
"ruff/a.py": []
}
----- stderr -----
"###);
});
Ok(())
}
#[test]
fn notebook_with_magic() -> Result<()> {
let tempdir = TempDir::new()?;
let root = ChildPath::new(tempdir.path());
root.child("ruff").child("__init__.py").write_str("")?;
root.child("ruff")
.child("a.py")
.write_str(indoc::indoc! {r#"
def helper():
pass
"#})?;
// Create a notebook with IPython magic commands and imports
root.child("notebook.ipynb").write_str(indoc::indoc! {r#"
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from ruff.a import helper"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"version": "3.12.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
"#})?;
insta::with_settings!({
filters => INSTA_FILTERS.to_vec(),
}, {
assert_cmd_snapshot!(command().current_dir(&root), @r###"
success: true
exit_code: 0
----- stdout -----
{
"notebook.ipynb": [
"ruff/a.py"
],
"ruff/__init__.py": [],
"ruff/a.py": []
}
----- stderr -----
"###);
});
Ok(())
}

View File

@@ -470,11 +470,6 @@ impl File {
self.source_type(db).is_stub()
}
/// Returns `true` if the file is an `__init__.pyi`
pub fn is_package_stub(self, db: &dyn Db) -> bool {
self.path(db).as_str().ends_with("__init__.pyi")
}
pub fn source_type(self, db: &dyn Db) -> PySourceType {
match self.path(db) {
FilePath::System(path) => path

View File

@@ -723,11 +723,10 @@ impl ruff_cache::CacheKey for SystemPathBuf {
/// A slice of a virtual path on [`System`](super::System) (akin to [`str`]).
#[repr(transparent)]
#[derive(Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct SystemVirtualPath(str);
impl SystemVirtualPath {
pub const fn new(path: &str) -> &SystemVirtualPath {
pub fn new(path: &str) -> &SystemVirtualPath {
// SAFETY: SystemVirtualPath is marked as #[repr(transparent)] so the conversion from a
// *const str to a *const SystemVirtualPath is valid.
unsafe { &*(path as *const str as *const SystemVirtualPath) }
@@ -768,8 +767,8 @@ pub struct SystemVirtualPathBuf(String);
impl SystemVirtualPathBuf {
#[inline]
pub const fn as_path(&self) -> &SystemVirtualPath {
SystemVirtualPath::new(self.0.as_str())
pub fn as_path(&self) -> &SystemVirtualPath {
SystemVirtualPath::new(&self.0)
}
}
@@ -853,12 +852,6 @@ impl ruff_cache::CacheKey for SystemVirtualPathBuf {
}
}
impl Borrow<SystemVirtualPath> for SystemVirtualPathBuf {
fn borrow(&self) -> &SystemVirtualPath {
self.as_path()
}
}
/// Deduplicates identical paths and removes nested paths.
///
/// # Examples

View File

@@ -62,7 +62,7 @@ fn generate_set(output: &mut String, set: Set, parents: &mut Vec<Set>) {
generate_set(
output,
Set::Named {
name: set_name.clone(),
name: set_name.to_string(),
set: *sub_set,
},
parents,

View File

@@ -104,7 +104,7 @@ fn generate_set(output: &mut String, set: Set, parents: &mut Vec<Set>) {
generate_set(
output,
Set::Named {
name: set_name.clone(),
name: set_name.to_string(),
set: *sub_set,
},
parents,

View File

@@ -1006,7 +1006,7 @@ impl<Context> std::fmt::Debug for Align<'_, Context> {
/// Block indents indent a block of code, such as in a function body, and therefore insert a line
/// break before and after the content.
///
/// Doesn't create an indentation if the passed in content is empty.
/// Doesn't create an indentation if the passed in content is [`FormatElement.is_empty`].
///
/// # Examples
///

View File

@@ -3,9 +3,8 @@ use std::collections::{BTreeMap, BTreeSet};
use anyhow::Result;
use ruff_db::system::{SystemPath, SystemPathBuf};
use ruff_python_ast::PySourceType;
use ruff_python_ast::helpers::to_module_path;
use ruff_python_parser::{ParseOptions, parse};
use ruff_python_parser::{Mode, ParseOptions, parse};
use crate::collector::Collector;
pub use crate::db::ModuleDb;
@@ -25,14 +24,13 @@ impl ModuleImports {
/// Detect the [`ModuleImports`] for a given Python file.
pub fn detect(
db: &ModuleDb,
source: &str,
source_type: PySourceType,
path: &SystemPath,
package: Option<&SystemPath>,
string_imports: StringImports,
) -> Result<Self> {
// Parse the source code.
let parsed = parse(source, ParseOptions::from(source_type))?;
// Read and parse the source code.
let source = std::fs::read_to_string(path)?;
let parsed = parse(&source, ParseOptions::from(Mode::Module))?;
let module_path =
package.and_then(|package| to_module_path(package.as_std_path(), path.as_std_path()));

View File

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

View File

@@ -145,11 +145,3 @@ with open("file.txt", "w") as f:
with open("file.txt", "w") as f:
for line in text:
f.write(line)
# See: https://github.com/astral-sh/ruff/issues/20785
import json
data = {"price": 100}
with open("test.json", "wb") as f:
f.write(json.dumps(data, indent=4).encode("utf-8"))

View File

@@ -4,4 +4,4 @@ expression: content
---
syntax_errors.py:
1:15 invalid-syntax: Expected one or more symbol names after import
3:12 invalid-syntax: Expected `)`, found newline
3:12 invalid-syntax: Expected ')', found newline

View File

@@ -78,7 +78,7 @@ pub(crate) fn unconventional_import_alias(
let mut diagnostic = checker.report_diagnostic(
UnconventionalImportAlias {
name: qualified_name,
asname: expected_alias.clone(),
asname: expected_alias.to_string(),
},
binding.range(),
);

View File

@@ -6,17 +6,21 @@ use ruff_macros::CacheKey;
#[derive(Clone, Copy, Debug, CacheKey, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
pub enum ParametrizeNameType {
#[serde(rename = "csv")]
Csv,
#[serde(rename = "tuple")]
#[default]
Tuple,
#[serde(rename = "list")]
List,
}
impl Default for ParametrizeNameType {
fn default() -> Self {
Self::Tuple
}
}
impl Display for ParametrizeNameType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
@@ -29,15 +33,19 @@ impl Display for ParametrizeNameType {
#[derive(Clone, Copy, Debug, CacheKey, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
pub enum ParametrizeValuesType {
#[serde(rename = "tuple")]
Tuple,
#[serde(rename = "list")]
#[default]
List,
}
impl Default for ParametrizeValuesType {
fn default() -> Self {
Self::List
}
}
impl Display for ParametrizeValuesType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
@@ -49,15 +57,19 @@ impl Display for ParametrizeValuesType {
#[derive(Clone, Copy, Debug, CacheKey, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
pub enum ParametrizeValuesRowType {
#[serde(rename = "tuple")]
#[default]
Tuple,
#[serde(rename = "list")]
List,
}
impl Default for ParametrizeValuesRowType {
fn default() -> Self {
Self::Tuple
}
}
impl Display for ParametrizeValuesRowType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {

View File

@@ -9,15 +9,19 @@ use ruff_macros::CacheKey;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, CacheKey)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
pub enum Quote {
/// Use double quotes.
#[default]
Double,
/// Use single quotes.
Single,
}
impl Default for Quote {
fn default() -> Self {
Self::Double
}
}
impl From<ruff_python_ast::str::Quote> for Quote {
fn from(value: ruff_python_ast::str::Quote) -> Self {
match value {

View File

@@ -116,7 +116,7 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &Checker, stmt: &Stmt) {
let mut diagnostic = checker.report_diagnostic(
ReimplementedBuiltin {
replacement: contents.clone(),
replacement: contents.to_string(),
},
TextRange::new(stmt.start(), terminal.stmt.end()),
);
@@ -212,7 +212,7 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &Checker, stmt: &Stmt) {
let mut diagnostic = checker.report_diagnostic(
ReimplementedBuiltin {
replacement: contents.clone(),
replacement: contents.to_string(),
},
TextRange::new(stmt.start(), terminal.stmt.end()),
);

View File

@@ -47,7 +47,7 @@ pub(crate) fn banned_api<T: Ranged>(checker: &Checker, policy: &NameMatchPolicy,
checker.report_diagnostic(
BannedApi {
name: banned_module,
message: reason.msg.clone(),
message: reason.msg.to_string(),
},
node.range(),
);
@@ -74,8 +74,8 @@ pub(crate) fn banned_attribute_access(checker: &Checker, expr: &Expr) {
{
checker.report_diagnostic(
BannedApi {
name: banned_path.clone(),
message: ban.msg.clone(),
name: banned_path.to_string(),
message: ban.msg.to_string(),
},
expr.range(),
);

View File

@@ -20,17 +20,21 @@ use super::categorize::ImportSection;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, CacheKey)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
pub enum RelativeImportsOrder {
/// Place "closer" imports (fewer `.` characters, most local) before
/// "further" imports (more `.` characters, least local).
ClosestToFurthest,
/// Place "further" imports (more `.` characters, least local) imports
/// before "closer" imports (fewer `.` characters, most local).
#[default]
FurthestToClosest,
}
impl Default for RelativeImportsOrder {
fn default() -> Self {
Self::FurthestToClosest
}
}
impl Display for RelativeImportsOrder {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {

View File

@@ -427,7 +427,7 @@ pub(crate) fn literal_comparisons(checker: &Checker, compare: &ast::ExprCompare)
for diagnostic in &mut diagnostics {
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
content.clone(),
content.to_string(),
compare.range(),
)));
}

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:2:7
|
1 | #: E231
@@ -18,7 +18,7 @@ help: Add missing whitespace
4 | a[b1,:]
5 | #: E231
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:4:5
|
2 | a = (1,2)
@@ -38,7 +38,7 @@ help: Add missing whitespace
6 | a = [{'a':''}]
7 | #: Okay
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:6:10
|
4 | a[b1,:]
@@ -58,7 +58,7 @@ help: Add missing whitespace
8 | a = (4,)
9 | b = (5, )
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:19:10
|
17 | def foo() -> None:
@@ -77,7 +77,7 @@ help: Add missing whitespace
21 |
22 | #: Okay
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:29:20
|
27 | mdtypes_template = {
@@ -96,7 +96,7 @@ help: Add missing whitespace
31 |
32 | # E231
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:33:6
|
32 | # E231
@@ -115,7 +115,7 @@ help: Add missing whitespace
35 | # Okay because it's hard to differentiate between the usages of a colon in a f-string
36 | f"{a:=1}"
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:47:37
|
46 | #: E231
@@ -134,7 +134,7 @@ help: Add missing whitespace
49 | #: Okay
50 | a = (1,)
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:60:13
|
58 | results = {
@@ -154,7 +154,7 @@ help: Add missing whitespace
62 | results_in_tuple = (
63 | {
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:65:17
|
63 | {
@@ -174,7 +174,7 @@ help: Add missing whitespace
67 | )
68 | results_in_list = [
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:71:17
|
69 | {
@@ -194,7 +194,7 @@ help: Add missing whitespace
73 | ]
74 | results_in_list_first = [
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:76:17
|
74 | results_in_list_first = [
@@ -214,7 +214,7 @@ help: Add missing whitespace
78 | ]
79 |
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:82:13
|
80 | x = [
@@ -234,7 +234,7 @@ help: Add missing whitespace
84 | "k3":[2], # E231
85 | "k4": [2],
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:84:13
|
82 | "k1":[2], # E231
@@ -254,7 +254,7 @@ help: Add missing whitespace
86 | "k5": [2],
87 | "k6": [1, 2, 3, 4,5,6,7] # E231
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:87:26
|
85 | "k4": [2],
@@ -274,7 +274,7 @@ help: Add missing whitespace
89 | {
90 | "k1": [
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:87:28
|
85 | "k4": [2],
@@ -294,7 +294,7 @@ help: Add missing whitespace
89 | {
90 | "k1": [
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:87:30
|
85 | "k4": [2],
@@ -314,7 +314,7 @@ help: Add missing whitespace
89 | {
90 | "k1": [
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:92:21
|
90 | "k1": [
@@ -334,7 +334,7 @@ help: Add missing whitespace
94 | {
95 | "kb": [2,3], # E231
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:92:24
|
90 | "k1": [
@@ -354,7 +354,7 @@ help: Add missing whitespace
94 | {
95 | "kb": [2,3], # E231
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:95:25
|
93 | },
@@ -374,7 +374,7 @@ help: Add missing whitespace
97 | {
98 | "ka":[2, 3], # E231
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:98:21
|
96 | },
@@ -394,7 +394,7 @@ help: Add missing whitespace
100 | "kc": [2, 3], # Ok
101 | "kd": [2,3], # E231
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:101:25
|
99 | "kb": [2, 3], # Ok
@@ -414,7 +414,7 @@ help: Add missing whitespace
103 | },
104 | ]
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:102:21
|
100 | "kc": [2, 3], # Ok
@@ -434,7 +434,7 @@ help: Add missing whitespace
104 | ]
105 | }
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:102:24
|
100 | "kc": [2, 3], # Ok
@@ -454,7 +454,7 @@ help: Add missing whitespace
104 | ]
105 | }
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:109:18
|
108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults
@@ -473,7 +473,7 @@ help: Add missing whitespace
111 | y:B = [[["foo", "bar"]]],
112 | z:object = "fooo",
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:109:40
|
108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults
@@ -492,7 +492,7 @@ help: Add missing whitespace
111 | y:B = [[["foo", "bar"]]],
112 | z:object = "fooo",
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:109:70
|
108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults
@@ -511,7 +511,7 @@ help: Add missing whitespace
111 | y:B = [[["foo", "bar"]]],
112 | z:object = "fooo",
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:110:6
|
108 | # Should be E231 errors on all of these type parameters and function parameters, but not on their (strange) defaults
@@ -531,7 +531,7 @@ help: Add missing whitespace
112 | z:object = "fooo",
113 | ):
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:111:6
|
109 | def pep_696_bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](
@@ -551,7 +551,7 @@ help: Add missing whitespace
113 | ):
114 | pass
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:112:6
|
110 | x:A = "foo"[::-1],
@@ -571,7 +571,7 @@ help: Add missing whitespace
114 | pass
115 |
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:116:18
|
114 | pass
@@ -591,7 +591,7 @@ help: Add missing whitespace
118 | self,
119 | x:A = "foo"[::-1],
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:116:40
|
114 | pass
@@ -611,7 +611,7 @@ help: Add missing whitespace
118 | self,
119 | x:A = "foo"[::-1],
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:116:70
|
114 | pass
@@ -631,7 +631,7 @@ help: Add missing whitespace
118 | self,
119 | x:A = "foo"[::-1],
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:117:29
|
116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]:
@@ -650,7 +650,7 @@ help: Add missing whitespace
119 | x:A = "foo"[::-1],
120 | y:B = [[["foo", "bar"]]],
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:117:51
|
116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]:
@@ -669,7 +669,7 @@ help: Add missing whitespace
119 | x:A = "foo"[::-1],
120 | y:B = [[["foo", "bar"]]],
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:117:81
|
116 | class PEP696Bad[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]:
@@ -688,7 +688,7 @@ help: Add missing whitespace
119 | x:A = "foo"[::-1],
120 | y:B = [[["foo", "bar"]]],
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:119:10
|
117 | def pep_696_bad_method[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes](
@@ -708,7 +708,7 @@ help: Add missing whitespace
121 | z:object = "fooo",
122 | ):
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:120:10
|
118 | self,
@@ -728,7 +728,7 @@ help: Add missing whitespace
122 | ):
123 | pass
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:121:10
|
119 | x:A = "foo"[::-1],
@@ -748,7 +748,7 @@ help: Add missing whitespace
123 | pass
124 |
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:125:32
|
123 | pass
@@ -768,7 +768,7 @@ help: Add missing whitespace
127 | pass
128 |
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:125:54
|
123 | pass
@@ -788,7 +788,7 @@ help: Add missing whitespace
127 | pass
128 |
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:125:84
|
123 | pass
@@ -808,7 +808,7 @@ help: Add missing whitespace
127 | pass
128 |
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:126:47
|
125 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]():
@@ -826,7 +826,7 @@ help: Add missing whitespace
128 |
129 | # Should be no E231 errors on any of these:
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:126:69
|
125 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]():
@@ -844,7 +844,7 @@ help: Add missing whitespace
128 |
129 | # Should be no E231 errors on any of these:
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:126:99
|
125 | class PEP696BadWithEmptyBases[A:object="foo"[::-1], B:object =[[["foo", "bar"]]], C:object= bytes]():
@@ -862,7 +862,7 @@ help: Add missing whitespace
128 |
129 | # Should be no E231 errors on any of these:
E231 [*] Missing whitespace after `,`
E231 [*] Missing whitespace after ','
--> E23.py:147:6
|
146 | # E231
@@ -881,7 +881,7 @@ help: Add missing whitespace
149 | # Okay because it's hard to differentiate between the usages of a colon in a t-string
150 | t"{a:=1}"
E231 [*] Missing whitespace after `:`
E231 [*] Missing whitespace after ':'
--> E23.py:161:37
|
160 | #: E231

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
invalid-syntax: Expected `]`, found `(`
invalid-syntax: Expected ']', found '('
--> E30_syntax_error.py:4:15
|
2 | # parenthesis.
@@ -11,7 +11,7 @@ invalid-syntax: Expected `]`, found `(`
5 | pass
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:13:18
|
12 | class Foo:
@@ -32,7 +32,7 @@ E301 Expected 1 blank line, found 0
|
help: Add missing blank line
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:18:11
|
16 | pass
@@ -41,7 +41,7 @@ invalid-syntax: Expected `)`, found newline
| ^
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:21:9
|
21 | def top(

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
invalid-syntax: Expected `]`, found `(`
invalid-syntax: Expected ']', found '('
--> E30_syntax_error.py:4:15
|
2 | # parenthesis.
@@ -22,7 +22,7 @@ E302 Expected 2 blank lines, found 1
|
help: Add missing blank line(s)
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:13:18
|
12 | class Foo:
@@ -32,7 +32,7 @@ invalid-syntax: Expected `)`, found newline
15 | def method():
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:18:11
|
16 | pass
@@ -41,7 +41,7 @@ invalid-syntax: Expected `)`, found newline
| ^
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:21:9
|
21 | def top(

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
invalid-syntax: Expected `]`, found `(`
invalid-syntax: Expected ']', found '('
--> E30_syntax_error.py:4:15
|
2 | # parenthesis.
@@ -21,7 +21,7 @@ E303 Too many blank lines (3)
|
help: Remove extraneous blank line(s)
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:13:18
|
12 | class Foo:
@@ -31,7 +31,7 @@ invalid-syntax: Expected `)`, found newline
15 | def method():
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:18:11
|
16 | pass
@@ -40,7 +40,7 @@ invalid-syntax: Expected `)`, found newline
| ^
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:21:9
|
21 | def top(

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
invalid-syntax: Expected `]`, found `(`
invalid-syntax: Expected ']', found '('
--> E30_syntax_error.py:4:15
|
2 | # parenthesis.
@@ -11,7 +11,7 @@ invalid-syntax: Expected `]`, found `(`
5 | pass
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:13:18
|
12 | class Foo:
@@ -31,7 +31,7 @@ E305 Expected 2 blank lines after class or function definition, found (1)
|
help: Add missing blank line(s)
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:18:11
|
16 | pass
@@ -40,7 +40,7 @@ invalid-syntax: Expected `)`, found newline
| ^
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:21:9
|
21 | def top(

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
invalid-syntax: Expected `]`, found `(`
invalid-syntax: Expected ']', found '('
--> E30_syntax_error.py:4:15
|
2 | # parenthesis.
@@ -11,7 +11,7 @@ invalid-syntax: Expected `]`, found `(`
5 | pass
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:13:18
|
12 | class Foo:
@@ -21,7 +21,7 @@ invalid-syntax: Expected `)`, found newline
15 | def method():
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:18:11
|
16 | pass
@@ -30,7 +30,7 @@ invalid-syntax: Expected `)`, found newline
| ^
|
invalid-syntax: Expected `)`, found newline
invalid-syntax: Expected ')', found newline
--> E30_syntax_error.py:21:9
|
21 | def top(

View File

@@ -94,7 +94,7 @@ pub(crate) fn capitalized(checker: &Checker, docstring: &Docstring) {
let mut diagnostic = checker.report_diagnostic(
FirstWordUncapitalized {
first_word: first_word.to_string(),
capitalized_word: capitalized_word.clone(),
capitalized_word: capitalized_word.to_string(),
},
docstring.range(),
);

View File

@@ -188,7 +188,7 @@ pub(crate) fn bit_count(checker: &Checker, call: &ExprCall) {
let mut diagnostic = checker.report_diagnostic(
BitCount {
existing: SourceCodeSnippet::from_str(literal_text),
replacement: SourceCodeSnippet::new(replacement.clone()),
replacement: SourceCodeSnippet::new(replacement.to_string()),
},
call.range(),
);

View File

@@ -5,6 +5,7 @@ use ruff_python_ast::{
relocate::relocate_expr,
visitor::{self, Visitor},
};
use ruff_python_codegen::Generator;
use ruff_text_size::{Ranged, TextRange};

View File

@@ -134,14 +134,3 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(fo
75 | f.write(foobar)
|
help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
FURB103 `open` and `write` should be replaced by `Path("test.json")....`
--> FURB103.py:154:6
|
152 | data = {"price": 100}
153 |
154 | with open("test.json", "wb") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
155 | f.write(json.dumps(data, indent=4).encode("utf-8"))
|
help: Replace with `Path("test.json")....`

View File

@@ -257,25 +257,4 @@ help: Replace with `Path("file.txt").write_text(foobar, newline="\r\n")`
75 + pathlib.Path("file.txt").write_text(foobar, newline="\r\n")
76 |
77 | # Non-errors.
78 |
FURB103 [*] `open` and `write` should be replaced by `Path("test.json")....`
--> FURB103.py:154:6
|
152 | data = {"price": 100}
153 |
154 | with open("test.json", "wb") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
155 | f.write(json.dumps(data, indent=4).encode("utf-8"))
|
help: Replace with `Path("test.json")....`
148 |
149 | # See: https://github.com/astral-sh/ruff/issues/20785
150 | import json
151 + import pathlib
152 |
153 | data = {"price": 100}
154 |
- with open("test.json", "wb") as f:
- f.write(json.dumps(data, indent=4).encode("utf-8"))
155 + pathlib.Path("test.json").write_bytes(json.dumps(data, indent=4).encode("utf-8"))
78 |

View File

@@ -104,14 +104,3 @@ FURB103 `open` and `write` should be replaced by `Path("file.txt").write_text(ba
51 | # writes a single time to file and that bit they can replace.
|
help: Replace with `Path("file.txt").write_text(bar(bar(a + x)))`
FURB103 `open` and `write` should be replaced by `Path("test.json")....`
--> FURB103.py:154:6
|
152 | data = {"price": 100}
153 |
154 | with open("test.json", "wb") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
155 | f.write(json.dumps(data, indent=4).encode("utf-8"))
|
help: Replace with `Path("test.json")....`

View File

@@ -3372,7 +3372,7 @@ impl Arguments {
pub fn arguments_source_order(&self) -> impl Iterator<Item = ArgOrKeyword<'_>> {
let args = self.args.iter().map(ArgOrKeyword::Arg);
let keywords = self.keywords.iter().map(ArgOrKeyword::Keyword);
args.merge_by(keywords, |left, right| left.start() <= right.start())
args.merge_by(keywords, |left, right| left.start() < right.start())
}
pub fn inner_range(&self) -> TextRange {

View File

@@ -335,96 +335,3 @@ def overload4():
# trailing comment
def overload4(a: int): ...
# In preview, we preserve these newlines at the start of functions:
def preserved1():
return 1
def preserved2():
pass
def preserved3():
def inner(): ...
def preserved4():
def inner():
print("with a body")
return 1
return 2
def preserved5():
...
# trailing comment prevents collapsing the stub
def preserved6():
# Comment
return 1
def preserved7():
# comment
# another line
# and a third
return 0
def preserved8(): # this also prevents collapsing the stub
...
# But we still discard these newlines:
def removed1():
"Docstring"
return 1
def removed2():
...
def removed3():
... # trailing same-line comment does not prevent collapsing the stub
# And we discard empty lines after the first:
def partially_preserved1():
return 1
# We only preserve blank lines, not add new ones
def untouched1():
# comment
return 0
def untouched2():
# comment
return 0
def untouched3():
# comment
# another line
# and a third
return 0

View File

@@ -61,9 +61,3 @@ def test6 ():
print("Format" )
print(3 + 4)<RANGE_END>
print("Format to fix indentation" )
def test7 ():
<RANGE_START>print("Format" )
print(3 + 4)<RANGE_END>
print("Format to fix indentation" )

View File

@@ -334,7 +334,7 @@ class A: ...
let options = PyFormatOptions::from_source_type(source_type);
let printed = format_range(&source, TextRange::new(start, end), options).unwrap();
let mut formatted = source.clone();
let mut formatted = source.to_string();
formatted.replace_range(
std::ops::Range::<usize>::from(printed.source_range()),
printed.as_code(),

View File

@@ -36,10 +36,3 @@ pub(crate) const fn is_remove_parens_around_except_types_enabled(
) -> bool {
context.is_preview()
}
/// Returns `true` if the
/// [`allow_newline_after_block_open`](https://github.com/astral-sh/ruff/pull/21110) preview style
/// is enabled.
pub(crate) const fn is_allow_newline_after_block_open_enabled(context: &PyFormatContext) -> bool {
context.is_preview()
}

View File

@@ -8,7 +8,7 @@ use ruff_python_trivia::{SimpleToken, SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::comments::{SourceComment, leading_alternate_branch_comments, trailing_comments};
use crate::statement::suite::{SuiteKind, as_only_an_ellipsis};
use crate::statement::suite::{SuiteKind, contains_only_an_ellipsis};
use crate::verbatim::write_suppressed_clause_header;
use crate::{has_skip_comment, prelude::*};
@@ -449,10 +449,17 @@ impl Format<PyFormatContext<'_>> for FormatClauseBody<'_> {
|| matches!(self.kind, SuiteKind::Function | SuiteKind::Class);
if should_collapse_stub
&& let Some(ellipsis) = as_only_an_ellipsis(self.body, f.context().comments())
&& contains_only_an_ellipsis(self.body, f.context().comments())
&& self.trailing_comments.is_empty()
{
write!(f, [space(), ellipsis.format(), hard_line_break()])
write!(
f,
[
space(),
self.body.format().with_options(self.kind),
hard_line_break()
]
)
} else {
write!(
f,

View File

@@ -13,9 +13,7 @@ use crate::comments::{
use crate::context::{NodeLevel, TopLevelStatementPosition, WithIndentLevel, WithNodeLevel};
use crate::other::string_literal::StringLiteralKind;
use crate::prelude::*;
use crate::preview::{
is_allow_newline_after_block_open_enabled, is_blank_line_before_decorated_class_in_stub_enabled,
};
use crate::preview::is_blank_line_before_decorated_class_in_stub_enabled;
use crate::statement::stmt_expr::FormatStmtExpr;
use crate::verbatim::{
suppressed_node, write_suppressed_statements_starting_with_leading_comment,
@@ -171,22 +169,6 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
false,
)
} else {
// Allow an empty line after a function header in preview, if the function has no
// docstring and no initial comment.
let allow_newline_after_block_open =
is_allow_newline_after_block_open_enabled(f.context())
&& matches!(self.kind, SuiteKind::Function)
&& matches!(first, SuiteChildStatement::Other(_));
let start = comments
.leading(first)
.first()
.map_or_else(|| first.start(), Ranged::start);
if allow_newline_after_block_open && lines_before(start, f.context().source()) > 1 {
empty_line().fmt(f)?;
}
first.fmt(f)?;
let empty_line_after_docstring = if matches!(first, SuiteChildStatement::Docstring(_))
@@ -236,7 +218,7 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
)?;
} else {
// Preserve empty lines after a stub implementation but don't insert a new one if there isn't any present in the source.
// This is useful when having multiple function overloads that should be grouped together by omitting new lines between them.
// This is useful when having multiple function overloads that should be grouped to getter by omitting new lines between them.
let is_preceding_stub_function_without_empty_line = following
.is_function_def_stmt()
&& preceding
@@ -746,21 +728,17 @@ fn stub_suite_can_omit_empty_line(preceding: &Stmt, following: &Stmt, f: &PyForm
/// Returns `true` if a function or class body contains only an ellipsis with no comments.
pub(crate) fn contains_only_an_ellipsis(body: &[Stmt], comments: &Comments) -> bool {
as_only_an_ellipsis(body, comments).is_some()
}
/// Returns `Some(Stmt::Ellipsis)` if a function or class body contains only an ellipsis with no
/// comments.
pub(crate) fn as_only_an_ellipsis<'a>(body: &'a [Stmt], comments: &Comments) -> Option<&'a Stmt> {
if let [node @ Stmt::Expr(ast::StmtExpr { value, .. })] = body
&& value.is_ellipsis_literal_expr()
&& !comments.has_leading(node)
&& !comments.has_trailing_own_line(node)
{
return Some(node);
match body {
[Stmt::Expr(ast::StmtExpr { value, .. })] => {
let [node] = body else {
return false;
};
value.is_ellipsis_literal_expr()
&& !comments.has_leading(node)
&& !comments.has_trailing_own_line(node)
}
_ => false,
}
None
}
/// Returns `true` if a [`Stmt`] is a class or function definition.

View File

@@ -1,6 +1,7 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/newlines.py
snapshot_kind: text
---
## Input
```python
@@ -341,99 +342,6 @@ def overload4():
# trailing comment
def overload4(a: int): ...
# In preview, we preserve these newlines at the start of functions:
def preserved1():
return 1
def preserved2():
pass
def preserved3():
def inner(): ...
def preserved4():
def inner():
print("with a body")
return 1
return 2
def preserved5():
...
# trailing comment prevents collapsing the stub
def preserved6():
# Comment
return 1
def preserved7():
# comment
# another line
# and a third
return 0
def preserved8(): # this also prevents collapsing the stub
...
# But we still discard these newlines:
def removed1():
"Docstring"
return 1
def removed2():
...
def removed3():
... # trailing same-line comment does not prevent collapsing the stub
# And we discard empty lines after the first:
def partially_preserved1():
return 1
# We only preserve blank lines, not add new ones
def untouched1():
# comment
return 0
def untouched2():
# comment
return 0
def untouched3():
# comment
# another line
# and a third
return 0
```
## Output
@@ -824,88 +732,6 @@ def overload4():
def overload4(a: int): ...
# In preview, we preserve these newlines at the start of functions:
def preserved1():
return 1
def preserved2():
pass
def preserved3():
def inner(): ...
def preserved4():
def inner():
print("with a body")
return 1
return 2
def preserved5():
...
# trailing comment prevents collapsing the stub
def preserved6():
# Comment
return 1
def preserved7():
# comment
# another line
# and a third
return 0
def preserved8(): # this also prevents collapsing the stub
...
# But we still discard these newlines:
def removed1():
"Docstring"
return 1
def removed2(): ...
def removed3(): ... # trailing same-line comment does not prevent collapsing the stub
# And we discard empty lines after the first:
def partially_preserved1():
return 1
# We only preserve blank lines, not add new ones
def untouched1():
# comment
return 0
def untouched2():
# comment
return 0
def untouched3():
# comment
# another line
# and a third
return 0
```
@@ -913,15 +739,7 @@ def untouched3():
```diff
--- Stable
+++ Preview
@@ -253,6 +253,7 @@
def fakehttp():
+
class FakeHTTPConnection:
if mock_close:
@@ -277,6 +278,7 @@
@@ -277,6 +277,7 @@
def a():
return 1
@@ -929,7 +747,7 @@ def untouched3():
else:
pass
@@ -293,6 +295,7 @@
@@ -293,6 +294,7 @@
def a():
return 1
@@ -937,7 +755,7 @@ def untouched3():
case 1:
def a():
@@ -303,6 +306,7 @@
@@ -303,6 +305,7 @@
def a():
return 1
@@ -945,7 +763,7 @@ def untouched3():
except RuntimeError:
def a():
@@ -313,6 +317,7 @@
@@ -313,6 +316,7 @@
def a():
return 1
@@ -953,7 +771,7 @@ def untouched3():
finally:
def a():
@@ -323,18 +328,22 @@
@@ -323,18 +327,22 @@
def a():
return 1
@@ -976,64 +794,4 @@ def untouched3():
finally:
def a():
@@ -388,18 +397,22 @@
# In preview, we preserve these newlines at the start of functions:
def preserved1():
+
return 1
def preserved2():
+
pass
def preserved3():
+
def inner(): ...
def preserved4():
+
def inner():
print("with a body")
return 1
@@ -408,17 +421,20 @@
def preserved5():
+
...
# trailing comment prevents collapsing the stub
def preserved6():
+
# Comment
return 1
def preserved7():
+
# comment
# another line
# and a third
@@ -427,6 +443,7 @@
def preserved8(): # this also prevents collapsing the stub
+
...
@@ -445,6 +462,7 @@
# And we discard empty lines after the first:
def partially_preserved1():
+
return 1
```

View File

@@ -67,12 +67,6 @@ def test6 ():
print("Format" )
print(3 + 4)<RANGE_END>
print("Format to fix indentation" )
def test7 ():
<RANGE_START>print("Format" )
print(3 + 4)<RANGE_END>
print("Format to fix indentation" )
```
## Outputs
@@ -152,27 +146,6 @@ def test6 ():
print("Format")
print(3 + 4)
print("Format to fix indentation" )
def test7 ():
print("Format")
print(3 + 4)
print("Format to fix indentation" )
```
#### Preview changes
```diff
--- Stable
+++ Preview
@@ -55,6 +55,7 @@
def test6 ():
+
print("Format")
print(3 + 4)
print("Format to fix indentation" )
```
@@ -252,27 +225,6 @@ def test6 ():
print("Format")
print(3 + 4)
print("Format to fix indentation")
def test7 ():
print("Format")
print(3 + 4)
print("Format to fix indentation")
```
#### Preview changes
```diff
--- Stable
+++ Preview
@@ -55,6 +55,7 @@
def test6 ():
+
print("Format")
print(3 + 4)
print("Format to fix indentation")
```
@@ -352,25 +304,4 @@ def test6 ():
print("Format")
print(3 + 4)
print("Format to fix indentation")
def test7 ():
print("Format")
print(3 + 4)
print("Format to fix indentation")
```
#### Preview changes
```diff
--- Stable
+++ Preview
@@ -55,6 +55,7 @@
def test6 ():
+
print("Format")
print(3 + 4)
print("Format to fix indentation")
```

View File

@@ -78,9 +78,9 @@ pub enum InterpolatedStringErrorType {
impl std::fmt::Display for InterpolatedStringErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::UnclosedLbrace => write!(f, "expecting `}}`"),
Self::UnclosedLbrace => write!(f, "expecting '}}'"),
Self::InvalidConversionFlag => write!(f, "invalid conversion character"),
Self::SingleRbrace => write!(f, "single `}}` is not allowed"),
Self::SingleRbrace => write!(f, "single '}}' is not allowed"),
Self::UnterminatedString => write!(f, "unterminated string"),
Self::UnterminatedTripleQuotedString => write!(f, "unterminated triple-quoted string"),
Self::LambdaWithoutParentheses => {
@@ -232,7 +232,7 @@ impl std::fmt::Display for ParseErrorType {
ParseErrorType::UnexpectedTokenAfterAsync(kind) => {
write!(
f,
"Expected `def`, `with` or `for` to follow `async`, found {kind}",
"Expected 'def', 'with' or 'for' to follow 'async', found {kind}",
)
}
ParseErrorType::InvalidArgumentUnpackingOrder => {
@@ -286,10 +286,10 @@ impl std::fmt::Display for ParseErrorType {
f.write_str("Parameter without a default cannot follow a parameter with a default")
}
ParseErrorType::ExpectedKeywordParam => {
f.write_str("Expected one or more keyword parameter after `*` separator")
f.write_str("Expected one or more keyword parameter after '*' separator")
}
ParseErrorType::VarParameterWithDefault => {
f.write_str("Parameter with `*` or `**` cannot have default value")
f.write_str("Parameter with '*' or '**' cannot have default value")
}
ParseErrorType::InvalidStarPatternUsage => {
f.write_str("Star pattern cannot be used here")

View File

@@ -635,93 +635,93 @@ impl fmt::Display for TokenKind {
TokenKind::TStringEnd => "TStringEnd",
TokenKind::IpyEscapeCommand => "IPython escape command",
TokenKind::Comment => "comment",
TokenKind::Question => "`?`",
TokenKind::Exclamation => "`!`",
TokenKind::Lpar => "`(`",
TokenKind::Rpar => "`)`",
TokenKind::Lsqb => "`[`",
TokenKind::Rsqb => "`]`",
TokenKind::Lbrace => "`{`",
TokenKind::Rbrace => "`}`",
TokenKind::Equal => "`=`",
TokenKind::ColonEqual => "`:=`",
TokenKind::Dot => "`.`",
TokenKind::Colon => "`:`",
TokenKind::Semi => "`;`",
TokenKind::Comma => "`,`",
TokenKind::Rarrow => "`->`",
TokenKind::Plus => "`+`",
TokenKind::Minus => "`-`",
TokenKind::Star => "`*`",
TokenKind::DoubleStar => "`**`",
TokenKind::Slash => "`/`",
TokenKind::DoubleSlash => "`//`",
TokenKind::Percent => "`%`",
TokenKind::Vbar => "`|`",
TokenKind::Amper => "`&`",
TokenKind::CircumFlex => "`^`",
TokenKind::LeftShift => "`<<`",
TokenKind::RightShift => "`>>`",
TokenKind::Tilde => "`~`",
TokenKind::At => "`@`",
TokenKind::Less => "`<`",
TokenKind::Greater => "`>`",
TokenKind::EqEqual => "`==`",
TokenKind::NotEqual => "`!=`",
TokenKind::LessEqual => "`<=`",
TokenKind::GreaterEqual => "`>=`",
TokenKind::PlusEqual => "`+=`",
TokenKind::MinusEqual => "`-=`",
TokenKind::StarEqual => "`*=`",
TokenKind::DoubleStarEqual => "`**=`",
TokenKind::SlashEqual => "`/=`",
TokenKind::DoubleSlashEqual => "`//=`",
TokenKind::PercentEqual => "`%=`",
TokenKind::VbarEqual => "`|=`",
TokenKind::AmperEqual => "`&=`",
TokenKind::CircumflexEqual => "`^=`",
TokenKind::LeftShiftEqual => "`<<=`",
TokenKind::RightShiftEqual => "`>>=`",
TokenKind::AtEqual => "`@=`",
TokenKind::Ellipsis => "`...`",
TokenKind::False => "`False`",
TokenKind::None => "`None`",
TokenKind::True => "`True`",
TokenKind::And => "`and`",
TokenKind::As => "`as`",
TokenKind::Assert => "`assert`",
TokenKind::Async => "`async`",
TokenKind::Await => "`await`",
TokenKind::Break => "`break`",
TokenKind::Class => "`class`",
TokenKind::Continue => "`continue`",
TokenKind::Def => "`def`",
TokenKind::Del => "`del`",
TokenKind::Elif => "`elif`",
TokenKind::Else => "`else`",
TokenKind::Except => "`except`",
TokenKind::Finally => "`finally`",
TokenKind::For => "`for`",
TokenKind::From => "`from`",
TokenKind::Global => "`global`",
TokenKind::If => "`if`",
TokenKind::Import => "`import`",
TokenKind::In => "`in`",
TokenKind::Is => "`is`",
TokenKind::Lambda => "`lambda`",
TokenKind::Nonlocal => "`nonlocal`",
TokenKind::Not => "`not`",
TokenKind::Or => "`or`",
TokenKind::Pass => "`pass`",
TokenKind::Raise => "`raise`",
TokenKind::Return => "`return`",
TokenKind::Try => "`try`",
TokenKind::While => "`while`",
TokenKind::Match => "`match`",
TokenKind::Type => "`type`",
TokenKind::Case => "`case`",
TokenKind::With => "`with`",
TokenKind::Yield => "`yield`",
TokenKind::Question => "'?'",
TokenKind::Exclamation => "'!'",
TokenKind::Lpar => "'('",
TokenKind::Rpar => "')'",
TokenKind::Lsqb => "'['",
TokenKind::Rsqb => "']'",
TokenKind::Lbrace => "'{'",
TokenKind::Rbrace => "'}'",
TokenKind::Equal => "'='",
TokenKind::ColonEqual => "':='",
TokenKind::Dot => "'.'",
TokenKind::Colon => "':'",
TokenKind::Semi => "';'",
TokenKind::Comma => "','",
TokenKind::Rarrow => "'->'",
TokenKind::Plus => "'+'",
TokenKind::Minus => "'-'",
TokenKind::Star => "'*'",
TokenKind::DoubleStar => "'**'",
TokenKind::Slash => "'/'",
TokenKind::DoubleSlash => "'//'",
TokenKind::Percent => "'%'",
TokenKind::Vbar => "'|'",
TokenKind::Amper => "'&'",
TokenKind::CircumFlex => "'^'",
TokenKind::LeftShift => "'<<'",
TokenKind::RightShift => "'>>'",
TokenKind::Tilde => "'~'",
TokenKind::At => "'@'",
TokenKind::Less => "'<'",
TokenKind::Greater => "'>'",
TokenKind::EqEqual => "'=='",
TokenKind::NotEqual => "'!='",
TokenKind::LessEqual => "'<='",
TokenKind::GreaterEqual => "'>='",
TokenKind::PlusEqual => "'+='",
TokenKind::MinusEqual => "'-='",
TokenKind::StarEqual => "'*='",
TokenKind::DoubleStarEqual => "'**='",
TokenKind::SlashEqual => "'/='",
TokenKind::DoubleSlashEqual => "'//='",
TokenKind::PercentEqual => "'%='",
TokenKind::VbarEqual => "'|='",
TokenKind::AmperEqual => "'&='",
TokenKind::CircumflexEqual => "'^='",
TokenKind::LeftShiftEqual => "'<<='",
TokenKind::RightShiftEqual => "'>>='",
TokenKind::AtEqual => "'@='",
TokenKind::Ellipsis => "'...'",
TokenKind::False => "'False'",
TokenKind::None => "'None'",
TokenKind::True => "'True'",
TokenKind::And => "'and'",
TokenKind::As => "'as'",
TokenKind::Assert => "'assert'",
TokenKind::Async => "'async'",
TokenKind::Await => "'await'",
TokenKind::Break => "'break'",
TokenKind::Class => "'class'",
TokenKind::Continue => "'continue'",
TokenKind::Def => "'def'",
TokenKind::Del => "'del'",
TokenKind::Elif => "'elif'",
TokenKind::Else => "'else'",
TokenKind::Except => "'except'",
TokenKind::Finally => "'finally'",
TokenKind::For => "'for'",
TokenKind::From => "'from'",
TokenKind::Global => "'global'",
TokenKind::If => "'if'",
TokenKind::Import => "'import'",
TokenKind::In => "'in'",
TokenKind::Is => "'is'",
TokenKind::Lambda => "'lambda'",
TokenKind::Nonlocal => "'nonlocal'",
TokenKind::Not => "'not'",
TokenKind::Or => "'or'",
TokenKind::Pass => "'pass'",
TokenKind::Raise => "'raise'",
TokenKind::Return => "'return'",
TokenKind::Try => "'try'",
TokenKind::While => "'while'",
TokenKind::Match => "'match'",
TokenKind::Type => "'type'",
TokenKind::Case => "'case'",
TokenKind::With => "'with'",
TokenKind::Yield => "'yield'",
};
f.write_str(value)
}

View File

@@ -131,7 +131,7 @@ Module(
|
1 | assert *x
2 | assert assert x
| ^^^^^^ Syntax Error: Expected an identifier, but found a keyword `assert` that cannot be used here
| ^^^^^^ Syntax Error: Expected an identifier, but found a keyword 'assert' that cannot be used here
3 | assert yield x
4 | assert x := 1
|

View File

@@ -148,7 +148,7 @@ Module(
|
1 | a = pass = c
| ^^^^ Syntax Error: Expected an identifier, but found a keyword `pass` that cannot be used here
| ^^^^ Syntax Error: Expected an identifier, but found a keyword 'pass' that cannot be used here
2 | a + b
3 | a = b = pass = c
|
@@ -158,6 +158,6 @@ Module(
1 | a = pass = c
2 | a + b
3 | a = b = pass = c
| ^^^^ Syntax Error: Expected an identifier, but found a keyword `pass` that cannot be used here
| ^^^^ Syntax Error: Expected an identifier, but found a keyword 'pass' that cannot be used here
4 | a + b
|

View File

@@ -181,7 +181,7 @@ Module(
|
1 | async class Foo: ...
| ^^^^^ Syntax Error: Expected `def`, `with` or `for` to follow `async`, found `class`
| ^^^^^ Syntax Error: Expected 'def', 'with' or 'for' to follow 'async', found 'class'
2 | async while test: ...
3 | async x = 1
|
@@ -190,7 +190,7 @@ Module(
|
1 | async class Foo: ...
2 | async while test: ...
| ^^^^^ Syntax Error: Expected `def`, `with` or `for` to follow `async`, found `while`
| ^^^^^ Syntax Error: Expected 'def', 'with' or 'for' to follow 'async', found 'while'
3 | async x = 1
4 | async async def foo(): ...
|
@@ -200,7 +200,7 @@ Module(
1 | async class Foo: ...
2 | async while test: ...
3 | async x = 1
| ^ Syntax Error: Expected `def`, `with` or `for` to follow `async`, found name
| ^ Syntax Error: Expected 'def', 'with' or 'for' to follow 'async', found name
4 | async async def foo(): ...
5 | async match test:
|
@@ -210,7 +210,7 @@ Module(
2 | async while test: ...
3 | async x = 1
4 | async async def foo(): ...
| ^^^^^ Syntax Error: Expected `def`, `with` or `for` to follow `async`, found `async`
| ^^^^^ Syntax Error: Expected 'def', 'with' or 'for' to follow 'async', found 'async'
5 | async match test:
6 | case _: ...
|
@@ -220,6 +220,6 @@ Module(
3 | async x = 1
4 | async async def foo(): ...
5 | async match test:
| ^^^^^ Syntax Error: Expected `def`, `with` or `for` to follow `async`, found `match`
| ^^^^^ Syntax Error: Expected 'def', 'with' or 'for' to follow 'async', found 'match'
6 | case _: ...
|

View File

@@ -245,7 +245,7 @@ Module(
3 | *x += 1
4 | pass += 1
5 | x += pass
| ^^^^ Syntax Error: Expected an identifier, but found a keyword `pass` that cannot be used here
| ^^^^ Syntax Error: Expected an identifier, but found a keyword 'pass' that cannot be used here
6 | (x + y) += 1
|

View File

@@ -121,7 +121,7 @@ Module(
|
1 | class Foo[T1, *T2(a, b):
| ^ Syntax Error: Expected `]`, found `(`
| ^ Syntax Error: Expected ']', found '('
2 | pass
3 | x = 10
|

View File

@@ -68,7 +68,7 @@ Module(
|
1 | call(**x := 1)
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
|

View File

@@ -61,5 +61,5 @@ Module(
|
1 | # The comma between the first two elements is expected in `parse_list_expression`.
2 | [0, 1 2]
| ^ Syntax Error: Expected `,`, found int
| ^ Syntax Error: Expected ',', found int
|

View File

@@ -77,7 +77,7 @@ Module(
|
1 | (async)
| ^^^^^ Syntax Error: Expected an identifier, but found a keyword `async` that cannot be used here
| ^^^^^ Syntax Error: Expected an identifier, but found a keyword 'async' that cannot be used here
2 | (x async x in iter)
|
@@ -85,5 +85,5 @@ Module(
|
1 | (async)
2 | (x async x in iter)
| ^ Syntax Error: Expected `for`, found name
| ^ Syntax Error: Expected 'for', found name
|

View File

@@ -169,7 +169,7 @@ Module(
|
1 | @def foo(): ...
| ^^^ Syntax Error: Expected an identifier, but found a keyword `def` that cannot be used here
| ^^^ Syntax Error: Expected an identifier, but found a keyword 'def' that cannot be used here
2 | @
3 | def foo(): ...
|

View File

@@ -161,7 +161,7 @@ Module(
|
1 | @x def foo(): ...
| ^^^ Syntax Error: Expected newline, found `def`
| ^^^ Syntax Error: Expected newline, found 'def'
2 | @x async def foo(): ...
3 | @x class Foo: ...
|
@@ -170,7 +170,7 @@ Module(
|
1 | @x def foo(): ...
2 | @x async def foo(): ...
| ^^^^^ Syntax Error: Expected newline, found `async`
| ^^^^^ Syntax Error: Expected newline, found 'async'
3 | @x class Foo: ...
|
@@ -179,5 +179,5 @@ Module(
1 | @x def foo(): ...
2 | @x async def foo(): ...
3 | @x class Foo: ...
| ^^^^^ Syntax Error: Expected newline, found `class`
| ^^^^^ Syntax Error: Expected newline, found 'class'
|

View File

@@ -238,7 +238,7 @@ Module(
3 | call(***x)
4 |
5 | call(**x := 1)
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
|

View File

@@ -61,5 +61,5 @@ Module(
|
1 | call(x y)
| ^ Syntax Error: Expected `,`, found name
| ^ Syntax Error: Expected ',', found name
|

View File

@@ -76,7 +76,7 @@ Module(
|
1 | call(
| ^ Syntax Error: Expected `)`, found newline
| ^ Syntax Error: Expected ')', found newline
2 |
3 | def foo():
4 | pass

View File

@@ -85,7 +85,7 @@ Module(
|
1 | call(x
| ^ Syntax Error: Expected `)`, found newline
| ^ Syntax Error: Expected ')', found newline
2 |
3 | def foo():
4 | pass

View File

@@ -85,7 +85,7 @@ Module(
|
1 | call(x,
| ^ Syntax Error: Expected `)`, found newline
| ^ Syntax Error: Expected ')', found newline
2 |
3 | def foo():
4 | pass

View File

@@ -175,7 +175,7 @@ Module(
|
6 | # Same here as well, `not` without `in` is considered to be a unary operator
7 | x not is y
| ^^ Syntax Error: Expected an identifier, but found a keyword `is` that cannot be used here
| ^^ Syntax Error: Expected an identifier, but found a keyword 'is' that cannot be used here
|

View File

@@ -544,7 +544,7 @@ Module(
2 | # the ones which are higher than that.
3 |
4 | {**x := 1}
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
5 | {a: 1, **x if True else y}
6 | {**lambda x: x, b: 2}
|
@@ -554,7 +554,7 @@ Module(
2 | # the ones which are higher than that.
3 |
4 | {**x := 1}
| ^ Syntax Error: Expected `:`, found `}`
| ^ Syntax Error: Expected ':', found '}'
5 | {a: 1, **x if True else y}
6 | {**lambda x: x, b: 2}
|

View File

@@ -134,7 +134,7 @@ Module(
2 | # it's actually a comprehension.
3 |
4 | {**x: y for x, y in data}
| ^^^ Syntax Error: Expected `:`, found `for`
| ^^^ Syntax Error: Expected ':', found 'for'
5 |
6 | # TODO(dhruvmanila): This test case fails because there's no way to represent `**y`
|
@@ -144,7 +144,7 @@ Module(
2 | # it's actually a comprehension.
3 |
4 | {**x: y for x, y in data}
| ^ Syntax Error: Expected `,`, found name
| ^ Syntax Error: Expected ',', found name
5 |
6 | # TODO(dhruvmanila): This test case fails because there's no way to represent `**y`
|
@@ -154,7 +154,7 @@ Module(
2 | # it's actually a comprehension.
3 |
4 | {**x: y for x, y in data}
| ^ Syntax Error: Expected `:`, found `,`
| ^ Syntax Error: Expected ':', found ','
5 |
6 | # TODO(dhruvmanila): This test case fails because there's no way to represent `**y`
|
@@ -164,7 +164,7 @@ Module(
2 | # it's actually a comprehension.
3 |
4 | {**x: y for x, y in data}
| ^ Syntax Error: Expected `:`, found `}`
| ^ Syntax Error: Expected ':', found '}'
5 |
6 | # TODO(dhruvmanila): This test case fails because there's no way to represent `**y`
|

View File

@@ -86,7 +86,7 @@ Module(
1 | {x:
2 |
3 | def foo():
| ^^^ Syntax Error: Expected an identifier, but found a keyword `def` that cannot be used here
| ^^^ Syntax Error: Expected an identifier, but found a keyword 'def' that cannot be used here
4 | pass
|
@@ -95,7 +95,7 @@ Module(
1 | {x:
2 |
3 | def foo():
| ^^^ Syntax Error: Expected `,`, found name
| ^^^ Syntax Error: Expected ',', found name
4 | pass
|
@@ -103,7 +103,7 @@ Module(
|
3 | def foo():
4 | pass
| ^^^^ Syntax Error: Expected an identifier, but found a keyword `pass` that cannot be used here
| ^^^^ Syntax Error: Expected an identifier, but found a keyword 'pass' that cannot be used here
|

View File

@@ -85,7 +85,7 @@ Module(
|
1 | {x: 1,
| ^ Syntax Error: Expected `}`, found newline
| ^ Syntax Error: Expected '}', found newline
2 |
3 | def foo():
4 | pass

View File

@@ -149,7 +149,7 @@ Module(
1 | # Unparenthesized named expression not allowed in key
2 |
3 | {x := 1: y, z := 2: a}
| ^^ Syntax Error: Expected `:`, found `:=`
| ^^ Syntax Error: Expected ':', found ':='
4 |
5 | x + y
|

View File

@@ -145,7 +145,7 @@ Module(
1 | # Unparenthesized named expression not allowed in value
2 |
3 | {x: y := 1, z: a := 2}
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
4 |
5 | x + y
|
@@ -155,7 +155,7 @@ Module(
1 | # Unparenthesized named expression not allowed in value
2 |
3 | {x: y := 1, z: a := 2}
| ^ Syntax Error: Expected `:`, found `,`
| ^ Syntax Error: Expected ':', found ','
4 |
5 | x + y
|
@@ -165,7 +165,7 @@ Module(
1 | # Unparenthesized named expression not allowed in value
2 |
3 | {x: y := 1, z: a := 2}
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
4 |
5 | x + y
|
@@ -175,7 +175,7 @@ Module(
1 | # Unparenthesized named expression not allowed in value
2 |
3 | {x: y := 1, z: a := 2}
| ^ Syntax Error: Expected `:`, found `}`
| ^ Syntax Error: Expected ':', found '}'
4 |
5 | x + y
|

View File

@@ -504,7 +504,7 @@ Module(
|
9 | # Missing comma
10 | {1: 2 3: 4}
| ^ Syntax Error: Expected `,`, found int
| ^ Syntax Error: Expected ',', found int
11 |
12 | # No value
|

View File

@@ -338,7 +338,7 @@ Module(
7 | lambda a, *a: 1
8 |
9 | lambda a, *, **a: 1
| ^^^ Syntax Error: Expected one or more keyword parameter after `*` separator
| ^^^ Syntax Error: Expected one or more keyword parameter after '*' separator
|

View File

@@ -85,7 +85,7 @@ Module(
2 | # token starts a statement.
3 |
4 | [1, 2
| ^ Syntax Error: Expected `]`, found newline
| ^ Syntax Error: Expected ']', found newline
5 |
6 | def foo():
7 | pass

View File

@@ -305,7 +305,7 @@ Module(
|
9 | # Missing comma
10 | [1 2]
| ^ Syntax Error: Expected `,`, found int
| ^ Syntax Error: Expected ',', found int
11 |
12 | # Dictionary element in a list
|

View File

@@ -84,7 +84,7 @@ Module(
3 | (x :=
4 |
5 | def foo():
| ^^^ Syntax Error: Expected an identifier, but found a keyword `def` that cannot be used here
| ^^^ Syntax Error: Expected an identifier, but found a keyword 'def' that cannot be used here
6 | pass
|
@@ -93,7 +93,7 @@ Module(
3 | (x :=
4 |
5 | def foo():
| ^^^ Syntax Error: Expected `)`, found name
| ^^^ Syntax Error: Expected ')', found name
6 | pass
|
@@ -101,7 +101,7 @@ Module(
|
5 | def foo():
6 | pass
| ^^^^ Syntax Error: Expected an identifier, but found a keyword `pass` that cannot be used here
| ^^^^ Syntax Error: Expected an identifier, but found a keyword 'pass' that cannot be used here
|

View File

@@ -142,14 +142,14 @@ Module(
|
1 | (*x for x in y)
2 | (x := 1, for x in y)
| ^^^ Syntax Error: Expected `)`, found `for`
| ^^^ Syntax Error: Expected ')', found 'for'
|
|
1 | (*x for x in y)
2 | (x := 1, for x in y)
| ^ Syntax Error: Expected `:`, found `)`
| ^ Syntax Error: Expected ':', found ')'
|

View File

@@ -86,7 +86,7 @@ Module(
2 | # token starts a statement.
3 |
4 | (1, 2
| ^ Syntax Error: Expected `)`, found newline
| ^ Syntax Error: Expected ')', found newline
5 |
6 | def foo():
7 | pass

View File

@@ -315,7 +315,7 @@ Module(
|
9 | # Missing comma
10 | (1 2)
| ^ Syntax Error: Expected `)`, found int
| ^ Syntax Error: Expected ')', found int
11 |
12 | # Dictionary element in a list
|
@@ -343,7 +343,7 @@ Module(
|
12 | # Dictionary element in a list
13 | (1: 2)
| ^ Syntax Error: Expected `)`, found `:`
| ^ Syntax Error: Expected ')', found ':'
14 |
15 | # Missing expression
|
@@ -390,7 +390,7 @@ Module(
16 | (1, x + )
17 |
18 | (1; 2)
| ^ Syntax Error: Expected `)`, found `;`
| ^ Syntax Error: Expected ')', found ';'
19 |
20 | # Unparenthesized named expression is not allowed
|
@@ -420,5 +420,5 @@ Module(
|
20 | # Unparenthesized named expression is not allowed
21 | x, y := 2, z
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
|

View File

@@ -1542,5 +1542,5 @@ Module(
18 | *x if True else y, z, *x if True else y
19 | *lambda x: x, z, *lambda x: x
20 | *x := 2, z, *x := 2
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
|

View File

@@ -84,7 +84,7 @@ Module(
2 | # token starts a statement.
3 |
4 | {1, 2
| ^ Syntax Error: Expected `}`, found newline
| ^ Syntax Error: Expected '}', found newline
5 |
6 | def foo():
7 | pass

View File

@@ -302,7 +302,7 @@ Module(
|
11 | # Missing comma
12 | {1 2}
| ^ Syntax Error: Expected `,`, found int
| ^ Syntax Error: Expected ',', found int
13 |
14 | # Dictionary element in a list
|

View File

@@ -95,7 +95,7 @@ Module(
1 | x[::
2 |
3 | def foo():
| ^^^ Syntax Error: Expected an identifier, but found a keyword `def` that cannot be used here
| ^^^ Syntax Error: Expected an identifier, but found a keyword 'def' that cannot be used here
4 | pass
|
@@ -104,7 +104,7 @@ Module(
1 | x[::
2 |
3 | def foo():
| ^^^ Syntax Error: Expected `]`, found name
| ^^^ Syntax Error: Expected ']', found name
4 | pass
|
@@ -112,7 +112,7 @@ Module(
|
3 | def foo():
4 | pass
| ^^^^ Syntax Error: Expected an identifier, but found a keyword `pass` that cannot be used here
| ^^^^ Syntax Error: Expected an identifier, but found a keyword 'pass' that cannot be used here
|

View File

@@ -125,5 +125,5 @@ Module(
2 | yield x := 1
3 |
4 | yield 1, x := 2, 3
| ^^ Syntax Error: Expected `,`, found `:=`
| ^^ Syntax Error: Expected ',', found ':='
|

View File

@@ -117,7 +117,7 @@ Module(
|
1 | f"{lambda x: x}"
| ^^ Syntax Error: f-string: expecting `}`
| ^^ Syntax Error: f-string: expecting '}'
|

View File

@@ -267,7 +267,7 @@ Module(
|
1 | f"{"
2 | f"{foo!r"
| ^ Syntax Error: f-string: expecting `}`
| ^ Syntax Error: f-string: expecting '}'
3 | f"{foo="
4 | f"{"
|
@@ -277,7 +277,7 @@ Module(
1 | f"{"
2 | f"{foo!r"
3 | f"{foo="
| ^ Syntax Error: f-string: expecting `}`
| ^ Syntax Error: f-string: expecting '}'
4 | f"{"
5 | f"""{"""
|

View File

@@ -146,7 +146,7 @@ Module(
|
1 | f"hello {x:"
| ^ Syntax Error: f-string: expecting `}`
| ^ Syntax Error: f-string: expecting '}'
2 | f"hello {x:.3f"
|
@@ -154,5 +154,5 @@ Module(
|
1 | f"hello {x:"
2 | f"hello {x:.3f"
| ^ Syntax Error: f-string: expecting `}`
| ^ Syntax Error: f-string: expecting '}'
|

View File

@@ -192,7 +192,7 @@ Module(
1 | for x in *a and b: ...
2 | for x in yield a: ...
3 | for target in x := 1: ...
| ^^ Syntax Error: Expected `:`, found `:=`
| ^^ Syntax Error: Expected ':', found ':='
|

View File

@@ -498,7 +498,7 @@ Module(
4 | for *x | y in z: ...
5 | for await x in z: ...
6 | for yield x in y: ...
| ^ Syntax Error: Expected `in`, found `:`
| ^ Syntax Error: Expected 'in', found ':'
7 | for [x, 1, y, *["a"]] in z: ...
|

View File

@@ -94,7 +94,7 @@ Module(
|
1 | for a b: ...
| ^ Syntax Error: Expected `in`, found name
| ^ Syntax Error: Expected 'in', found name
2 | for a: ...
|
@@ -102,5 +102,5 @@ Module(
|
1 | for a b: ...
2 | for a: ...
| ^ Syntax Error: Expected `in`, found `:`
| ^ Syntax Error: Expected 'in', found ':'
|

View File

@@ -56,11 +56,11 @@ Module(
|
1 | for in x: ...
| ^^ Syntax Error: Expected an identifier, but found a keyword `in` that cannot be used here
| ^^ Syntax Error: Expected an identifier, but found a keyword 'in' that cannot be used here
|
|
1 | for in x: ...
| ^ Syntax Error: Expected `in`, found name
| ^ Syntax Error: Expected 'in', found name
|

View File

@@ -166,7 +166,7 @@ Module(
|
1 | from x import a.
| ^ Syntax Error: Expected `,`, found `.`
| ^ Syntax Error: Expected ',', found '.'
2 | from x import a.b
3 | from x import a, b.c, d, e.f, g
|
@@ -175,7 +175,7 @@ Module(
|
1 | from x import a.
2 | from x import a.b
| ^ Syntax Error: Expected `,`, found `.`
| ^ Syntax Error: Expected ',', found '.'
3 | from x import a, b.c, d, e.f, g
|
@@ -184,7 +184,7 @@ Module(
1 | from x import a.
2 | from x import a.b
3 | from x import a, b.c, d, e.f, g
| ^ Syntax Error: Expected `,`, found `.`
| ^ Syntax Error: Expected ',', found '.'
|
@@ -192,5 +192,5 @@ Module(
1 | from x import a.
2 | from x import a.b
3 | from x import a, b.c, d, e.f, g
| ^ Syntax Error: Expected `,`, found `.`
| ^ Syntax Error: Expected ',', found '.'
|

View File

@@ -152,7 +152,7 @@ Module(
|
1 | from x import (a, b
| ^ Syntax Error: Expected `)`, found newline
| ^ Syntax Error: Expected ')', found newline
2 | 1 + 1
3 | from x import (a, b,
4 | 2 + 2
@@ -163,6 +163,6 @@ Module(
1 | from x import (a, b
2 | 1 + 1
3 | from x import (a, b,
| ^ Syntax Error: Expected `)`, found newline
| ^ Syntax Error: Expected ')', found newline
4 | 2 + 2
|

View File

@@ -234,7 +234,7 @@ Module(
|
1 | def foo(a: int, b:
| ^ Syntax Error: Expected `)`, found newline
| ^ Syntax Error: Expected ')', found newline
2 | def foo():
3 | return 42
4 | def foo(a: int, b: str
@@ -254,7 +254,7 @@ Module(
3 | return 42
4 | def foo(a: int, b: str
5 | x = 10
| ^ Syntax Error: Expected `,`, found name
| ^ Syntax Error: Expected ',', found name
|

View File

@@ -163,7 +163,7 @@ Module(
|
1 | def foo[T1, *T2(a, b):
| ^ Syntax Error: Expected `]`, found `(`
| ^ Syntax Error: Expected ']', found '('
2 | return a + b
3 | x = 10
|

View File

@@ -79,7 +79,7 @@ Module(
1 | if x:
2 | pass
3 | elif y
| ^ Syntax Error: Expected `:`, found newline
| ^ Syntax Error: Expected ':', found newline
4 | pass
5 | else:
6 | pass

View File

@@ -82,7 +82,7 @@ Module(
|
1 | if x
| ^ Syntax Error: Expected `:`, found newline
| ^ Syntax Error: Expected ':', found newline
2 | if x
3 | pass
4 | a = 1
@@ -101,7 +101,7 @@ Module(
|
1 | if x
2 | if x
| ^ Syntax Error: Expected `:`, found newline
| ^ Syntax Error: Expected ':', found newline
3 | pass
4 | a = 1
|

View File

@@ -80,6 +80,6 @@ Module(
|
1 | match [1, 2]
| ^ Syntax Error: Expected `:`, found newline
| ^ Syntax Error: Expected ':', found newline
2 | case _: ...
|

View File

@@ -61,7 +61,7 @@ Module(
|
1 | match foo: case _: ...
| ^^^^ Syntax Error: Expected newline, found `case`
| ^^^^ Syntax Error: Expected newline, found 'case'
|

View File

@@ -326,7 +326,7 @@ Module(
|
1 | if True: pass elif False: pass else: pass
| ^^^^ Syntax Error: Expected newline, found `elif`
| ^^^^ Syntax Error: Expected newline, found 'elif'
2 | if True: pass; elif False: pass; else: pass
3 | for x in iter: break else: pass
|
@@ -334,7 +334,7 @@ Module(
|
1 | if True: pass elif False: pass else: pass
| ^^^^ Syntax Error: Expected newline, found `else`
| ^^^^ Syntax Error: Expected newline, found 'else'
2 | if True: pass; elif False: pass; else: pass
3 | for x in iter: break else: pass
|
@@ -343,7 +343,7 @@ Module(
|
1 | if True: pass elif False: pass else: pass
2 | if True: pass; elif False: pass; else: pass
| ^^^^ Syntax Error: Expected newline, found `elif`
| ^^^^ Syntax Error: Expected newline, found 'elif'
3 | for x in iter: break else: pass
4 | for x in iter: break; else: pass
|
@@ -352,7 +352,7 @@ Module(
|
1 | if True: pass elif False: pass else: pass
2 | if True: pass; elif False: pass; else: pass
| ^^^^ Syntax Error: Expected newline, found `else`
| ^^^^ Syntax Error: Expected newline, found 'else'
3 | for x in iter: break else: pass
4 | for x in iter: break; else: pass
|
@@ -362,7 +362,7 @@ Module(
1 | if True: pass elif False: pass else: pass
2 | if True: pass; elif False: pass; else: pass
3 | for x in iter: break else: pass
| ^^^^ Syntax Error: Expected newline, found `else`
| ^^^^ Syntax Error: Expected newline, found 'else'
4 | for x in iter: break; else: pass
5 | try: pass except exc: pass else: pass finally: pass
|
@@ -372,7 +372,7 @@ Module(
2 | if True: pass; elif False: pass; else: pass
3 | for x in iter: break else: pass
4 | for x in iter: break; else: pass
| ^^^^ Syntax Error: Expected newline, found `else`
| ^^^^ Syntax Error: Expected newline, found 'else'
5 | try: pass except exc: pass else: pass finally: pass
6 | try: pass; except exc: pass; else: pass; finally: pass
|
@@ -382,7 +382,7 @@ Module(
3 | for x in iter: break else: pass
4 | for x in iter: break; else: pass
5 | try: pass except exc: pass else: pass finally: pass
| ^^^^^^ Syntax Error: Expected newline, found `except`
| ^^^^^^ Syntax Error: Expected newline, found 'except'
6 | try: pass; except exc: pass; else: pass; finally: pass
|
@@ -391,7 +391,7 @@ Module(
3 | for x in iter: break else: pass
4 | for x in iter: break; else: pass
5 | try: pass except exc: pass else: pass finally: pass
| ^^^^ Syntax Error: Expected newline, found `else`
| ^^^^ Syntax Error: Expected newline, found 'else'
6 | try: pass; except exc: pass; else: pass; finally: pass
|
@@ -400,7 +400,7 @@ Module(
3 | for x in iter: break else: pass
4 | for x in iter: break; else: pass
5 | try: pass except exc: pass else: pass finally: pass
| ^^^^^^^ Syntax Error: Expected newline, found `finally`
| ^^^^^^^ Syntax Error: Expected newline, found 'finally'
6 | try: pass; except exc: pass; else: pass; finally: pass
|
@@ -409,7 +409,7 @@ Module(
4 | for x in iter: break; else: pass
5 | try: pass except exc: pass else: pass finally: pass
6 | try: pass; except exc: pass; else: pass; finally: pass
| ^^^^^^ Syntax Error: Expected newline, found `except`
| ^^^^^^ Syntax Error: Expected newline, found 'except'
|
@@ -417,7 +417,7 @@ Module(
4 | for x in iter: break; else: pass
5 | try: pass except exc: pass else: pass finally: pass
6 | try: pass; except exc: pass; else: pass; finally: pass
| ^^^^ Syntax Error: Expected newline, found `else`
| ^^^^ Syntax Error: Expected newline, found 'else'
|
@@ -425,5 +425,5 @@ Module(
4 | for x in iter: break; else: pass
5 | try: pass except exc: pass else: pass finally: pass
6 | try: pass; except exc: pass; else: pass; finally: pass
| ^^^^^^^ Syntax Error: Expected newline, found `finally`
| ^^^^^^^ Syntax Error: Expected newline, found 'finally'
|

View File

@@ -238,7 +238,7 @@ Module(
1 | # even after 3.9, an unparenthesized named expression is not allowed in a slice
2 | lst[x:=1:-1]
3 | lst[1:x:=1]
| ^^ Syntax Error: Expected `]`, found `:=`
| ^^ Syntax Error: Expected ']', found ':='
4 | lst[1:3:x:=1]
|
@@ -265,7 +265,7 @@ Module(
2 | lst[x:=1:-1]
3 | lst[1:x:=1]
4 | lst[1:3:x:=1]
| ^^ Syntax Error: Expected `]`, found `:=`
| ^^ Syntax Error: Expected ']', found ':='
|

Some files were not shown because too many files have changed in this diff Show More