Compare commits
30 Commits
alex/into_
...
alex/dont-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80f045a261 | ||
|
|
349e24db9a | ||
|
|
bff32a41dc | ||
|
|
17c7b3cde1 | ||
|
|
921f409ee8 | ||
|
|
a151f9746d | ||
|
|
521217bb90 | ||
|
|
a32d5b8dc4 | ||
|
|
6337e22f0c | ||
|
|
827d8ae5d4 | ||
|
|
1734ddfb3e | ||
|
|
ff3a6a8fbd | ||
|
|
9664474c51 | ||
|
|
69b4c29924 | ||
|
|
bb40c34361 | ||
|
|
b93d8f2b9f | ||
|
|
1d111c8780 | ||
|
|
9d7da914b9 | ||
|
|
0c2cf75869 | ||
|
|
1d6ae8596a | ||
|
|
cf4e82d4b0 | ||
|
|
1baf98aab3 | ||
|
|
3179b05221 | ||
|
|
172e8d4ae0 | ||
|
|
735ec0c1f9 | ||
|
|
3585c96ea5 | ||
|
|
4b026c2a55 | ||
|
|
4b758b3746 | ||
|
|
8737a2d5f5 | ||
|
|
3be3a10a2f |
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@@ -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
|
||||
# Dogfood ty on py-fuzzer
|
||||
- run: uv run --project=./python/py-fuzzer cargo run -p ty check --project=./python/py-fuzzer
|
||||
- name: 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' && 5 || 20 }}
|
||||
timeout-minutes: ${{ github.repository == 'astral-sh/ruff' && 10 || 20 }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
|
||||
55
CHANGELOG.md
55
CHANGELOG.md
@@ -1,5 +1,60 @@
|
||||
# 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
44
Cargo.lock
generated
@@ -243,7 +243,7 @@ dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.10.5",
|
||||
"itertools 0.13.0",
|
||||
"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.52.0",
|
||||
"windows-sys 0.59.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.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1007,7 +1007,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1093,7 +1093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1115,13 +1115,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "etcetera"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6"
|
||||
checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"home",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1366,15 +1365,6 @@ 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"
|
||||
@@ -1563,7 +1553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.5",
|
||||
"hashbrown 0.16.0",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
@@ -1690,7 +1680,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1754,7 +1744,7 @@ dependencies = [
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2835,7 +2825,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argfile",
|
||||
@@ -3092,7 +3082,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_linter"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"anyhow",
|
||||
@@ -3447,7 +3437,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_wasm"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
@@ -3545,7 +3535,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3941,7 +3931,7 @@ dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5021,7 +5011,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -5,7 +5,7 @@ resolver = "2"
|
||||
[workspace.package]
|
||||
# Please update rustfmt.toml when bumping the Rust edition
|
||||
edition = "2024"
|
||||
rust-version = "1.88"
|
||||
rust-version = "1.89"
|
||||
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.10.0" }
|
||||
etcetera = { version = "0.11.0" }
|
||||
fern = { version = "0.7.0" }
|
||||
filetime = { version = "0.2.23" }
|
||||
getrandom = { version = "0.3.1" }
|
||||
|
||||
@@ -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.2/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/0.14.2/install.ps1 | iex"
|
||||
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"
|
||||
```
|
||||
|
||||
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.2
|
||||
rev: v0.14.3
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
publish = true
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
@@ -7,6 +7,7 @@ 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};
|
||||
@@ -127,10 +128,6 @@ 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 {
|
||||
@@ -147,13 +144,34 @@ 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, &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,
|
||||
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()
|
||||
});
|
||||
|
||||
debug!("Discovered {} imports for {}", imports.len(), path);
|
||||
|
||||
|
||||
@@ -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.to_string();
|
||||
let mut formatted = unformatted.clone();
|
||||
formatted.replace_range(
|
||||
std::ops::Range::<usize>::from(formatted_range.source_range()),
|
||||
formatted_range.as_code(),
|
||||
|
||||
@@ -653,3 +653,133 @@ 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(())
|
||||
}
|
||||
|
||||
@@ -470,6 +470,11 @@ 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
|
||||
|
||||
@@ -723,10 +723,11 @@ 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 fn new(path: &str) -> &SystemVirtualPath {
|
||||
pub const 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) }
|
||||
@@ -767,8 +768,8 @@ pub struct SystemVirtualPathBuf(String);
|
||||
|
||||
impl SystemVirtualPathBuf {
|
||||
#[inline]
|
||||
pub fn as_path(&self) -> &SystemVirtualPath {
|
||||
SystemVirtualPath::new(&self.0)
|
||||
pub const fn as_path(&self) -> &SystemVirtualPath {
|
||||
SystemVirtualPath::new(self.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,6 +853,12 @@ 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
|
||||
|
||||
@@ -62,7 +62,7 @@ fn generate_set(output: &mut String, set: Set, parents: &mut Vec<Set>) {
|
||||
generate_set(
|
||||
output,
|
||||
Set::Named {
|
||||
name: set_name.to_string(),
|
||||
name: set_name.clone(),
|
||||
set: *sub_set,
|
||||
},
|
||||
parents,
|
||||
|
||||
@@ -104,7 +104,7 @@ fn generate_set(output: &mut String, set: Set, parents: &mut Vec<Set>) {
|
||||
generate_set(
|
||||
output,
|
||||
Set::Named {
|
||||
name: set_name.to_string(),
|
||||
name: set_name.clone(),
|
||||
set: *sub_set,
|
||||
},
|
||||
parents,
|
||||
|
||||
@@ -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 [`FormatElement.is_empty`].
|
||||
/// Doesn't create an indentation if the passed in content is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
||||
@@ -3,8 +3,9 @@ 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::{Mode, ParseOptions, parse};
|
||||
use ruff_python_parser::{ParseOptions, parse};
|
||||
|
||||
use crate::collector::Collector;
|
||||
pub use crate::db::ModuleDb;
|
||||
@@ -24,13 +25,14 @@ 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> {
|
||||
// Read and parse the source code.
|
||||
let source = std::fs::read_to_string(path)?;
|
||||
let parsed = parse(&source, ParseOptions::from(Mode::Module))?;
|
||||
// Parse the source code.
|
||||
let parsed = parse(source, ParseOptions::from(source_type))?;
|
||||
|
||||
let module_path =
|
||||
package.and_then(|package| to_module_path(package.as_std_path(), path.as_std_path()));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_linter"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
@@ -145,3 +145,11 @@ 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"))
|
||||
@@ -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
|
||||
|
||||
@@ -78,7 +78,7 @@ pub(crate) fn unconventional_import_alias(
|
||||
let mut diagnostic = checker.report_diagnostic(
|
||||
UnconventionalImportAlias {
|
||||
name: qualified_name,
|
||||
asname: expected_alias.to_string(),
|
||||
asname: expected_alias.clone(),
|
||||
},
|
||||
binding.range(),
|
||||
);
|
||||
|
||||
@@ -6,21 +6,17 @@ 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 {
|
||||
@@ -33,19 +29,15 @@ 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 {
|
||||
@@ -57,19 +49,15 @@ 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 {
|
||||
|
||||
@@ -9,19 +9,15 @@ 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 {
|
||||
|
||||
@@ -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.to_string(),
|
||||
replacement: contents.clone(),
|
||||
},
|
||||
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.to_string(),
|
||||
replacement: contents.clone(),
|
||||
},
|
||||
TextRange::new(stmt.start(), terminal.stmt.end()),
|
||||
);
|
||||
|
||||
@@ -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.to_string(),
|
||||
message: reason.msg.clone(),
|
||||
},
|
||||
node.range(),
|
||||
);
|
||||
@@ -74,8 +74,8 @@ pub(crate) fn banned_attribute_access(checker: &Checker, expr: &Expr) {
|
||||
{
|
||||
checker.report_diagnostic(
|
||||
BannedApi {
|
||||
name: banned_path.to_string(),
|
||||
message: ban.msg.to_string(),
|
||||
name: banned_path.clone(),
|
||||
message: ban.msg.clone(),
|
||||
},
|
||||
expr.range(),
|
||||
);
|
||||
|
||||
@@ -20,21 +20,17 @@ 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 {
|
||||
|
||||
@@ -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.to_string(),
|
||||
content.clone(),
|
||||
compare.range(),
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.to_string(),
|
||||
capitalized_word: capitalized_word.clone(),
|
||||
},
|
||||
docstring.range(),
|
||||
);
|
||||
|
||||
@@ -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.to_string()),
|
||||
replacement: SourceCodeSnippet::new(replacement.clone()),
|
||||
},
|
||||
call.range(),
|
||||
);
|
||||
|
||||
@@ -5,7 +5,6 @@ use ruff_python_ast::{
|
||||
relocate::relocate_expr,
|
||||
visitor::{self, Visitor},
|
||||
};
|
||||
|
||||
use ruff_python_codegen::Generator;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
|
||||
@@ -134,3 +134,14 @@ 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")....`
|
||||
|
||||
@@ -257,4 +257,25 @@ 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 |
|
||||
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"))
|
||||
|
||||
@@ -104,3 +104,14 @@ 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")....`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -335,3 +335,96 @@ 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
|
||||
|
||||
@@ -61,3 +61,9 @@ 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" )
|
||||
|
||||
@@ -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.to_string();
|
||||
let mut formatted = source.clone();
|
||||
formatted.replace_range(
|
||||
std::ops::Range::<usize>::from(printed.source_range()),
|
||||
printed.as_code(),
|
||||
|
||||
@@ -36,3 +36,10 @@ 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()
|
||||
}
|
||||
|
||||
@@ -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, contains_only_an_ellipsis};
|
||||
use crate::statement::suite::{SuiteKind, as_only_an_ellipsis};
|
||||
use crate::verbatim::write_suppressed_clause_header;
|
||||
use crate::{has_skip_comment, prelude::*};
|
||||
|
||||
@@ -449,17 +449,10 @@ impl Format<PyFormatContext<'_>> for FormatClauseBody<'_> {
|
||||
|| matches!(self.kind, SuiteKind::Function | SuiteKind::Class);
|
||||
|
||||
if should_collapse_stub
|
||||
&& contains_only_an_ellipsis(self.body, f.context().comments())
|
||||
&& let Some(ellipsis) = as_only_an_ellipsis(self.body, f.context().comments())
|
||||
&& self.trailing_comments.is_empty()
|
||||
{
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
space(),
|
||||
self.body.format().with_options(self.kind),
|
||||
hard_line_break()
|
||||
]
|
||||
)
|
||||
write!(f, [space(), ellipsis.format(), hard_line_break()])
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
|
||||
@@ -13,7 +13,9 @@ use crate::comments::{
|
||||
use crate::context::{NodeLevel, TopLevelStatementPosition, WithIndentLevel, WithNodeLevel};
|
||||
use crate::other::string_literal::StringLiteralKind;
|
||||
use crate::prelude::*;
|
||||
use crate::preview::is_blank_line_before_decorated_class_in_stub_enabled;
|
||||
use crate::preview::{
|
||||
is_allow_newline_after_block_open_enabled, 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,
|
||||
@@ -169,6 +171,22 @@ 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(_))
|
||||
@@ -218,7 +236,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 to getter by omitting new lines between them.
|
||||
// This is useful when having multiple function overloads that should be grouped together by omitting new lines between them.
|
||||
let is_preceding_stub_function_without_empty_line = following
|
||||
.is_function_def_stmt()
|
||||
&& preceding
|
||||
@@ -728,17 +746,21 @@ 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 {
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns `true` if a [`Stmt`] is a class or function definition.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
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
|
||||
@@ -342,6 +341,99 @@ 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
|
||||
@@ -732,6 +824,88 @@ 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
|
||||
```
|
||||
|
||||
|
||||
@@ -739,7 +913,15 @@ def overload4(a: int): ...
|
||||
```diff
|
||||
--- Stable
|
||||
+++ Preview
|
||||
@@ -277,6 +277,7 @@
|
||||
@@ -253,6 +253,7 @@
|
||||
|
||||
|
||||
def fakehttp():
|
||||
+
|
||||
class FakeHTTPConnection:
|
||||
if mock_close:
|
||||
|
||||
@@ -277,6 +278,7 @@
|
||||
|
||||
def a():
|
||||
return 1
|
||||
@@ -747,7 +929,7 @@ def overload4(a: int): ...
|
||||
else:
|
||||
pass
|
||||
|
||||
@@ -293,6 +294,7 @@
|
||||
@@ -293,6 +295,7 @@
|
||||
|
||||
def a():
|
||||
return 1
|
||||
@@ -755,7 +937,7 @@ def overload4(a: int): ...
|
||||
case 1:
|
||||
|
||||
def a():
|
||||
@@ -303,6 +305,7 @@
|
||||
@@ -303,6 +306,7 @@
|
||||
|
||||
def a():
|
||||
return 1
|
||||
@@ -763,7 +945,7 @@ def overload4(a: int): ...
|
||||
except RuntimeError:
|
||||
|
||||
def a():
|
||||
@@ -313,6 +316,7 @@
|
||||
@@ -313,6 +317,7 @@
|
||||
|
||||
def a():
|
||||
return 1
|
||||
@@ -771,7 +953,7 @@ def overload4(a: int): ...
|
||||
finally:
|
||||
|
||||
def a():
|
||||
@@ -323,18 +327,22 @@
|
||||
@@ -323,18 +328,22 @@
|
||||
|
||||
def a():
|
||||
return 1
|
||||
@@ -794,4 +976,64 @@ def overload4(a: int): ...
|
||||
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
|
||||
|
||||
|
||||
```
|
||||
|
||||
@@ -67,6 +67,12 @@ 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
|
||||
@@ -146,6 +152,27 @@ 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" )
|
||||
```
|
||||
|
||||
|
||||
@@ -225,6 +252,27 @@ 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")
|
||||
```
|
||||
|
||||
|
||||
@@ -304,4 +352,25 @@ 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")
|
||||
```
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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 _: ...
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -68,7 +68,7 @@ Module(
|
||||
|
||||
|
|
||||
1 | call(**x := 1)
|
||||
| ^^ Syntax Error: Expected ',', found ':='
|
||||
| ^^ Syntax Error: Expected `,`, found `:=`
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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(): ...
|
||||
|
|
||||
|
||||
@@ -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`
|
||||
|
|
||||
|
||||
@@ -238,7 +238,7 @@ Module(
|
||||
3 | call(***x)
|
||||
4 |
|
||||
5 | call(**x := 1)
|
||||
| ^^ Syntax Error: Expected ',', found ':='
|
||||
| ^^ Syntax Error: Expected `,`, found `:=`
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -61,5 +61,5 @@ Module(
|
||||
|
||||
|
|
||||
1 | call(x y)
|
||||
| ^ Syntax Error: Expected ',', found name
|
||||
| ^ Syntax Error: Expected `,`, found name
|
||||
|
|
||||
|
||||
@@ -76,7 +76,7 @@ Module(
|
||||
|
||||
|
|
||||
1 | call(
|
||||
| ^ Syntax Error: Expected ')', found newline
|
||||
| ^ Syntax Error: Expected `)`, found newline
|
||||
2 |
|
||||
3 | def foo():
|
||||
4 | pass
|
||||
|
||||
@@ -85,7 +85,7 @@ Module(
|
||||
|
||||
|
|
||||
1 | call(x
|
||||
| ^ Syntax Error: Expected ')', found newline
|
||||
| ^ Syntax Error: Expected `)`, found newline
|
||||
2 |
|
||||
3 | def foo():
|
||||
4 | pass
|
||||
|
||||
@@ -85,7 +85,7 @@ Module(
|
||||
|
||||
|
|
||||
1 | call(x,
|
||||
| ^ Syntax Error: Expected ')', found newline
|
||||
| ^ Syntax Error: Expected `)`, found newline
|
||||
2 |
|
||||
3 | def foo():
|
||||
4 | pass
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
|
||||
|
||||
@@ -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`
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ Module(
|
||||
|
||||
|
|
||||
1 | {x: 1,
|
||||
| ^ Syntax Error: Expected '}', found newline
|
||||
| ^ Syntax Error: Expected `}`, found newline
|
||||
2 |
|
||||
3 | def foo():
|
||||
4 | pass
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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 `)`
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 `:=`
|
||||
|
|
||||
|
||||
@@ -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 `:=`
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -125,5 +125,5 @@ Module(
|
||||
2 | yield x := 1
|
||||
3 |
|
||||
4 | yield 1, x := 2, 3
|
||||
| ^^ Syntax Error: Expected ',', found ':='
|
||||
| ^^ Syntax Error: Expected `,`, found `:=`
|
||||
|
|
||||
|
||||
@@ -117,7 +117,7 @@ Module(
|
||||
|
||||
|
|
||||
1 | f"{lambda x: x}"
|
||||
| ^^ Syntax Error: f-string: expecting '}'
|
||||
| ^^ Syntax Error: f-string: expecting `}`
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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"""{"""
|
||||
|
|
||||
|
||||
@@ -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 `}`
|
||||
|
|
||||
|
||||
@@ -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 `:=`
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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: ...
|
||||
|
|
||||
|
||||
|
||||
@@ -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 `:`
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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 `.`
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -80,6 +80,6 @@ Module(
|
||||
|
||||
|
|
||||
1 | match [1, 2]
|
||||
| ^ Syntax Error: Expected ':', found newline
|
||||
| ^ Syntax Error: Expected `:`, found newline
|
||||
2 | case _: ...
|
||||
|
|
||||
|
||||
@@ -61,7 +61,7 @@ Module(
|
||||
|
||||
|
|
||||
1 | match foo: case _: ...
|
||||
| ^^^^ Syntax Error: Expected newline, found 'case'
|
||||
| ^^^^ Syntax Error: Expected newline, found `case`
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -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`
|
||||
|
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user