Compare commits
15 Commits
zanie/eco-
...
indent-lam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5a18a697c | ||
|
|
3e218fa2ec | ||
|
|
dd2d8cb579 | ||
|
|
a08c5b7fa7 | ||
|
|
9f30ccc1f4 | ||
|
|
31286e1c95 | ||
|
|
b9994dc495 | ||
|
|
f16505d885 | ||
|
|
d04d964ace | ||
|
|
f64c389654 | ||
|
|
2ff1afb15c | ||
|
|
7fa6ac976a | ||
|
|
7dd5137913 | ||
|
|
0d93fbb4a2 | ||
|
|
d350ede992 |
18
.github/workflows/pr-comment.yaml
vendored
18
.github/workflows/pr-comment.yaml
vendored
@@ -1,4 +1,4 @@
|
||||
name: PR Check Comment
|
||||
name: Ecosystem check comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
@@ -18,13 +18,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: Download PR Number
|
||||
name: Download pull request number
|
||||
with:
|
||||
name: pr-number
|
||||
run_id: ${{ github.event.workflow_run.id || github.event.inputs.workflow_run_id }}
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- name: Extract PR Number
|
||||
- name: Parse pull request number
|
||||
id: pr-number
|
||||
run: |
|
||||
if [[ -f pr-number ]]
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: "Download Ecosystem Result"
|
||||
name: "Download ecosystem results"
|
||||
id: download-ecosystem-result
|
||||
if: steps.pr-number.outputs.pr-number
|
||||
with:
|
||||
@@ -44,10 +44,14 @@ jobs:
|
||||
workflow_conclusion: completed
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- name: Generate Comment
|
||||
- name: Generate comment content
|
||||
id: generate-comment
|
||||
if: steps.download-ecosystem-result.outputs.found_artifact == 'true'
|
||||
run: |
|
||||
# Note this identifier is used to find the comment to update on
|
||||
# subsequent runs
|
||||
echo '<!-- generated-comment ecosystem -->' >> comment.txt
|
||||
|
||||
echo '## `ruff-ecosystem` results' >> comment.txt
|
||||
cat pr/ecosystem/ecosystem-result >> comment.txt
|
||||
echo "" >> comment.txt
|
||||
@@ -56,14 +60,14 @@ jobs:
|
||||
cat comment.txt >> $GITHUB_OUTPUT
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Find Comment
|
||||
- name: Find existing comment
|
||||
uses: peter-evans/find-comment@v2
|
||||
if: steps.generate-comment.outcome == 'success'
|
||||
id: find-comment
|
||||
with:
|
||||
issue-number: ${{ steps.pr-number.outputs.pr-number }}
|
||||
comment-author: "github-actions[bot]"
|
||||
body-includes: PR Check Results
|
||||
body-includes: "<!-- generated-comment ecosystem -->"
|
||||
|
||||
- name: Create or update comment
|
||||
if: steps.find-comment.outcome == 'success'
|
||||
|
||||
25
LICENSE
25
LICENSE
@@ -1269,6 +1269,31 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-trio, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Zac Hatfield-Dodds
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- Pyright, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
@@ -314,6 +314,7 @@ quality tools, including:
|
||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [flake8-todos](https://pypi.org/project/flake8-todos/)
|
||||
- [flake8-trio](https://pypi.org/project/flake8-trio/)
|
||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
|
||||
|
||||
18
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO100.py
vendored
Normal file
18
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO100.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import trio
|
||||
|
||||
|
||||
async def foo():
|
||||
with trio.fail_after():
|
||||
...
|
||||
|
||||
async def foo():
|
||||
with trio.fail_at():
|
||||
await ...
|
||||
|
||||
async def foo():
|
||||
with trio.move_on_after():
|
||||
...
|
||||
|
||||
async def foo():
|
||||
with trio.move_at():
|
||||
await ...
|
||||
106
crates/ruff_linter/resources/test/fixtures/numpy/NPY201.py
vendored
Normal file
106
crates/ruff_linter/resources/test/fixtures/numpy/NPY201.py
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
def func():
|
||||
import numpy as np
|
||||
|
||||
np.add_docstring
|
||||
|
||||
np.add_newdoc
|
||||
|
||||
np.add_newdoc_ufunc
|
||||
|
||||
np.asfarray([1,2,3])
|
||||
|
||||
np.byte_bounds(np.array([1,2,3]))
|
||||
|
||||
np.cast
|
||||
|
||||
np.cfloat(12+34j)
|
||||
|
||||
np.clongfloat(12+34j)
|
||||
|
||||
np.compat
|
||||
|
||||
np.complex_(12+34j)
|
||||
|
||||
np.DataSource
|
||||
|
||||
np.deprecate
|
||||
|
||||
np.deprecate_with_doc
|
||||
|
||||
np.disp(10)
|
||||
|
||||
np.fastCopyAndTranspose
|
||||
|
||||
np.find_common_type
|
||||
|
||||
np.get_array_wrap
|
||||
|
||||
np.float_
|
||||
|
||||
np.geterrobj
|
||||
|
||||
np.Inf
|
||||
|
||||
np.Infinity
|
||||
|
||||
np.infty
|
||||
|
||||
np.issctype
|
||||
|
||||
np.issubclass_(np.int32, np.integer)
|
||||
|
||||
np.issubsctype
|
||||
|
||||
np.mat
|
||||
|
||||
np.maximum_sctype
|
||||
|
||||
np.NaN
|
||||
|
||||
np.nbytes[np.int64]
|
||||
|
||||
np.NINF
|
||||
|
||||
np.NZERO
|
||||
|
||||
np.longcomplex(12+34j)
|
||||
|
||||
np.longfloat(12+34j)
|
||||
|
||||
np.lookfor
|
||||
|
||||
np.obj2sctype(int)
|
||||
|
||||
np.PINF
|
||||
|
||||
np.PZERO
|
||||
|
||||
np.recfromcsv
|
||||
|
||||
np.recfromtxt
|
||||
|
||||
np.round_(12.34)
|
||||
|
||||
np.safe_eval
|
||||
|
||||
np.sctype2char
|
||||
|
||||
np.sctypes
|
||||
|
||||
np.seterrobj
|
||||
|
||||
np.set_numeric_ops
|
||||
|
||||
np.set_string_function
|
||||
|
||||
np.singlecomplex(12+1j)
|
||||
|
||||
np.string_("asdf")
|
||||
|
||||
np.source
|
||||
|
||||
np.tracemalloc_domain
|
||||
|
||||
np.unicode_("asf")
|
||||
|
||||
np.who()
|
||||
@@ -45,3 +45,11 @@ x = f"string { # And here's a comment with an unusual parenthesis: )
|
||||
# And here's a comment with a greek alpha: ∗
|
||||
foo # And here's a comment with an unusual punctuation mark: ᜵
|
||||
}"
|
||||
|
||||
# At runtime the attribute will be stored as Greek small letter mu instead of
|
||||
# micro sign because of PEP 3131's NFKC normalization
|
||||
class Labware:
|
||||
µL = 1.5
|
||||
|
||||
|
||||
assert getattr(Labware(), "µL") == 1.5
|
||||
|
||||
@@ -158,6 +158,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::NumpyDeprecatedFunction) {
|
||||
numpy::rules::deprecated_function(checker, expr);
|
||||
}
|
||||
if checker.enabled(Rule::Numpy2Deprecation) {
|
||||
numpy::rules::numpy_2_0_deprecation(checker, expr);
|
||||
}
|
||||
if checker.enabled(Rule::CollectionsNamedTuple) {
|
||||
flake8_pyi::rules::collections_named_tuple(checker, expr);
|
||||
}
|
||||
@@ -314,6 +317,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::NumpyDeprecatedFunction) {
|
||||
numpy::rules::deprecated_function(checker, expr);
|
||||
}
|
||||
if checker.enabled(Rule::Numpy2Deprecation) {
|
||||
numpy::rules::numpy_2_0_deprecation(checker, expr);
|
||||
}
|
||||
if checker.enabled(Rule::DeprecatedMockImport) {
|
||||
pyupgrade::rules::deprecated_mock_attribute(checker, expr);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::rules::{
|
||||
airflow, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_debugger,
|
||||
flake8_django, flake8_errmsg, flake8_import_conventions, flake8_pie, flake8_pyi,
|
||||
flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_slots,
|
||||
flake8_tidy_imports, flake8_type_checking, mccabe, pandas_vet, pep8_naming, perflint,
|
||||
pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
|
||||
flake8_tidy_imports, flake8_trio, flake8_type_checking, mccabe, pandas_vet, pep8_naming,
|
||||
perflint, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
|
||||
};
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
@@ -1195,6 +1195,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::UselessWithLock) {
|
||||
pylint::rules::useless_with_lock(checker, with_stmt);
|
||||
}
|
||||
if checker.enabled(Rule::TrioTimeoutWithoutAwait) {
|
||||
flake8_trio::rules::timeout_without_await(checker, with_stmt, items);
|
||||
}
|
||||
}
|
||||
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
|
||||
if checker.enabled(Rule::FunctionUsesLoopVariable) {
|
||||
|
||||
@@ -290,6 +290,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Flake8Async, "101") => (RuleGroup::Stable, rules::flake8_async::rules::OpenSleepOrSubprocessInAsyncFunction),
|
||||
(Flake8Async, "102") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingOsCallInAsyncFunction),
|
||||
|
||||
// flake8-trio
|
||||
(Flake8Trio, "100") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioTimeoutWithoutAwait),
|
||||
|
||||
// flake8-builtins
|
||||
(Flake8Builtins, "001") => (RuleGroup::Stable, rules::flake8_builtins::rules::BuiltinVariableShadowing),
|
||||
(Flake8Builtins, "002") => (RuleGroup::Stable, rules::flake8_builtins::rules::BuiltinArgumentShadowing),
|
||||
@@ -856,6 +859,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Numpy, "001") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedTypeAlias),
|
||||
(Numpy, "002") => (RuleGroup::Stable, rules::numpy::rules::NumpyLegacyRandom),
|
||||
(Numpy, "003") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedFunction),
|
||||
(Numpy, "201") => (RuleGroup::Preview, rules::numpy::rules::Numpy2Deprecation),
|
||||
|
||||
// ruff
|
||||
(Ruff, "001") => (RuleGroup::Stable, rules::ruff::rules::AmbiguousUnicodeCharacterString),
|
||||
|
||||
@@ -64,6 +64,9 @@ pub enum Linter {
|
||||
/// [flake8-async](https://pypi.org/project/flake8-async/)
|
||||
#[prefix = "ASYNC"]
|
||||
Flake8Async,
|
||||
/// [flake8-trio](https://pypi.org/project/flake8-trio/)
|
||||
#[prefix = "TRIO"]
|
||||
Flake8Trio,
|
||||
/// [flake8-bandit](https://pypi.org/project/flake8-bandit/)
|
||||
#[prefix = "S"]
|
||||
Flake8Bandit,
|
||||
|
||||
26
crates/ruff_linter/src/rules/flake8_trio/mod.rs
Normal file
26
crates/ruff_linter/src/rules/flake8_trio/mod.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
//! Rules from [flake8-trio](https://pypi.org/project/flake8-trio/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::assert_messages;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::LinterSettings;
|
||||
use crate::test::test_path;
|
||||
|
||||
#[test_case(Rule::TrioTimeoutWithoutAwait, Path::new("TRIO100.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_trio").join(path).as_path(),
|
||||
&LinterSettings::for_rule(rule_code),
|
||||
)?;
|
||||
assert_messages!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
3
crates/ruff_linter/src/rules/flake8_trio/rules/mod.rs
Normal file
3
crates/ruff_linter/src/rules/flake8_trio/rules/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub(crate) use timeout_without_await::*;
|
||||
|
||||
mod timeout_without_await;
|
||||
@@ -0,0 +1,125 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::CallPath;
|
||||
use ruff_python_ast::visitor::{walk_expr, walk_stmt, Visitor};
|
||||
use ruff_python_ast::{Expr, ExprAwait, Stmt, StmtWith, WithItem};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for trio functions that should contain await but don't.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Some trio context managers, such as `trio.fail_after` and
|
||||
/// `trio.move_on_after`, have no effect unless they contain an `await`
|
||||
/// statement. The use of such functions without an `await` statement is
|
||||
/// likely a mistake.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// async def func():
|
||||
/// with trio.move_on_after(2):
|
||||
/// do_something()
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// async def func():
|
||||
/// with trio.move_on_after(2):
|
||||
/// do_something()
|
||||
/// await awaitable()
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct TrioTimeoutWithoutAwait {
|
||||
method_name: MethodName,
|
||||
}
|
||||
|
||||
impl Violation for TrioTimeoutWithoutAwait {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let Self { method_name } = self;
|
||||
format!("A `with {method_name}(...):` context does not contain any `await` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint.")
|
||||
}
|
||||
}
|
||||
|
||||
/// TRIO100
|
||||
pub(crate) fn timeout_without_await(
|
||||
checker: &mut Checker,
|
||||
with_stmt: &StmtWith,
|
||||
with_items: &[WithItem],
|
||||
) {
|
||||
let Some(method_name) = with_items.iter().find_map(|item| {
|
||||
let call = item.context_expr.as_call_expr()?;
|
||||
let call_path = checker.semantic().resolve_call_path(call.func.as_ref())?;
|
||||
MethodName::try_from(&call_path)
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut visitor = AwaitVisitor::default();
|
||||
visitor.visit_body(&with_stmt.body);
|
||||
if visitor.seen_await {
|
||||
return;
|
||||
}
|
||||
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
TrioTimeoutWithoutAwait { method_name },
|
||||
with_stmt.range,
|
||||
));
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum MethodName {
|
||||
MoveOnAfter,
|
||||
MoveOnAt,
|
||||
FailAfter,
|
||||
FailAt,
|
||||
CancelScope,
|
||||
}
|
||||
|
||||
impl MethodName {
|
||||
fn try_from(call_path: &CallPath<'_>) -> Option<Self> {
|
||||
match call_path.as_slice() {
|
||||
["trio", "move_on_after"] => Some(Self::MoveOnAfter),
|
||||
["trio", "move_on_at"] => Some(Self::MoveOnAt),
|
||||
["trio", "fail_after"] => Some(Self::FailAfter),
|
||||
["trio", "fail_at"] => Some(Self::FailAt),
|
||||
["trio", "CancelScope"] => Some(Self::CancelScope),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MethodName {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
MethodName::MoveOnAfter => write!(f, "trio.move_on_after"),
|
||||
MethodName::MoveOnAt => write!(f, "trio.move_on_at"),
|
||||
MethodName::FailAfter => write!(f, "trio.fail_after"),
|
||||
MethodName::FailAt => write!(f, "trio.fail_at"),
|
||||
MethodName::CancelScope => write!(f, "trio.CancelScope"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct AwaitVisitor {
|
||||
seen_await: bool,
|
||||
}
|
||||
|
||||
impl Visitor<'_> for AwaitVisitor {
|
||||
fn visit_stmt(&mut self, stmt: &Stmt) {
|
||||
match stmt {
|
||||
Stmt::FunctionDef(_) | Stmt::ClassDef(_) => (),
|
||||
_ => walk_stmt(self, stmt),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &Expr) {
|
||||
if let Expr::Await(ExprAwait { .. }) = expr {
|
||||
self.seen_await = true;
|
||||
} else {
|
||||
walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_trio/mod.rs
|
||||
---
|
||||
TRIO100.py:5:5: TRIO100 A `with trio.fail_after(...):` context does not contain any `await` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint.
|
||||
|
|
||||
4 | async def foo():
|
||||
5 | with trio.fail_after():
|
||||
| _____^
|
||||
6 | | ...
|
||||
| |___________^ TRIO100
|
||||
7 |
|
||||
8 | async def foo():
|
||||
|
|
||||
|
||||
TRIO100.py:13:5: TRIO100 A `with trio.move_on_after(...):` context does not contain any `await` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint.
|
||||
|
|
||||
12 | async def foo():
|
||||
13 | with trio.move_on_after():
|
||||
| _____^
|
||||
14 | | ...
|
||||
| |___________^ TRIO100
|
||||
15 |
|
||||
16 | async def foo():
|
||||
|
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ pub mod flake8_simplify;
|
||||
pub mod flake8_slots;
|
||||
pub mod flake8_tidy_imports;
|
||||
pub mod flake8_todos;
|
||||
pub mod flake8_trio;
|
||||
pub mod flake8_type_checking;
|
||||
pub mod flake8_unused_arguments;
|
||||
pub mod flake8_use_pathlib;
|
||||
|
||||
@@ -16,6 +16,7 @@ mod tests {
|
||||
#[test_case(Rule::NumpyDeprecatedTypeAlias, Path::new("NPY001.py"))]
|
||||
#[test_case(Rule::NumpyLegacyRandom, Path::new("NPY002.py"))]
|
||||
#[test_case(Rule::NumpyDeprecatedFunction, Path::new("NPY003.py"))]
|
||||
#[test_case(Rule::Numpy2Deprecation, Path::new("NPY201.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
pub(crate) use deprecated_function::*;
|
||||
pub(crate) use deprecated_type_alias::*;
|
||||
pub(crate) use legacy_random::*;
|
||||
pub(crate) use numpy_2_0_deprecation::*;
|
||||
|
||||
mod deprecated_function;
|
||||
mod deprecated_type_alias;
|
||||
mod legacy_random;
|
||||
mod numpy_2_0_deprecation;
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::importer::ImportRequest;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of NumPy functions and constants that were removed from
|
||||
/// the main namespace in NumPy 2.0.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// NumPy 2.0 includes an overhaul of NumPy's Python API, intended to remove
|
||||
/// redundant aliases and routines, and establish unambiguous mechanisms for
|
||||
/// accessing constants, dtypes, and functions.
|
||||
///
|
||||
/// As part of this overhaul, a variety of deprecated NumPy functions and
|
||||
/// constants were removed from the main namespace.
|
||||
///
|
||||
/// The majority of these functions and constants can be automatically replaced
|
||||
/// by other members of the NumPy API, even prior to NumPy 2.0, or by
|
||||
/// equivalents from the Python standard library. This rule flags all uses of
|
||||
/// removed members, along with automatic fixes for any backwards-compatible
|
||||
/// replacements.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```python
|
||||
/// import numpy as np
|
||||
///
|
||||
/// arr1 = [np.Infinity, np.NaN, np.nan, np.PINF, np.inf]
|
||||
/// arr2 = [np.float_(1.5), np.float64(5.1)]
|
||||
/// np.round_(arr2)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// import numpy as np
|
||||
///
|
||||
/// arr1 = [np.inf, np.nan, np.nan, np.inf, np.inf]
|
||||
/// arr2 = [np.float64(1.5), np.float64(5.1)]
|
||||
/// np.round(arr2)
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct Numpy2Deprecation {
|
||||
existing: String,
|
||||
migration_guide: Option<String>,
|
||||
}
|
||||
|
||||
impl Violation for Numpy2Deprecation {
|
||||
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let Numpy2Deprecation {
|
||||
existing,
|
||||
migration_guide,
|
||||
} = self;
|
||||
match migration_guide {
|
||||
Some(migration_guide) => {
|
||||
format!("`np.{existing}` will be removed in NumPy 2.0. {migration_guide}",)
|
||||
}
|
||||
None => format!("`np.{existing}` will be removed without replacement in NumPy 2.0."),
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> Option<String> {
|
||||
let Numpy2Deprecation {
|
||||
existing: _,
|
||||
migration_guide,
|
||||
} = self;
|
||||
migration_guide.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Replacement<'a> {
|
||||
existing: &'a str,
|
||||
details: Details<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Details<'a> {
|
||||
/// The deprecated member can be replaced by another member in the NumPy API.
|
||||
AutoImport { path: &'a str, name: &'a str },
|
||||
/// The deprecated member can be replaced by a member of the Python standard library.
|
||||
AutoPurePython { python_expr: &'a str },
|
||||
/// The deprecated member can be replaced by a manual migration.
|
||||
Manual { guideline: Option<&'a str> },
|
||||
}
|
||||
|
||||
impl Details<'_> {
|
||||
fn guideline(&self) -> Option<String> {
|
||||
match self {
|
||||
Details::AutoImport { path, name } => Some(format!("Use `{path}.{name}` instead.")),
|
||||
Details::AutoPurePython { python_expr } => {
|
||||
Some(format!("Use `{python_expr}` instead."))
|
||||
}
|
||||
Details::Manual { guideline } => guideline.map(ToString::to_string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// NPY201
|
||||
pub(crate) fn numpy_2_0_deprecation(checker: &mut Checker, expr: &Expr) {
|
||||
let maybe_replacement = checker
|
||||
.semantic()
|
||||
.resolve_call_path(expr)
|
||||
.and_then(|call_path| match call_path.as_slice() {
|
||||
// NumPy's main namespace np.* members removed in 2.0
|
||||
["numpy", "add_docstring"] => Some(Replacement {
|
||||
existing: "add_docstring",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy.lib",
|
||||
name: "add_docstring",
|
||||
},
|
||||
}),
|
||||
["numpy", "add_newdoc"] => Some(Replacement {
|
||||
existing: "add_newdoc",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy.lib",
|
||||
name: "add_newdoc",
|
||||
},
|
||||
}),
|
||||
["numpy", "add_newdoc_ufunc"] => Some(Replacement {
|
||||
existing: "add_newdoc_ufunc",
|
||||
details: Details::Manual {
|
||||
guideline: Some("`add_newdoc_ufunc` is an internal function."),
|
||||
},
|
||||
}),
|
||||
["numpy", "asfarray"] => Some(Replacement {
|
||||
existing: "asfarray",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `np.asarray` with a `float` dtype instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "byte_bounds"] => Some(Replacement {
|
||||
existing: "byte_bounds",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy.lib.array_utils",
|
||||
name: "byte_bounds",
|
||||
},
|
||||
}),
|
||||
["numpy", "cast"] => Some(Replacement {
|
||||
existing: "cast",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `np.asarray(arr, dtype=dtype)` instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "cfloat"] => Some(Replacement {
|
||||
existing: "cfloat",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "complex128",
|
||||
},
|
||||
}),
|
||||
["numpy", "clongfloat"] => Some(Replacement {
|
||||
existing: "clongfloat",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "clongdouble",
|
||||
},
|
||||
}),
|
||||
["numpy", "compat"] => Some(Replacement {
|
||||
existing: "compat",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Python 2 is no longer supported."),
|
||||
},
|
||||
}),
|
||||
["numpy", "complex_"] => Some(Replacement {
|
||||
existing: "complex_",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "complex128",
|
||||
},
|
||||
}),
|
||||
["numpy", "DataSource"] => Some(Replacement {
|
||||
existing: "DataSource",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy.lib.npyio",
|
||||
name: "DataSource",
|
||||
},
|
||||
}),
|
||||
["numpy", "deprecate"] => Some(Replacement {
|
||||
existing: "deprecate",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Emit `DeprecationWarning` with `warnings.warn` directly, or use `typing.deprecated`."),
|
||||
},
|
||||
}),
|
||||
["numpy", "deprecate_with_doc"] => Some(Replacement {
|
||||
existing: "deprecate_with_doc",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Emit `DeprecationWarning` with `warnings.warn` directly, or use `typing.deprecated`."),
|
||||
},
|
||||
}),
|
||||
["numpy", "disp"] => Some(Replacement {
|
||||
existing: "disp",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use a dedicated print function instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "fastCopyAndTranspose"] => Some(Replacement {
|
||||
existing: "fastCopyAndTranspose",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `arr.T.copy()` instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "find_common_type"] => Some(Replacement {
|
||||
existing: "find_common_type",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `numpy.promote_types` or `numpy.result_type` instead. To achieve semantics for the `scalar_types` argument, use `numpy.result_type` and pass the Python values `0`, `0.0`, or `0j`."),
|
||||
},
|
||||
}),
|
||||
["numpy", "get_array_wrap"] => Some(Replacement {
|
||||
existing: "get_array_wrap",
|
||||
details: Details::Manual {
|
||||
guideline: None,
|
||||
},
|
||||
}),
|
||||
["numpy", "float_"] => Some(Replacement {
|
||||
existing: "float_",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "float64",
|
||||
},
|
||||
}),
|
||||
["numpy", "geterrobj"] => Some(Replacement {
|
||||
existing: "geterrobj",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use the `np.errstate` context manager instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "INF"] => Some(Replacement {
|
||||
existing: "INF",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "inf",
|
||||
},
|
||||
}),
|
||||
["numpy", "Inf"] => Some(Replacement {
|
||||
existing: "Inf",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "inf",
|
||||
},
|
||||
}),
|
||||
["numpy", "Infinity"] => Some(Replacement {
|
||||
existing: "Infinity",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "inf",
|
||||
},
|
||||
}),
|
||||
["numpy", "infty"] => Some(Replacement {
|
||||
existing: "infty",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "inf",
|
||||
},
|
||||
}),
|
||||
["numpy", "issctype"] => Some(Replacement {
|
||||
existing: "issctype",
|
||||
details: Details::Manual {
|
||||
guideline: None,
|
||||
},
|
||||
}),
|
||||
["numpy", "issubclass_"] => Some(Replacement {
|
||||
existing: "issubclass_",
|
||||
details: Details::AutoPurePython {
|
||||
python_expr: "issubclass",
|
||||
},
|
||||
}),
|
||||
["numpy", "issubsctype"] => Some(Replacement {
|
||||
existing: "issubsctype",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "issubdtype",
|
||||
},
|
||||
}),
|
||||
["numpy", "mat"] => Some(Replacement {
|
||||
existing: "mat",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "asmatrix",
|
||||
},
|
||||
}),
|
||||
["numpy", "maximum_sctype"] => Some(Replacement {
|
||||
existing: "maximum_sctype",
|
||||
details: Details::Manual {
|
||||
guideline: None,
|
||||
},
|
||||
}),
|
||||
["numpy", "NaN"] => Some(Replacement {
|
||||
existing: "NaN",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "nan",
|
||||
},
|
||||
}),
|
||||
["numpy", "nbytes"] => Some(Replacement {
|
||||
existing: "nbytes",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `np.dtype(<dtype>).itemsize` instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "NINF"] => Some(Replacement {
|
||||
existing: "NINF",
|
||||
details: Details::AutoPurePython {
|
||||
python_expr: "-np.inf",
|
||||
},
|
||||
}),
|
||||
["numpy", "NZERO"] => Some(Replacement {
|
||||
existing: "NZERO",
|
||||
details: Details::AutoPurePython {
|
||||
python_expr: "-0.0",
|
||||
},
|
||||
}),
|
||||
["numpy", "longcomplex"] => Some(Replacement {
|
||||
existing: "longcomplex",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "clongdouble",
|
||||
},
|
||||
}),
|
||||
["numpy", "longfloat"] => Some(Replacement {
|
||||
existing: "longfloat",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "longdouble",
|
||||
},
|
||||
}),
|
||||
["numpy", "lookfor"] => Some(Replacement {
|
||||
existing: "lookfor",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Search NumPy’s documentation directly."),
|
||||
},
|
||||
}),
|
||||
["numpy", "obj2sctype"] => Some(Replacement {
|
||||
existing: "obj2sctype",
|
||||
details: Details::Manual {
|
||||
guideline: None,
|
||||
},
|
||||
}),
|
||||
["numpy", "PINF"] => Some(Replacement {
|
||||
existing: "PINF",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "inf",
|
||||
},
|
||||
}),
|
||||
["numpy", "PZERO"] => Some(Replacement {
|
||||
existing: "PZERO",
|
||||
details: Details::AutoPurePython { python_expr: "0.0" },
|
||||
}),
|
||||
["numpy", "recfromcsv"] => Some(Replacement {
|
||||
existing: "recfromcsv",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `np.genfromtxt` with comma delimiter instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "recfromtxt"] => Some(Replacement {
|
||||
existing: "recfromtxt",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `np.genfromtxt` instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "round_"] => Some(Replacement {
|
||||
existing: "round_",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "round",
|
||||
},
|
||||
}),
|
||||
["numpy", "safe_eval"] => Some(Replacement {
|
||||
existing: "safe_eval",
|
||||
details: Details::AutoImport {
|
||||
path: "ast",
|
||||
name: "literal_eval",
|
||||
},
|
||||
}),
|
||||
["numpy", "sctype2char"] => Some(Replacement {
|
||||
existing: "sctype2char",
|
||||
details: Details::Manual {
|
||||
guideline: None,
|
||||
},
|
||||
}),
|
||||
["numpy", "sctypes"] => Some(Replacement {
|
||||
existing: "sctypes",
|
||||
details: Details::Manual {
|
||||
guideline: None,
|
||||
},
|
||||
}),
|
||||
["numpy", "seterrobj"] => Some(Replacement {
|
||||
existing: "seterrobj",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use the `np.errstate` context manager instead."),
|
||||
},
|
||||
}),
|
||||
["numpy", "set_string_function"] => Some(Replacement {
|
||||
existing: "set_string_function",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use `np.set_printoptions` for custom printing of NumPy objects."),
|
||||
},
|
||||
}),
|
||||
["numpy", "singlecomplex"] => Some(Replacement {
|
||||
existing: "singlecomplex",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "complex64",
|
||||
},
|
||||
}),
|
||||
["numpy", "string_"] => Some(Replacement {
|
||||
existing: "string_",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "bytes_",
|
||||
},
|
||||
}),
|
||||
["numpy", "source"] => Some(Replacement {
|
||||
existing: "source",
|
||||
details: Details::AutoImport {
|
||||
path: "inspect",
|
||||
name: "getsource",
|
||||
},
|
||||
}),
|
||||
["numpy", "tracemalloc_domain"] => Some(Replacement {
|
||||
existing: "tracemalloc_domain",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy.lib",
|
||||
name: "tracemalloc_domain",
|
||||
},
|
||||
}),
|
||||
["numpy", "unicode_"] => Some(Replacement {
|
||||
existing: "unicode_",
|
||||
details: Details::AutoImport {
|
||||
path: "numpy",
|
||||
name: "str_",
|
||||
},
|
||||
}),
|
||||
["numpy", "who"] => Some(Replacement {
|
||||
existing: "who",
|
||||
details: Details::Manual {
|
||||
guideline: Some("Use an IDE variable explorer or `locals()` instead."),
|
||||
},
|
||||
}),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if let Some(replacement) = maybe_replacement {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
Numpy2Deprecation {
|
||||
existing: replacement.existing.to_string(),
|
||||
migration_guide: replacement.details.guideline(),
|
||||
},
|
||||
expr.range(),
|
||||
);
|
||||
match replacement.details {
|
||||
Details::AutoImport { path, name } => {
|
||||
diagnostic.try_set_fix(|| {
|
||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||
&ImportRequest::import_from(path, name),
|
||||
expr.start(),
|
||||
checker.semantic(),
|
||||
)?;
|
||||
let replacement_edit = Edit::range_replacement(binding, expr.range());
|
||||
Ok(Fix::safe_edits(import_edit, [replacement_edit]))
|
||||
});
|
||||
}
|
||||
Details::AutoPurePython { python_expr } => diagnostic.set_fix(Fix::safe_edit(
|
||||
Edit::range_replacement(python_expr.to_string(), expr.range()),
|
||||
)),
|
||||
Details::Manual { guideline: _ } => {}
|
||||
};
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,865 @@
|
||||
---
|
||||
source: crates/ruff_linter/src/rules/numpy/mod.rs
|
||||
---
|
||||
NPY201.py:4:5: NPY201 [*] `np.add_docstring` will be removed in NumPy 2.0. Use `numpy.lib.add_docstring` instead.
|
||||
|
|
||||
2 | import numpy as np
|
||||
3 |
|
||||
4 | np.add_docstring
|
||||
| ^^^^^^^^^^^^^^^^ NPY201
|
||||
5 |
|
||||
6 | np.add_newdoc
|
||||
|
|
||||
= help: Use `numpy.lib.add_docstring` instead.
|
||||
|
||||
ℹ Fix
|
||||
1 |+from numpy.lib import add_docstring
|
||||
1 2 | def func():
|
||||
2 3 | import numpy as np
|
||||
3 4 |
|
||||
4 |- np.add_docstring
|
||||
5 |+ add_docstring
|
||||
5 6 |
|
||||
6 7 | np.add_newdoc
|
||||
7 8 |
|
||||
|
||||
NPY201.py:6:5: NPY201 [*] `np.add_newdoc` will be removed in NumPy 2.0. Use `numpy.lib.add_newdoc` instead.
|
||||
|
|
||||
4 | np.add_docstring
|
||||
5 |
|
||||
6 | np.add_newdoc
|
||||
| ^^^^^^^^^^^^^ NPY201
|
||||
7 |
|
||||
8 | np.add_newdoc_ufunc
|
||||
|
|
||||
= help: Use `numpy.lib.add_newdoc` instead.
|
||||
|
||||
ℹ Fix
|
||||
1 |+from numpy.lib import add_newdoc
|
||||
1 2 | def func():
|
||||
2 3 | import numpy as np
|
||||
3 4 |
|
||||
4 5 | np.add_docstring
|
||||
5 6 |
|
||||
6 |- np.add_newdoc
|
||||
7 |+ add_newdoc
|
||||
7 8 |
|
||||
8 9 | np.add_newdoc_ufunc
|
||||
9 10 |
|
||||
|
||||
NPY201.py:8:5: NPY201 `np.add_newdoc_ufunc` will be removed in NumPy 2.0. `add_newdoc_ufunc` is an internal function.
|
||||
|
|
||||
6 | np.add_newdoc
|
||||
7 |
|
||||
8 | np.add_newdoc_ufunc
|
||||
| ^^^^^^^^^^^^^^^^^^^ NPY201
|
||||
9 |
|
||||
10 | np.asfarray([1,2,3])
|
||||
|
|
||||
= help: `add_newdoc_ufunc` is an internal function.
|
||||
|
||||
NPY201.py:10:5: NPY201 `np.asfarray` will be removed in NumPy 2.0. Use `np.asarray` with a `float` dtype instead.
|
||||
|
|
||||
8 | np.add_newdoc_ufunc
|
||||
9 |
|
||||
10 | np.asfarray([1,2,3])
|
||||
| ^^^^^^^^^^^ NPY201
|
||||
11 |
|
||||
12 | np.byte_bounds(np.array([1,2,3]))
|
||||
|
|
||||
= help: Use `np.asarray` with a `float` dtype instead.
|
||||
|
||||
NPY201.py:12:5: NPY201 [*] `np.byte_bounds` will be removed in NumPy 2.0. Use `numpy.lib.array_utils.byte_bounds` instead.
|
||||
|
|
||||
10 | np.asfarray([1,2,3])
|
||||
11 |
|
||||
12 | np.byte_bounds(np.array([1,2,3]))
|
||||
| ^^^^^^^^^^^^^^ NPY201
|
||||
13 |
|
||||
14 | np.cast
|
||||
|
|
||||
= help: Use `numpy.lib.array_utils.byte_bounds` instead.
|
||||
|
||||
ℹ Fix
|
||||
1 |+from numpy.lib.array_utils import byte_bounds
|
||||
1 2 | def func():
|
||||
2 3 | import numpy as np
|
||||
3 4 |
|
||||
--------------------------------------------------------------------------------
|
||||
9 10 |
|
||||
10 11 | np.asfarray([1,2,3])
|
||||
11 12 |
|
||||
12 |- np.byte_bounds(np.array([1,2,3]))
|
||||
13 |+ byte_bounds(np.array([1,2,3]))
|
||||
13 14 |
|
||||
14 15 | np.cast
|
||||
15 16 |
|
||||
|
||||
NPY201.py:14:5: NPY201 `np.cast` will be removed in NumPy 2.0. Use `np.asarray(arr, dtype=dtype)` instead.
|
||||
|
|
||||
12 | np.byte_bounds(np.array([1,2,3]))
|
||||
13 |
|
||||
14 | np.cast
|
||||
| ^^^^^^^ NPY201
|
||||
15 |
|
||||
16 | np.cfloat(12+34j)
|
||||
|
|
||||
= help: Use `np.asarray(arr, dtype=dtype)` instead.
|
||||
|
||||
NPY201.py:16:5: NPY201 [*] `np.cfloat` will be removed in NumPy 2.0. Use `numpy.complex128` instead.
|
||||
|
|
||||
14 | np.cast
|
||||
15 |
|
||||
16 | np.cfloat(12+34j)
|
||||
| ^^^^^^^^^ NPY201
|
||||
17 |
|
||||
18 | np.clongfloat(12+34j)
|
||||
|
|
||||
= help: Use `numpy.complex128` instead.
|
||||
|
||||
ℹ Fix
|
||||
13 13 |
|
||||
14 14 | np.cast
|
||||
15 15 |
|
||||
16 |- np.cfloat(12+34j)
|
||||
16 |+ np.complex128(12+34j)
|
||||
17 17 |
|
||||
18 18 | np.clongfloat(12+34j)
|
||||
19 19 |
|
||||
|
||||
NPY201.py:18:5: NPY201 [*] `np.clongfloat` will be removed in NumPy 2.0. Use `numpy.clongdouble` instead.
|
||||
|
|
||||
16 | np.cfloat(12+34j)
|
||||
17 |
|
||||
18 | np.clongfloat(12+34j)
|
||||
| ^^^^^^^^^^^^^ NPY201
|
||||
19 |
|
||||
20 | np.compat
|
||||
|
|
||||
= help: Use `numpy.clongdouble` instead.
|
||||
|
||||
ℹ Fix
|
||||
15 15 |
|
||||
16 16 | np.cfloat(12+34j)
|
||||
17 17 |
|
||||
18 |- np.clongfloat(12+34j)
|
||||
18 |+ np.clongdouble(12+34j)
|
||||
19 19 |
|
||||
20 20 | np.compat
|
||||
21 21 |
|
||||
|
||||
NPY201.py:20:5: NPY201 `np.compat` will be removed in NumPy 2.0. Python 2 is no longer supported.
|
||||
|
|
||||
18 | np.clongfloat(12+34j)
|
||||
19 |
|
||||
20 | np.compat
|
||||
| ^^^^^^^^^ NPY201
|
||||
21 |
|
||||
22 | np.complex_(12+34j)
|
||||
|
|
||||
= help: Python 2 is no longer supported.
|
||||
|
||||
NPY201.py:22:5: NPY201 [*] `np.complex_` will be removed in NumPy 2.0. Use `numpy.complex128` instead.
|
||||
|
|
||||
20 | np.compat
|
||||
21 |
|
||||
22 | np.complex_(12+34j)
|
||||
| ^^^^^^^^^^^ NPY201
|
||||
23 |
|
||||
24 | np.DataSource
|
||||
|
|
||||
= help: Use `numpy.complex128` instead.
|
||||
|
||||
ℹ Fix
|
||||
19 19 |
|
||||
20 20 | np.compat
|
||||
21 21 |
|
||||
22 |- np.complex_(12+34j)
|
||||
22 |+ np.complex128(12+34j)
|
||||
23 23 |
|
||||
24 24 | np.DataSource
|
||||
25 25 |
|
||||
|
||||
NPY201.py:24:5: NPY201 [*] `np.DataSource` will be removed in NumPy 2.0. Use `numpy.lib.npyio.DataSource` instead.
|
||||
|
|
||||
22 | np.complex_(12+34j)
|
||||
23 |
|
||||
24 | np.DataSource
|
||||
| ^^^^^^^^^^^^^ NPY201
|
||||
25 |
|
||||
26 | np.deprecate
|
||||
|
|
||||
= help: Use `numpy.lib.npyio.DataSource` instead.
|
||||
|
||||
ℹ Fix
|
||||
1 |+from numpy.lib.npyio import DataSource
|
||||
1 2 | def func():
|
||||
2 3 | import numpy as np
|
||||
3 4 |
|
||||
--------------------------------------------------------------------------------
|
||||
21 22 |
|
||||
22 23 | np.complex_(12+34j)
|
||||
23 24 |
|
||||
24 |- np.DataSource
|
||||
25 |+ DataSource
|
||||
25 26 |
|
||||
26 27 | np.deprecate
|
||||
27 28 |
|
||||
|
||||
NPY201.py:26:5: NPY201 `np.deprecate` will be removed in NumPy 2.0. Emit `DeprecationWarning` with `warnings.warn` directly, or use `typing.deprecated`.
|
||||
|
|
||||
24 | np.DataSource
|
||||
25 |
|
||||
26 | np.deprecate
|
||||
| ^^^^^^^^^^^^ NPY201
|
||||
27 |
|
||||
28 | np.deprecate_with_doc
|
||||
|
|
||||
= help: Emit `DeprecationWarning` with `warnings.warn` directly, or use `typing.deprecated`.
|
||||
|
||||
NPY201.py:28:5: NPY201 `np.deprecate_with_doc` will be removed in NumPy 2.0. Emit `DeprecationWarning` with `warnings.warn` directly, or use `typing.deprecated`.
|
||||
|
|
||||
26 | np.deprecate
|
||||
27 |
|
||||
28 | np.deprecate_with_doc
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ NPY201
|
||||
29 |
|
||||
30 | np.disp(10)
|
||||
|
|
||||
= help: Emit `DeprecationWarning` with `warnings.warn` directly, or use `typing.deprecated`.
|
||||
|
||||
NPY201.py:30:5: NPY201 `np.disp` will be removed in NumPy 2.0. Use a dedicated print function instead.
|
||||
|
|
||||
28 | np.deprecate_with_doc
|
||||
29 |
|
||||
30 | np.disp(10)
|
||||
| ^^^^^^^ NPY201
|
||||
31 |
|
||||
32 | np.fastCopyAndTranspose
|
||||
|
|
||||
= help: Use a dedicated print function instead.
|
||||
|
||||
NPY201.py:32:5: NPY201 `np.fastCopyAndTranspose` will be removed in NumPy 2.0. Use `arr.T.copy()` instead.
|
||||
|
|
||||
30 | np.disp(10)
|
||||
31 |
|
||||
32 | np.fastCopyAndTranspose
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ NPY201
|
||||
33 |
|
||||
34 | np.find_common_type
|
||||
|
|
||||
= help: Use `arr.T.copy()` instead.
|
||||
|
||||
NPY201.py:34:5: NPY201 `np.find_common_type` will be removed in NumPy 2.0. Use `numpy.promote_types` or `numpy.result_type` instead. To achieve semantics for the `scalar_types` argument, use `numpy.result_type` and pass the Python values `0`, `0.0`, or `0j`.
|
||||
|
|
||||
32 | np.fastCopyAndTranspose
|
||||
33 |
|
||||
34 | np.find_common_type
|
||||
| ^^^^^^^^^^^^^^^^^^^ NPY201
|
||||
35 |
|
||||
36 | np.get_array_wrap
|
||||
|
|
||||
= help: Use `numpy.promote_types` or `numpy.result_type` instead. To achieve semantics for the `scalar_types` argument, use `numpy.result_type` and pass the Python values `0`, `0.0`, or `0j`.
|
||||
|
||||
NPY201.py:36:5: NPY201 `np.get_array_wrap` will be removed without replacement in NumPy 2.0.
|
||||
|
|
||||
34 | np.find_common_type
|
||||
35 |
|
||||
36 | np.get_array_wrap
|
||||
| ^^^^^^^^^^^^^^^^^ NPY201
|
||||
37 |
|
||||
38 | np.float_
|
||||
|
|
||||
|
||||
NPY201.py:38:5: NPY201 [*] `np.float_` will be removed in NumPy 2.0. Use `numpy.float64` instead.
|
||||
|
|
||||
36 | np.get_array_wrap
|
||||
37 |
|
||||
38 | np.float_
|
||||
| ^^^^^^^^^ NPY201
|
||||
39 |
|
||||
40 | np.geterrobj
|
||||
|
|
||||
= help: Use `numpy.float64` instead.
|
||||
|
||||
ℹ Fix
|
||||
35 35 |
|
||||
36 36 | np.get_array_wrap
|
||||
37 37 |
|
||||
38 |- np.float_
|
||||
38 |+ np.float64
|
||||
39 39 |
|
||||
40 40 | np.geterrobj
|
||||
41 41 |
|
||||
|
||||
NPY201.py:40:5: NPY201 `np.geterrobj` will be removed in NumPy 2.0. Use the `np.errstate` context manager instead.
|
||||
|
|
||||
38 | np.float_
|
||||
39 |
|
||||
40 | np.geterrobj
|
||||
| ^^^^^^^^^^^^ NPY201
|
||||
41 |
|
||||
42 | np.Inf
|
||||
|
|
||||
= help: Use the `np.errstate` context manager instead.
|
||||
|
||||
NPY201.py:42:5: NPY201 [*] `np.Inf` will be removed in NumPy 2.0. Use `numpy.inf` instead.
|
||||
|
|
||||
40 | np.geterrobj
|
||||
41 |
|
||||
42 | np.Inf
|
||||
| ^^^^^^ NPY201
|
||||
43 |
|
||||
44 | np.Infinity
|
||||
|
|
||||
= help: Use `numpy.inf` instead.
|
||||
|
||||
ℹ Fix
|
||||
39 39 |
|
||||
40 40 | np.geterrobj
|
||||
41 41 |
|
||||
42 |- np.Inf
|
||||
42 |+ np.inf
|
||||
43 43 |
|
||||
44 44 | np.Infinity
|
||||
45 45 |
|
||||
|
||||
NPY201.py:44:5: NPY201 [*] `np.Infinity` will be removed in NumPy 2.0. Use `numpy.inf` instead.
|
||||
|
|
||||
42 | np.Inf
|
||||
43 |
|
||||
44 | np.Infinity
|
||||
| ^^^^^^^^^^^ NPY201
|
||||
45 |
|
||||
46 | np.infty
|
||||
|
|
||||
= help: Use `numpy.inf` instead.
|
||||
|
||||
ℹ Fix
|
||||
41 41 |
|
||||
42 42 | np.Inf
|
||||
43 43 |
|
||||
44 |- np.Infinity
|
||||
44 |+ np.inf
|
||||
45 45 |
|
||||
46 46 | np.infty
|
||||
47 47 |
|
||||
|
||||
NPY201.py:46:5: NPY201 [*] `np.infty` will be removed in NumPy 2.0. Use `numpy.inf` instead.
|
||||
|
|
||||
44 | np.Infinity
|
||||
45 |
|
||||
46 | np.infty
|
||||
| ^^^^^^^^ NPY201
|
||||
47 |
|
||||
48 | np.issctype
|
||||
|
|
||||
= help: Use `numpy.inf` instead.
|
||||
|
||||
ℹ Fix
|
||||
43 43 |
|
||||
44 44 | np.Infinity
|
||||
45 45 |
|
||||
46 |- np.infty
|
||||
46 |+ np.inf
|
||||
47 47 |
|
||||
48 48 | np.issctype
|
||||
49 49 |
|
||||
|
||||
NPY201.py:48:5: NPY201 `np.issctype` will be removed without replacement in NumPy 2.0.
|
||||
|
|
||||
46 | np.infty
|
||||
47 |
|
||||
48 | np.issctype
|
||||
| ^^^^^^^^^^^ NPY201
|
||||
49 |
|
||||
50 | np.issubclass_(np.int32, np.integer)
|
||||
|
|
||||
|
||||
NPY201.py:50:5: NPY201 [*] `np.issubclass_` will be removed in NumPy 2.0. Use `issubclass` instead.
|
||||
|
|
||||
48 | np.issctype
|
||||
49 |
|
||||
50 | np.issubclass_(np.int32, np.integer)
|
||||
| ^^^^^^^^^^^^^^ NPY201
|
||||
51 |
|
||||
52 | np.issubsctype
|
||||
|
|
||||
= help: Use `issubclass` instead.
|
||||
|
||||
ℹ Fix
|
||||
47 47 |
|
||||
48 48 | np.issctype
|
||||
49 49 |
|
||||
50 |- np.issubclass_(np.int32, np.integer)
|
||||
50 |+ issubclass(np.int32, np.integer)
|
||||
51 51 |
|
||||
52 52 | np.issubsctype
|
||||
53 53 |
|
||||
|
||||
NPY201.py:52:5: NPY201 [*] `np.issubsctype` will be removed in NumPy 2.0. Use `numpy.issubdtype` instead.
|
||||
|
|
||||
50 | np.issubclass_(np.int32, np.integer)
|
||||
51 |
|
||||
52 | np.issubsctype
|
||||
| ^^^^^^^^^^^^^^ NPY201
|
||||
53 |
|
||||
54 | np.mat
|
||||
|
|
||||
= help: Use `numpy.issubdtype` instead.
|
||||
|
||||
ℹ Fix
|
||||
49 49 |
|
||||
50 50 | np.issubclass_(np.int32, np.integer)
|
||||
51 51 |
|
||||
52 |- np.issubsctype
|
||||
52 |+ np.issubdtype
|
||||
53 53 |
|
||||
54 54 | np.mat
|
||||
55 55 |
|
||||
|
||||
NPY201.py:54:5: NPY201 [*] `np.mat` will be removed in NumPy 2.0. Use `numpy.asmatrix` instead.
|
||||
|
|
||||
52 | np.issubsctype
|
||||
53 |
|
||||
54 | np.mat
|
||||
| ^^^^^^ NPY201
|
||||
55 |
|
||||
56 | np.maximum_sctype
|
||||
|
|
||||
= help: Use `numpy.asmatrix` instead.
|
||||
|
||||
ℹ Fix
|
||||
51 51 |
|
||||
52 52 | np.issubsctype
|
||||
53 53 |
|
||||
54 |- np.mat
|
||||
54 |+ np.asmatrix
|
||||
55 55 |
|
||||
56 56 | np.maximum_sctype
|
||||
57 57 |
|
||||
|
||||
NPY201.py:56:5: NPY201 `np.maximum_sctype` will be removed without replacement in NumPy 2.0.
|
||||
|
|
||||
54 | np.mat
|
||||
55 |
|
||||
56 | np.maximum_sctype
|
||||
| ^^^^^^^^^^^^^^^^^ NPY201
|
||||
57 |
|
||||
58 | np.NaN
|
||||
|
|
||||
|
||||
NPY201.py:58:5: NPY201 [*] `np.NaN` will be removed in NumPy 2.0. Use `numpy.nan` instead.
|
||||
|
|
||||
56 | np.maximum_sctype
|
||||
57 |
|
||||
58 | np.NaN
|
||||
| ^^^^^^ NPY201
|
||||
59 |
|
||||
60 | np.nbytes[np.int64]
|
||||
|
|
||||
= help: Use `numpy.nan` instead.
|
||||
|
||||
ℹ Fix
|
||||
55 55 |
|
||||
56 56 | np.maximum_sctype
|
||||
57 57 |
|
||||
58 |- np.NaN
|
||||
58 |+ np.nan
|
||||
59 59 |
|
||||
60 60 | np.nbytes[np.int64]
|
||||
61 61 |
|
||||
|
||||
NPY201.py:60:5: NPY201 `np.nbytes` will be removed in NumPy 2.0. Use `np.dtype(<dtype>).itemsize` instead.
|
||||
|
|
||||
58 | np.NaN
|
||||
59 |
|
||||
60 | np.nbytes[np.int64]
|
||||
| ^^^^^^^^^ NPY201
|
||||
61 |
|
||||
62 | np.NINF
|
||||
|
|
||||
= help: Use `np.dtype(<dtype>).itemsize` instead.
|
||||
|
||||
NPY201.py:62:5: NPY201 [*] `np.NINF` will be removed in NumPy 2.0. Use `-np.inf` instead.
|
||||
|
|
||||
60 | np.nbytes[np.int64]
|
||||
61 |
|
||||
62 | np.NINF
|
||||
| ^^^^^^^ NPY201
|
||||
63 |
|
||||
64 | np.NZERO
|
||||
|
|
||||
= help: Use `-np.inf` instead.
|
||||
|
||||
ℹ Fix
|
||||
59 59 |
|
||||
60 60 | np.nbytes[np.int64]
|
||||
61 61 |
|
||||
62 |- np.NINF
|
||||
62 |+ -np.inf
|
||||
63 63 |
|
||||
64 64 | np.NZERO
|
||||
65 65 |
|
||||
|
||||
NPY201.py:64:5: NPY201 [*] `np.NZERO` will be removed in NumPy 2.0. Use `-0.0` instead.
|
||||
|
|
||||
62 | np.NINF
|
||||
63 |
|
||||
64 | np.NZERO
|
||||
| ^^^^^^^^ NPY201
|
||||
65 |
|
||||
66 | np.longcomplex(12+34j)
|
||||
|
|
||||
= help: Use `-0.0` instead.
|
||||
|
||||
ℹ Fix
|
||||
61 61 |
|
||||
62 62 | np.NINF
|
||||
63 63 |
|
||||
64 |- np.NZERO
|
||||
64 |+ -0.0
|
||||
65 65 |
|
||||
66 66 | np.longcomplex(12+34j)
|
||||
67 67 |
|
||||
|
||||
NPY201.py:66:5: NPY201 [*] `np.longcomplex` will be removed in NumPy 2.0. Use `numpy.clongdouble` instead.
|
||||
|
|
||||
64 | np.NZERO
|
||||
65 |
|
||||
66 | np.longcomplex(12+34j)
|
||||
| ^^^^^^^^^^^^^^ NPY201
|
||||
67 |
|
||||
68 | np.longfloat(12+34j)
|
||||
|
|
||||
= help: Use `numpy.clongdouble` instead.
|
||||
|
||||
ℹ Fix
|
||||
63 63 |
|
||||
64 64 | np.NZERO
|
||||
65 65 |
|
||||
66 |- np.longcomplex(12+34j)
|
||||
66 |+ np.clongdouble(12+34j)
|
||||
67 67 |
|
||||
68 68 | np.longfloat(12+34j)
|
||||
69 69 |
|
||||
|
||||
NPY201.py:68:5: NPY201 [*] `np.longfloat` will be removed in NumPy 2.0. Use `numpy.longdouble` instead.
|
||||
|
|
||||
66 | np.longcomplex(12+34j)
|
||||
67 |
|
||||
68 | np.longfloat(12+34j)
|
||||
| ^^^^^^^^^^^^ NPY201
|
||||
69 |
|
||||
70 | np.lookfor
|
||||
|
|
||||
= help: Use `numpy.longdouble` instead.
|
||||
|
||||
ℹ Fix
|
||||
65 65 |
|
||||
66 66 | np.longcomplex(12+34j)
|
||||
67 67 |
|
||||
68 |- np.longfloat(12+34j)
|
||||
68 |+ np.longdouble(12+34j)
|
||||
69 69 |
|
||||
70 70 | np.lookfor
|
||||
71 71 |
|
||||
|
||||
NPY201.py:70:5: NPY201 `np.lookfor` will be removed in NumPy 2.0. Search NumPy’s documentation directly.
|
||||
|
|
||||
68 | np.longfloat(12+34j)
|
||||
69 |
|
||||
70 | np.lookfor
|
||||
| ^^^^^^^^^^ NPY201
|
||||
71 |
|
||||
72 | np.obj2sctype(int)
|
||||
|
|
||||
= help: Search NumPy’s documentation directly.
|
||||
|
||||
NPY201.py:72:5: NPY201 `np.obj2sctype` will be removed without replacement in NumPy 2.0.
|
||||
|
|
||||
70 | np.lookfor
|
||||
71 |
|
||||
72 | np.obj2sctype(int)
|
||||
| ^^^^^^^^^^^^^ NPY201
|
||||
73 |
|
||||
74 | np.PINF
|
||||
|
|
||||
|
||||
NPY201.py:74:5: NPY201 [*] `np.PINF` will be removed in NumPy 2.0. Use `numpy.inf` instead.
|
||||
|
|
||||
72 | np.obj2sctype(int)
|
||||
73 |
|
||||
74 | np.PINF
|
||||
| ^^^^^^^ NPY201
|
||||
75 |
|
||||
76 | np.PZERO
|
||||
|
|
||||
= help: Use `numpy.inf` instead.
|
||||
|
||||
ℹ Fix
|
||||
71 71 |
|
||||
72 72 | np.obj2sctype(int)
|
||||
73 73 |
|
||||
74 |- np.PINF
|
||||
74 |+ np.inf
|
||||
75 75 |
|
||||
76 76 | np.PZERO
|
||||
77 77 |
|
||||
|
||||
NPY201.py:76:5: NPY201 [*] `np.PZERO` will be removed in NumPy 2.0. Use `0.0` instead.
|
||||
|
|
||||
74 | np.PINF
|
||||
75 |
|
||||
76 | np.PZERO
|
||||
| ^^^^^^^^ NPY201
|
||||
77 |
|
||||
78 | np.recfromcsv
|
||||
|
|
||||
= help: Use `0.0` instead.
|
||||
|
||||
ℹ Fix
|
||||
73 73 |
|
||||
74 74 | np.PINF
|
||||
75 75 |
|
||||
76 |- np.PZERO
|
||||
76 |+ 0.0
|
||||
77 77 |
|
||||
78 78 | np.recfromcsv
|
||||
79 79 |
|
||||
|
||||
NPY201.py:78:5: NPY201 `np.recfromcsv` will be removed in NumPy 2.0. Use `np.genfromtxt` with comma delimiter instead.
|
||||
|
|
||||
76 | np.PZERO
|
||||
77 |
|
||||
78 | np.recfromcsv
|
||||
| ^^^^^^^^^^^^^ NPY201
|
||||
79 |
|
||||
80 | np.recfromtxt
|
||||
|
|
||||
= help: Use `np.genfromtxt` with comma delimiter instead.
|
||||
|
||||
NPY201.py:80:5: NPY201 `np.recfromtxt` will be removed in NumPy 2.0. Use `np.genfromtxt` instead.
|
||||
|
|
||||
78 | np.recfromcsv
|
||||
79 |
|
||||
80 | np.recfromtxt
|
||||
| ^^^^^^^^^^^^^ NPY201
|
||||
81 |
|
||||
82 | np.round_(12.34)
|
||||
|
|
||||
= help: Use `np.genfromtxt` instead.
|
||||
|
||||
NPY201.py:82:5: NPY201 [*] `np.round_` will be removed in NumPy 2.0. Use `numpy.round` instead.
|
||||
|
|
||||
80 | np.recfromtxt
|
||||
81 |
|
||||
82 | np.round_(12.34)
|
||||
| ^^^^^^^^^ NPY201
|
||||
83 |
|
||||
84 | np.safe_eval
|
||||
|
|
||||
= help: Use `numpy.round` instead.
|
||||
|
||||
ℹ Fix
|
||||
79 79 |
|
||||
80 80 | np.recfromtxt
|
||||
81 81 |
|
||||
82 |- np.round_(12.34)
|
||||
82 |+ np.round(12.34)
|
||||
83 83 |
|
||||
84 84 | np.safe_eval
|
||||
85 85 |
|
||||
|
||||
NPY201.py:84:5: NPY201 [*] `np.safe_eval` will be removed in NumPy 2.0. Use `ast.literal_eval` instead.
|
||||
|
|
||||
82 | np.round_(12.34)
|
||||
83 |
|
||||
84 | np.safe_eval
|
||||
| ^^^^^^^^^^^^ NPY201
|
||||
85 |
|
||||
86 | np.sctype2char
|
||||
|
|
||||
= help: Use `ast.literal_eval` instead.
|
||||
|
||||
ℹ Fix
|
||||
1 |+from ast import literal_eval
|
||||
1 2 | def func():
|
||||
2 3 | import numpy as np
|
||||
3 4 |
|
||||
--------------------------------------------------------------------------------
|
||||
81 82 |
|
||||
82 83 | np.round_(12.34)
|
||||
83 84 |
|
||||
84 |- np.safe_eval
|
||||
85 |+ literal_eval
|
||||
85 86 |
|
||||
86 87 | np.sctype2char
|
||||
87 88 |
|
||||
|
||||
NPY201.py:86:5: NPY201 `np.sctype2char` will be removed without replacement in NumPy 2.0.
|
||||
|
|
||||
84 | np.safe_eval
|
||||
85 |
|
||||
86 | np.sctype2char
|
||||
| ^^^^^^^^^^^^^^ NPY201
|
||||
87 |
|
||||
88 | np.sctypes
|
||||
|
|
||||
|
||||
NPY201.py:88:5: NPY201 `np.sctypes` will be removed without replacement in NumPy 2.0.
|
||||
|
|
||||
86 | np.sctype2char
|
||||
87 |
|
||||
88 | np.sctypes
|
||||
| ^^^^^^^^^^ NPY201
|
||||
89 |
|
||||
90 | np.seterrobj
|
||||
|
|
||||
|
||||
NPY201.py:90:5: NPY201 `np.seterrobj` will be removed in NumPy 2.0. Use the `np.errstate` context manager instead.
|
||||
|
|
||||
88 | np.sctypes
|
||||
89 |
|
||||
90 | np.seterrobj
|
||||
| ^^^^^^^^^^^^ NPY201
|
||||
91 |
|
||||
92 | np.set_numeric_ops
|
||||
|
|
||||
= help: Use the `np.errstate` context manager instead.
|
||||
|
||||
NPY201.py:94:5: NPY201 `np.set_string_function` will be removed in NumPy 2.0. Use `np.set_printoptions` for custom printing of NumPy objects.
|
||||
|
|
||||
92 | np.set_numeric_ops
|
||||
93 |
|
||||
94 | np.set_string_function
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ NPY201
|
||||
95 |
|
||||
96 | np.singlecomplex(12+1j)
|
||||
|
|
||||
= help: Use `np.set_printoptions` for custom printing of NumPy objects.
|
||||
|
||||
NPY201.py:96:5: NPY201 [*] `np.singlecomplex` will be removed in NumPy 2.0. Use `numpy.complex64` instead.
|
||||
|
|
||||
94 | np.set_string_function
|
||||
95 |
|
||||
96 | np.singlecomplex(12+1j)
|
||||
| ^^^^^^^^^^^^^^^^ NPY201
|
||||
97 |
|
||||
98 | np.string_("asdf")
|
||||
|
|
||||
= help: Use `numpy.complex64` instead.
|
||||
|
||||
ℹ Fix
|
||||
93 93 |
|
||||
94 94 | np.set_string_function
|
||||
95 95 |
|
||||
96 |- np.singlecomplex(12+1j)
|
||||
96 |+ np.complex64(12+1j)
|
||||
97 97 |
|
||||
98 98 | np.string_("asdf")
|
||||
99 99 |
|
||||
|
||||
NPY201.py:98:5: NPY201 [*] `np.string_` will be removed in NumPy 2.0. Use `numpy.bytes_` instead.
|
||||
|
|
||||
96 | np.singlecomplex(12+1j)
|
||||
97 |
|
||||
98 | np.string_("asdf")
|
||||
| ^^^^^^^^^^ NPY201
|
||||
99 |
|
||||
100 | np.source
|
||||
|
|
||||
= help: Use `numpy.bytes_` instead.
|
||||
|
||||
ℹ Fix
|
||||
95 95 |
|
||||
96 96 | np.singlecomplex(12+1j)
|
||||
97 97 |
|
||||
98 |- np.string_("asdf")
|
||||
98 |+ np.bytes_("asdf")
|
||||
99 99 |
|
||||
100 100 | np.source
|
||||
101 101 |
|
||||
|
||||
NPY201.py:100:5: NPY201 [*] `np.source` will be removed in NumPy 2.0. Use `inspect.getsource` instead.
|
||||
|
|
||||
98 | np.string_("asdf")
|
||||
99 |
|
||||
100 | np.source
|
||||
| ^^^^^^^^^ NPY201
|
||||
101 |
|
||||
102 | np.tracemalloc_domain
|
||||
|
|
||||
= help: Use `inspect.getsource` instead.
|
||||
|
||||
ℹ Fix
|
||||
1 |+from inspect import getsource
|
||||
1 2 | def func():
|
||||
2 3 | import numpy as np
|
||||
3 4 |
|
||||
--------------------------------------------------------------------------------
|
||||
97 98 |
|
||||
98 99 | np.string_("asdf")
|
||||
99 100 |
|
||||
100 |- np.source
|
||||
101 |+ getsource
|
||||
101 102 |
|
||||
102 103 | np.tracemalloc_domain
|
||||
103 104 |
|
||||
|
||||
NPY201.py:102:5: NPY201 [*] `np.tracemalloc_domain` will be removed in NumPy 2.0. Use `numpy.lib.tracemalloc_domain` instead.
|
||||
|
|
||||
100 | np.source
|
||||
101 |
|
||||
102 | np.tracemalloc_domain
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ NPY201
|
||||
103 |
|
||||
104 | np.unicode_("asf")
|
||||
|
|
||||
= help: Use `numpy.lib.tracemalloc_domain` instead.
|
||||
|
||||
ℹ Fix
|
||||
1 |+from numpy.lib import tracemalloc_domain
|
||||
1 2 | def func():
|
||||
2 3 | import numpy as np
|
||||
3 4 |
|
||||
--------------------------------------------------------------------------------
|
||||
99 100 |
|
||||
100 101 | np.source
|
||||
101 102 |
|
||||
102 |- np.tracemalloc_domain
|
||||
103 |+ tracemalloc_domain
|
||||
103 104 |
|
||||
104 105 | np.unicode_("asf")
|
||||
105 106 |
|
||||
|
||||
NPY201.py:104:5: NPY201 [*] `np.unicode_` will be removed in NumPy 2.0. Use `numpy.str_` instead.
|
||||
|
|
||||
102 | np.tracemalloc_domain
|
||||
103 |
|
||||
104 | np.unicode_("asf")
|
||||
| ^^^^^^^^^^^ NPY201
|
||||
105 |
|
||||
106 | np.who()
|
||||
|
|
||||
= help: Use `numpy.str_` instead.
|
||||
|
||||
ℹ Fix
|
||||
101 101 |
|
||||
102 102 | np.tracemalloc_domain
|
||||
103 103 |
|
||||
104 |- np.unicode_("asf")
|
||||
104 |+ np.str_("asf")
|
||||
105 105 |
|
||||
106 106 | np.who()
|
||||
|
||||
NPY201.py:106:5: NPY201 `np.who` will be removed in NumPy 2.0. Use an IDE variable explorer or `locals()` instead.
|
||||
|
|
||||
104 | np.unicode_("asf")
|
||||
105 |
|
||||
106 | np.who()
|
||||
| ^^^^^^ NPY201
|
||||
|
|
||||
= help: Use an IDE variable explorer or `locals()` instead.
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ pub(crate) fn ambiguous_unicode_character(
|
||||
let candidate = Candidate::new(
|
||||
TextSize::try_from(relative_offset).unwrap() + range.start(),
|
||||
current_char,
|
||||
representant as char,
|
||||
char::from_u32(representant).unwrap(),
|
||||
);
|
||||
if let Some(diagnostic) = candidate.into_diagnostic(context, settings) {
|
||||
diagnostics.push(diagnostic);
|
||||
@@ -178,7 +178,7 @@ pub(crate) fn ambiguous_unicode_character(
|
||||
word_candidates.push(Candidate::new(
|
||||
TextSize::try_from(relative_offset).unwrap() + range.start(),
|
||||
current_char,
|
||||
representant as char,
|
||||
char::from_u32(representant).unwrap(),
|
||||
));
|
||||
} else {
|
||||
// The current word contains at least one unambiguous unicode character.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/// Via: <https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json>
|
||||
/// See: <https://github.com/microsoft/vscode/blob/095ddabc52b82498ee7f718a34f9dd11d59099a8/src/vs/base/common/strings.ts#L1094>
|
||||
pub(crate) fn confusable(c: u32) -> Option<u8> {
|
||||
pub(crate) fn confusable(c: u32) -> Option<u32> {
|
||||
let result = match c {
|
||||
160u32 => 32,
|
||||
180u32 => 96,
|
||||
@@ -1586,6 +1586,9 @@ pub(crate) fn confusable(c: u32) -> Option<u8> {
|
||||
130_039_u32 => 55,
|
||||
130_040_u32 => 56,
|
||||
130_041_u32 => 57,
|
||||
0x212B => 0x00C5,
|
||||
0x2126 => 0x03A9,
|
||||
0x00B5 => 0x03BC,
|
||||
_ => return None,
|
||||
};
|
||||
Some(result)
|
||||
|
||||
@@ -155,4 +155,10 @@ confusables.py:46:62: RUF003 Comment contains ambiguous `᜵` (PHILIPPINE SINGLE
|
||||
47 | }"
|
||||
|
|
||||
|
||||
confusables.py:55:28: RUF001 String contains ambiguous `µ` (MICRO SIGN). Did you mean `μ` (GREEK SMALL LETTER MU)?
|
||||
|
|
||||
55 | assert getattr(Labware(), "µL") == 1.5
|
||||
| ^ RUF001
|
||||
|
|
||||
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@ use ruff_macros::CacheKey;
|
||||
|
||||
use crate::registry::{Rule, RuleSet, RuleSetIterator};
|
||||
|
||||
/// A table to keep track of which rules are enabled
|
||||
/// and Whether they should be fixed.
|
||||
/// A table to keep track of which rules are enabled and whether they should be fixed.
|
||||
#[derive(Debug, CacheKey, Default)]
|
||||
pub struct RuleTable {
|
||||
/// Maps rule codes to a boolean indicating if the rule should be fixed.
|
||||
|
||||
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagic.json
vendored
Normal file
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagic.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"execution_count": null,
|
||||
"cell_type": "code",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["pip install requests"]
|
||||
}
|
||||
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagic_after_code.json
vendored
Normal file
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagic_after_code.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"execution_count": null,
|
||||
"cell_type": "code",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["x = 1\n", "pip install requests"]
|
||||
}
|
||||
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagic_before_code.json
vendored
Normal file
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagic_before_code.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"execution_count": null,
|
||||
"cell_type": "code",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["pip install requests\n", "x = 1"]
|
||||
}
|
||||
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagics.json
vendored
Normal file
8
crates/ruff_notebook/resources/test/fixtures/jupyter/cell/automagics.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"execution_count": null,
|
||||
"cell_type": "code",
|
||||
"id": "1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["pip install requests\n", "pip install requests"]
|
||||
}
|
||||
@@ -80,14 +80,126 @@ impl Cell {
|
||||
// Ignore cells containing cell magic as they act on the entire cell
|
||||
// as compared to line magic which acts on a single line.
|
||||
!match source {
|
||||
SourceValue::String(string) => string
|
||||
.lines()
|
||||
.any(|line| line.trim_start().starts_with("%%")),
|
||||
SourceValue::StringArray(string_array) => string_array
|
||||
.iter()
|
||||
.any(|line| line.trim_start().starts_with("%%")),
|
||||
SourceValue::String(string) => Self::is_magic_cell(string.lines()),
|
||||
SourceValue::StringArray(string_array) => {
|
||||
Self::is_magic_cell(string_array.iter().map(String::as_str))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a cell should be ignored due to the use of cell magics.
|
||||
fn is_magic_cell<'a>(lines: impl Iterator<Item = &'a str>) -> bool {
|
||||
let mut lines = lines.peekable();
|
||||
|
||||
// Detect automatic line magics (automagic), which aren't supported by the parser. If a line
|
||||
// magic uses automagic, Jupyter doesn't allow following it with non-magic lines anyway, so
|
||||
// we aren't missing out on any valid Python code.
|
||||
//
|
||||
// For example, this is valid:
|
||||
// ```jupyter
|
||||
// cat /path/to/file
|
||||
// cat /path/to/file
|
||||
// ```
|
||||
//
|
||||
// But this is invalid:
|
||||
// ```jupyter
|
||||
// cat /path/to/file
|
||||
// x = 1
|
||||
// ```
|
||||
//
|
||||
// See: https://ipython.readthedocs.io/en/stable/interactive/magics.html
|
||||
if lines
|
||||
.peek()
|
||||
.and_then(|line| line.split_whitespace().next())
|
||||
.is_some_and(|token| {
|
||||
matches!(
|
||||
token,
|
||||
"alias"
|
||||
| "alias_magic"
|
||||
| "autoawait"
|
||||
| "autocall"
|
||||
| "automagic"
|
||||
| "bookmark"
|
||||
| "cd"
|
||||
| "code_wrap"
|
||||
| "colors"
|
||||
| "conda"
|
||||
| "config"
|
||||
| "debug"
|
||||
| "dhist"
|
||||
| "dirs"
|
||||
| "doctest_mode"
|
||||
| "edit"
|
||||
| "env"
|
||||
| "gui"
|
||||
| "history"
|
||||
| "killbgscripts"
|
||||
| "load"
|
||||
| "load_ext"
|
||||
| "loadpy"
|
||||
| "logoff"
|
||||
| "logon"
|
||||
| "logstart"
|
||||
| "logstate"
|
||||
| "logstop"
|
||||
| "lsmagic"
|
||||
| "macro"
|
||||
| "magic"
|
||||
| "mamba"
|
||||
| "matplotlib"
|
||||
| "micromamba"
|
||||
| "notebook"
|
||||
| "page"
|
||||
| "pastebin"
|
||||
| "pdb"
|
||||
| "pdef"
|
||||
| "pdoc"
|
||||
| "pfile"
|
||||
| "pinfo"
|
||||
| "pinfo2"
|
||||
| "pip"
|
||||
| "popd"
|
||||
| "pprint"
|
||||
| "precision"
|
||||
| "prun"
|
||||
| "psearch"
|
||||
| "psource"
|
||||
| "pushd"
|
||||
| "pwd"
|
||||
| "pycat"
|
||||
| "pylab"
|
||||
| "quickref"
|
||||
| "recall"
|
||||
| "rehashx"
|
||||
| "reload_ext"
|
||||
| "rerun"
|
||||
| "reset"
|
||||
| "reset_selective"
|
||||
| "run"
|
||||
| "save"
|
||||
| "sc"
|
||||
| "set_env"
|
||||
| "sx"
|
||||
| "system"
|
||||
| "tb"
|
||||
| "time"
|
||||
| "timeit"
|
||||
| "unalias"
|
||||
| "unload_ext"
|
||||
| "who"
|
||||
| "who_ls"
|
||||
| "whos"
|
||||
| "xdel"
|
||||
| "xmode"
|
||||
)
|
||||
})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Detect cell magics (which operate on multiple lines).
|
||||
lines.any(|line| line.trim_start().starts_with("%%"))
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can occur while deserializing a Jupyter Notebook.
|
||||
@@ -481,6 +593,10 @@ mod tests {
|
||||
#[test_case(Path::new("code_and_magic.json"), true; "code_and_magic")]
|
||||
#[test_case(Path::new("only_code.json"), true; "only_code")]
|
||||
#[test_case(Path::new("cell_magic.json"), false; "cell_magic")]
|
||||
#[test_case(Path::new("automagic.json"), false; "automagic")]
|
||||
#[test_case(Path::new("automagics.json"), false; "automagics")]
|
||||
#[test_case(Path::new("automagic_before_code.json"), false; "automagic_before_code")]
|
||||
#[test_case(Path::new("automagic_after_code.json"), true; "automagic_after_code")]
|
||||
fn test_is_valid_code_cell(path: &Path, expected: bool) -> Result<()> {
|
||||
/// Read a Jupyter cell from the `resources/test/fixtures/jupyter/cell` directory.
|
||||
fn read_jupyter_cell(path: impl AsRef<Path>) -> Result<Cell> {
|
||||
|
||||
@@ -649,8 +649,8 @@ pub enum ComparableLiteral<'a> {
|
||||
None,
|
||||
Ellipsis,
|
||||
Bool(&'a bool),
|
||||
Str { value: &'a str, unicode: &'a bool },
|
||||
Bytes { value: &'a [u8] },
|
||||
Str(&'a str),
|
||||
Bytes(&'a [u8]),
|
||||
Number(ComparableNumber<'a>),
|
||||
}
|
||||
|
||||
@@ -662,13 +662,11 @@ impl<'a> From<ast::LiteralExpressionRef<'a>> for ComparableLiteral<'a> {
|
||||
ast::LiteralExpressionRef::BooleanLiteral(ast::ExprBooleanLiteral {
|
||||
value, ..
|
||||
}) => Self::Bool(value),
|
||||
ast::LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral {
|
||||
value,
|
||||
unicode,
|
||||
..
|
||||
}) => Self::Str { value, unicode },
|
||||
ast::LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||
Self::Str(value)
|
||||
}
|
||||
ast::LiteralExpressionRef::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
|
||||
Self::Bytes { value }
|
||||
Self::Bytes(value)
|
||||
}
|
||||
ast::LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => {
|
||||
Self::Number(value.into())
|
||||
@@ -680,7 +678,6 @@ impl<'a> From<ast::LiteralExpressionRef<'a>> for ComparableLiteral<'a> {
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ExprStringLiteral<'a> {
|
||||
value: &'a str,
|
||||
unicode: &'a bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
@@ -948,9 +945,9 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
|
||||
// Compare strings based on resolved value, not representation (i.e., ignore whether
|
||||
// the string was implicitly concatenated).
|
||||
implicit_concatenated: _,
|
||||
unicode,
|
||||
unicode: _,
|
||||
range: _,
|
||||
}) => Self::StringLiteral(ExprStringLiteral { value, unicode }),
|
||||
}) => Self::StringLiteral(ExprStringLiteral { value }),
|
||||
ast::Expr::BytesLiteral(ast::ExprBytesLiteral {
|
||||
value,
|
||||
// Compare bytes based on resolved value, not representation (i.e., ignore whether
|
||||
|
||||
@@ -2313,6 +2313,14 @@ impl Parameters {
|
||||
&& self.vararg.is_none()
|
||||
&& self.kwarg.is_none()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.posonlyargs.len()
|
||||
+ self.args.len()
|
||||
+ usize::from(self.vararg.is_some())
|
||||
+ self.kwonlyargs.len()
|
||||
+ usize::from(self.kwarg.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
/// An alternative type of AST `arg`. This is used for each function argument that might have a default value.
|
||||
@@ -2516,33 +2524,10 @@ impl Parameters {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::borrowed_box)] // local utility
|
||||
fn clone_boxed_expr(expr: &Box<Expr>) -> Box<Expr> {
|
||||
let expr: &Expr = expr.as_ref();
|
||||
Box::new(expr.clone())
|
||||
}
|
||||
|
||||
impl ParameterWithDefault {
|
||||
pub fn as_parameter(&self) -> &Parameter {
|
||||
&self.parameter
|
||||
}
|
||||
|
||||
pub fn to_parameter(&self) -> (Parameter, Option<Box<Expr>>) {
|
||||
let ParameterWithDefault {
|
||||
range: _,
|
||||
parameter,
|
||||
default,
|
||||
} = self;
|
||||
(parameter.clone(), default.as_ref().map(clone_boxed_expr))
|
||||
}
|
||||
pub fn into_parameter(self) -> (Parameter, Option<Box<Expr>>) {
|
||||
let ParameterWithDefault {
|
||||
range: _,
|
||||
parameter,
|
||||
default,
|
||||
} = self;
|
||||
(parameter, default)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
|
||||
8
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.options.json
vendored
Normal file
8
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/lambda.options.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"preview": "disabled"
|
||||
},
|
||||
{
|
||||
"preview": "enabled"
|
||||
}
|
||||
]
|
||||
@@ -125,6 +125,13 @@ lambda a, /, c: a
|
||||
*x: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment
|
||||
*x,
|
||||
**y: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
@@ -135,6 +142,17 @@ lambda a, /, c: a
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
*
|
||||
# comment 2
|
||||
x,
|
||||
**y:
|
||||
# comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
* # comment 2
|
||||
@@ -142,6 +160,14 @@ lambda a, /, c: a
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
* # comment 2
|
||||
x,
|
||||
y: # comment 3
|
||||
x
|
||||
)
|
||||
|
||||
lambda *x\
|
||||
:x
|
||||
|
||||
@@ -196,6 +222,17 @@ lambda: ( # comment
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # 1
|
||||
# 2
|
||||
x, # 3
|
||||
# 4
|
||||
y
|
||||
: # 5
|
||||
# 6
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
x,
|
||||
@@ -203,3 +240,93 @@ lambda: ( # comment
|
||||
y:
|
||||
z
|
||||
)
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: (
|
||||
lambda y: lambda z: x
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ z # Trailing
|
||||
) # Trailing
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: lambda y: lambda z: [
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
z
|
||||
] # Trailing
|
||||
# Trailing
|
||||
|
||||
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/8179
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda self, *args, **kwargs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
|
||||
*args, **kwargs
|
||||
),
|
||||
)
|
||||
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda self, araa, kkkwargs,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
args,kwargs,
|
||||
e=1, f=2, g=2: d,
|
||||
g = 10
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top.
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
## Parenthesized
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
)
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
## Expression and statement comments
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbb # c
|
||||
) # d
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvv # c
|
||||
) # d
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
) # d
|
||||
|
||||
## Strings
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv" # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv" # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv" # c
|
||||
|
||||
# Always parenthesize if implicit concatenated
|
||||
____aaa = (
|
||||
"aaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvv"
|
||||
) # c
|
||||
|
||||
## Numbers
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = 1111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = 1111111111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = 11111111111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
## Breaking left
|
||||
|
||||
# Should break `[a]` first
|
||||
____[a] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
____[
|
||||
a
|
||||
] = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # cc
|
||||
)
|
||||
|
||||
(
|
||||
# some weird comments
|
||||
____[aaaaaaaaa]
|
||||
# some weird comments 2
|
||||
) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
# Preserve trailing assignment comments when the expression has own line comments
|
||||
____aaa = (
|
||||
# leading
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv
|
||||
# trailing
|
||||
) # cc
|
||||
|
||||
def setUpTestData(cls):
|
||||
cls.happening = (
|
||||
Happening.objects.create()
|
||||
) # make sure the defaults are working (#20158)
|
||||
|
||||
def setUpTestData(cls):
|
||||
cls.happening = (
|
||||
Happening.objects.create # make sure the defaults are working (#20158)
|
||||
)
|
||||
|
||||
if True:
|
||||
if True:
|
||||
if True:
|
||||
# Black layout
|
||||
model.config.use_cache = (
|
||||
False # FSTM still requires this hack -> FSTM should probably be refactored s
|
||||
)
|
||||
|
||||
## Annotated Assign
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____a : a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
)
|
||||
|
||||
# 88 characters
|
||||
____a: a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____a: a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
_a: a[b] = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
## Augmented Assign
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
)
|
||||
|
||||
# 88 characters
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
## Return
|
||||
|
||||
def test():
|
||||
# 88 characters unparenthesized
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
def test2():
|
||||
# 88 characters
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
|
||||
def test3():
|
||||
# 89 characters parenthesized (collapse)
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvv # c
|
||||
|
||||
## Return Parenthesized
|
||||
|
||||
def test4():
|
||||
# 88 characters unparenthesized
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
)
|
||||
|
||||
def test5():
|
||||
# 88 characters
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
)
|
||||
|
||||
def test6():
|
||||
# 89 characters parenthesized (collapse)
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvv # c
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ impl<'a> PyFormatContext<'a> {
|
||||
pub(crate) fn comments(&self) -> &Comments<'a> {
|
||||
&self.comments
|
||||
}
|
||||
|
||||
pub(crate) const fn is_preview(&self) -> bool {
|
||||
self.options.preview().is_enabled()
|
||||
}
|
||||
|
||||
pub(crate) const fn is_stable(&self) -> bool {
|
||||
!self.is_preview()
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatContext for PyFormatContext<'_> {
|
||||
|
||||
@@ -20,7 +20,7 @@ impl FormatNodeRule<ExprAwait> for FormatExprAwait {
|
||||
[
|
||||
token("await"),
|
||||
space(),
|
||||
maybe_parenthesize_expression(value, item, Parenthesize::IfBreaks)
|
||||
maybe_parenthesize_expression(value, item, Parenthesize::IfRequired)
|
||||
]
|
||||
)
|
||||
}
|
||||
@@ -39,6 +39,7 @@ impl NeedsParentheses for ExprAwait {
|
||||
context.comments().ranges(),
|
||||
context.source(),
|
||||
) {
|
||||
// Prefer splitting the value if it is parenthesized.
|
||||
OptionalParentheses::Never
|
||||
} else {
|
||||
self.value.needs_parentheses(self.into(), context)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use ruff_formatter::write;
|
||||
use ruff_formatter::{format_args, write};
|
||||
use ruff_python_ast::AnyNodeRef;
|
||||
use ruff_python_ast::ExprLambda;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::comments::{dangling_comments, SourceComment};
|
||||
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
|
||||
use crate::comments::{dangling_comments, leading_comments, SourceComment};
|
||||
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parenthesize};
|
||||
use crate::expression::{has_own_parentheses, maybe_parenthesize_expression};
|
||||
use crate::other::parameters::ParametersParentheses;
|
||||
use crate::prelude::*;
|
||||
|
||||
@@ -25,31 +26,49 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
|
||||
write!(f, [token("lambda")])?;
|
||||
|
||||
if let Some(parameters) = parameters {
|
||||
// In this context, a dangling comment can either be a comment between the `lambda` the
|
||||
// In this context, a dangling comment can either be a comment between the `lambda` and the
|
||||
// parameters, or a comment between the parameters and the body.
|
||||
let (dangling_before_parameters, dangling_after_parameters) = dangling
|
||||
.split_at(dangling.partition_point(|comment| comment.end() < parameters.start()));
|
||||
|
||||
if dangling_before_parameters.is_empty() {
|
||||
write!(f, [space()])?;
|
||||
} else {
|
||||
write!(f, [dangling_comments(dangling_before_parameters)])?;
|
||||
}
|
||||
|
||||
write!(
|
||||
f,
|
||||
[parameters
|
||||
.format()
|
||||
.with_options(ParametersParentheses::Never)]
|
||||
)?;
|
||||
group(&format_with(|f: &mut PyFormatter| {
|
||||
if f.context().node_level().is_parenthesized()
|
||||
&& (parameters.len() > 1 || !dangling_before_parameters.is_empty())
|
||||
{
|
||||
let end_of_line_start = dangling_before_parameters
|
||||
.partition_point(|comment| comment.line_position().is_end_of_line());
|
||||
let (same_line_comments, own_line_comments) =
|
||||
dangling_before_parameters.split_at(end_of_line_start);
|
||||
|
||||
write!(f, [token(":")])?;
|
||||
dangling_comments(same_line_comments).fmt(f)?;
|
||||
|
||||
if dangling_after_parameters.is_empty() {
|
||||
write!(f, [space()])?;
|
||||
} else {
|
||||
write!(f, [dangling_comments(dangling_after_parameters)])?;
|
||||
}
|
||||
soft_block_indent(&format_args![
|
||||
leading_comments(own_line_comments),
|
||||
parameters
|
||||
.format()
|
||||
.with_options(ParametersParentheses::Never),
|
||||
])
|
||||
.fmt(f)
|
||||
} else {
|
||||
parameters
|
||||
.format()
|
||||
.with_options(ParametersParentheses::Never)
|
||||
.fmt(f)
|
||||
}?;
|
||||
|
||||
token(":").fmt(f)?;
|
||||
|
||||
if dangling_after_parameters.is_empty() {
|
||||
space().fmt(f)
|
||||
} else {
|
||||
dangling_comments(dangling_after_parameters).fmt(f)
|
||||
}
|
||||
}))
|
||||
.fmt(f)?;
|
||||
} else {
|
||||
write!(f, [token(":")])?;
|
||||
|
||||
@@ -61,7 +80,12 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, [body.format()])
|
||||
// Avoid parenthesizing lists, dictionaries, etc.
|
||||
if f.context().is_stable() || has_own_parentheses(body, f.context()).is_some() {
|
||||
body.format().fmt(f)
|
||||
} else {
|
||||
maybe_parenthesize_expression(body, item, Parenthesize::IfBreaksOrIfRequired).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_dangling_comments(
|
||||
|
||||
@@ -69,6 +69,7 @@ impl NeedsParentheses for ExprNamedExpr {
|
||||
|| parent.is_stmt_delete()
|
||||
|| parent.is_stmt_for()
|
||||
|| parent.is_stmt_function_def()
|
||||
|| parent.is_expr_lambda()
|
||||
{
|
||||
OptionalParentheses::Always
|
||||
} else {
|
||||
|
||||
@@ -59,7 +59,10 @@ impl NeedsParentheses for AnyExpressionYield<'_> {
|
||||
OptionalParentheses::Never
|
||||
} else {
|
||||
// Ex) `x = yield f(1, 2, 3)`
|
||||
value.needs_parentheses(self.into(), context)
|
||||
match value.needs_parentheses(self.into(), context) {
|
||||
OptionalParentheses::BestFit => OptionalParentheses::Never,
|
||||
parentheses => parentheses,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Ex) `x = yield`
|
||||
|
||||
@@ -12,7 +12,9 @@ use ruff_python_trivia::CommentRanges;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::builders::parenthesize_if_expands;
|
||||
use crate::comments::{leading_comments, trailing_comments, LeadingDanglingTrailingComments};
|
||||
use crate::comments::{
|
||||
leading_comments, trailing_comments, LeadingDanglingTrailingComments, SourceComment,
|
||||
};
|
||||
use crate::context::{NodeLevel, WithNodeLevel};
|
||||
use crate::expression::expr_generator_exp::is_generator_parenthesized;
|
||||
use crate::expression::expr_tuple::is_tuple_parenthesized;
|
||||
@@ -374,10 +376,8 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
|
||||
return expression.format().with_options(Parentheses::Always).fmt(f);
|
||||
}
|
||||
|
||||
let node_comments = f
|
||||
.context()
|
||||
.comments()
|
||||
.leading_dangling_trailing(*expression);
|
||||
let comments = f.context().comments().clone();
|
||||
let node_comments = comments.leading_dangling_trailing(*expression);
|
||||
|
||||
// If the expression has comments, we always want to preserve the parentheses. This also
|
||||
// ensures that we correctly handle parenthesized comments, and don't need to worry about
|
||||
@@ -426,15 +426,106 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
|
||||
expression.format().with_options(Parentheses::Never).fmt(f)
|
||||
}
|
||||
Parenthesize::IfBreaks => {
|
||||
if node_comments.has_trailing() {
|
||||
expression.format().with_options(Parentheses::Always).fmt(f)
|
||||
// Is the expression the last token in the parent statement.
|
||||
// Excludes `await` and `yield` for which Black doesn't seem to apply the layout?
|
||||
let last_expression = parent.is_stmt_assign()
|
||||
|| parent.is_stmt_ann_assign()
|
||||
|| parent.is_stmt_aug_assign()
|
||||
|| parent.is_stmt_return();
|
||||
|
||||
// Format the statements and value's trailing end of line comments:
|
||||
// * after the expression if the expression needs no parentheses (necessary or the `expand_parent` makes the group never fit).
|
||||
// * inside the parentheses if the expression exceeds the line-width.
|
||||
//
|
||||
// ```python
|
||||
// a = long # with_comment
|
||||
// b = (
|
||||
// short # with_comment
|
||||
// )
|
||||
//
|
||||
// # formatted
|
||||
// a = (
|
||||
// long # with comment
|
||||
// )
|
||||
// b = short # with comment
|
||||
// ```
|
||||
// This matches Black's formatting with the exception that ruff applies this style also for
|
||||
// attribute chains and non-fluent call expressions. See https://github.com/psf/black/issues/4001#issuecomment-1786681792
|
||||
//
|
||||
// This logic isn't implemented in [`place_comment`] by associating trailing statement comments to the expression because
|
||||
// doing so breaks the suite empty lines formatting that relies on trailing comments to be stored on the statement.
|
||||
let (inline_comments, expression_trailing_comments) = if last_expression
|
||||
&& !(
|
||||
// Ignore non-fluent attribute chains for black compatibility.
|
||||
// See https://github.com/psf/black/issues/4001#issuecomment-1786681792
|
||||
expression.is_attribute_expr()
|
||||
|| expression.is_call_expr()
|
||||
|| expression.is_yield_from_expr()
|
||||
|| expression.is_yield_expr()
|
||||
|| expression.is_await_expr()
|
||||
) {
|
||||
let parent_trailing_comments = comments.trailing(*parent);
|
||||
let after_end_of_line = parent_trailing_comments
|
||||
.partition_point(|comment| comment.line_position().is_end_of_line());
|
||||
let (stmt_inline_comments, _) =
|
||||
parent_trailing_comments.split_at(after_end_of_line);
|
||||
|
||||
let after_end_of_line = node_comments
|
||||
.trailing
|
||||
.partition_point(|comment| comment.line_position().is_end_of_line());
|
||||
|
||||
let (expression_inline_comments, expression_trailing_comments) =
|
||||
node_comments.trailing.split_at(after_end_of_line);
|
||||
|
||||
(
|
||||
OptionalParenthesesInlinedComments {
|
||||
expression: expression_inline_comments,
|
||||
statement: stmt_inline_comments,
|
||||
},
|
||||
expression_trailing_comments,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
OptionalParenthesesInlinedComments::default(),
|
||||
node_comments.trailing,
|
||||
)
|
||||
};
|
||||
|
||||
if expression_trailing_comments.is_empty() {
|
||||
// The group id is necessary because the nested expressions may reference it.
|
||||
let group_id = f.group_id("optional_parentheses");
|
||||
let f = &mut WithNodeLevel::new(NodeLevel::Expression(Some(group_id)), f);
|
||||
best_fit_parenthesize(&expression.format().with_options(Parentheses::Never))
|
||||
.with_group_id(Some(group_id))
|
||||
.fmt(f)
|
||||
|
||||
best_fit_parenthesize(&format_with(|f| {
|
||||
inline_comments.mark_formatted();
|
||||
|
||||
expression
|
||||
.format()
|
||||
.with_options(Parentheses::Never)
|
||||
.fmt(f)?;
|
||||
|
||||
if !inline_comments.is_empty() {
|
||||
// If the expressions exceeds the line width, format the comments in the parentheses
|
||||
if_group_breaks(&inline_comments)
|
||||
.with_group_id(Some(group_id))
|
||||
.fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}))
|
||||
.with_group_id(Some(group_id))
|
||||
.fmt(f)?;
|
||||
|
||||
if !inline_comments.is_empty() {
|
||||
// If the line fits into the line width, format the comments after the parenthesized expression
|
||||
if_group_fits_on_line(&inline_comments)
|
||||
.with_group_id(Some(group_id))
|
||||
.fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
expression.format().with_options(Parentheses::Always).fmt(f)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1069,3 +1160,41 @@ impl From<ast::Operator> for OperatorPrecedence {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct OptionalParenthesesInlinedComments<'a> {
|
||||
expression: &'a [SourceComment],
|
||||
statement: &'a [SourceComment],
|
||||
}
|
||||
|
||||
impl<'a> OptionalParenthesesInlinedComments<'a> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.expression.is_empty() && self.statement.is_empty()
|
||||
}
|
||||
|
||||
fn iter_comments(&self) -> impl Iterator<Item = &'a SourceComment> {
|
||||
self.expression.iter().chain(self.statement)
|
||||
}
|
||||
|
||||
fn mark_formatted(&self) {
|
||||
for comment in self.iter_comments() {
|
||||
comment.mark_formatted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Format<PyFormatContext<'_>> for OptionalParenthesesInlinedComments<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||
for comment in self.iter_comments() {
|
||||
comment.mark_unformatted();
|
||||
}
|
||||
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
trailing_comments(self.expression),
|
||||
trailing_comments(self.statement)
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ impl PyFormatOptions {
|
||||
self.line_ending
|
||||
}
|
||||
|
||||
pub fn preview(&self) -> PreviewMode {
|
||||
pub const fn preview(&self) -> PreviewMode {
|
||||
self.preview
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ impl FormatNodeRule<ParameterWithDefault> for FormatParameterWithDefault {
|
||||
token("="),
|
||||
(!needs_line_break).then_some(space),
|
||||
needs_line_break.then_some(hard_line_break()),
|
||||
group(&default.format())
|
||||
default.format()
|
||||
]
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,15 @@ impl FormatNodeRule<Parameters> for FormatParameters {
|
||||
dangling.split_at(parenthesis_comments_end);
|
||||
|
||||
let format_inner = format_with(|f: &mut PyFormatter| {
|
||||
let separator = format_with(|f| write!(f, [token(","), soft_line_break_or_space()]));
|
||||
let separator = format_with(|f: &mut PyFormatter| {
|
||||
token(",").fmt(f)?;
|
||||
|
||||
if f.context().node_level().is_parenthesized() {
|
||||
soft_line_break_or_space().fmt(f)
|
||||
} else {
|
||||
space().fmt(f)
|
||||
}
|
||||
});
|
||||
let mut joiner = f.join_with(separator);
|
||||
let mut last_node: Option<AnyNodeRef> = None;
|
||||
|
||||
@@ -232,23 +240,19 @@ impl FormatNodeRule<Parameters> for FormatParameters {
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
|
||||
|
||||
let num_parameters = posonlyargs.len()
|
||||
+ args.len()
|
||||
+ usize::from(vararg.is_some())
|
||||
+ kwonlyargs.len()
|
||||
+ usize::from(kwarg.is_some());
|
||||
let num_parameters = item.len();
|
||||
|
||||
if self.parentheses == ParametersParentheses::Never {
|
||||
write!(f, [group(&format_inner), dangling_comments(dangling)])
|
||||
write!(f, [format_inner, dangling_comments(dangling)])
|
||||
} else if num_parameters == 0 {
|
||||
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
|
||||
// No parameters, format any dangling comments between `()`
|
||||
write!(f, [empty_parenthesized("(", dangling, ")")])
|
||||
} else {
|
||||
// Intentionally avoid `parenthesized`, which groups the entire formatted contents.
|
||||
// We want parameters to be grouped alongside return types, one level up, so we
|
||||
// format them "inline" here.
|
||||
let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f);
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
|
||||
@@ -93,7 +93,7 @@ async def main():
|
||||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -21,11 +21,15 @@
|
||||
@@ -21,7 +21,9 @@
|
||||
|
||||
# Check comments
|
||||
async def main():
|
||||
@@ -103,13 +103,6 @@ async def main():
|
||||
+ )
|
||||
|
||||
|
||||
async def main():
|
||||
- await asyncio.sleep(1) # Hello
|
||||
+ await (
|
||||
+ asyncio.sleep(1) # Hello
|
||||
+ )
|
||||
|
||||
|
||||
async def main():
|
||||
```
|
||||
|
||||
@@ -145,9 +138,7 @@ async def main():
|
||||
|
||||
|
||||
async def main():
|
||||
await (
|
||||
asyncio.sleep(1) # Hello
|
||||
)
|
||||
await asyncio.sleep(1) # Hello
|
||||
|
||||
|
||||
async def main():
|
||||
|
||||
@@ -131,6 +131,13 @@ lambda a, /, c: a
|
||||
*x: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment
|
||||
*x,
|
||||
**y: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
@@ -141,6 +148,17 @@ lambda a, /, c: a
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
*
|
||||
# comment 2
|
||||
x,
|
||||
**y:
|
||||
# comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
* # comment 2
|
||||
@@ -148,6 +166,14 @@ lambda a, /, c: a
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
* # comment 2
|
||||
x,
|
||||
y: # comment 3
|
||||
x
|
||||
)
|
||||
|
||||
lambda *x\
|
||||
:x
|
||||
|
||||
@@ -202,6 +228,17 @@ lambda: ( # comment
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # 1
|
||||
# 2
|
||||
x, # 3
|
||||
# 4
|
||||
y
|
||||
: # 5
|
||||
# 6
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
x,
|
||||
@@ -209,9 +246,109 @@ lambda: ( # comment
|
||||
y:
|
||||
z
|
||||
)
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: (
|
||||
lambda y: lambda z: x
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ z # Trailing
|
||||
) # Trailing
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: lambda y: lambda z: [
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
z
|
||||
] # Trailing
|
||||
# Trailing
|
||||
|
||||
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs), e=1, f=2, g=2: d
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/8179
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda self, *args, **kwargs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
|
||||
*args, **kwargs
|
||||
),
|
||||
)
|
||||
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda self, araa, kkkwargs,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
args,kwargs,
|
||||
e=1, f=2, g=2: d,
|
||||
g = 10
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
## Outputs
|
||||
### Output 1
|
||||
```
|
||||
indent-style = space
|
||||
line-width = 88
|
||||
indent-width = 4
|
||||
quote-style = Double
|
||||
magic-trailing-comma = Respect
|
||||
preview = Disabled
|
||||
```
|
||||
|
||||
## Output
|
||||
```py
|
||||
# Leading
|
||||
lambda x: x # Trailing
|
||||
@@ -275,8 +412,10 @@ a = (
|
||||
)
|
||||
|
||||
a = (
|
||||
lambda x, # Dangling
|
||||
y: 1
|
||||
lambda
|
||||
x, # Dangling
|
||||
y
|
||||
: 1
|
||||
)
|
||||
|
||||
# Regression test: lambda empty arguments ranges were too long, leading to unstable
|
||||
@@ -337,23 +476,54 @@ lambda a, /, c: a
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment
|
||||
*x: x
|
||||
# comment
|
||||
*x
|
||||
: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
# comment 2
|
||||
*x:
|
||||
# comment
|
||||
*x,
|
||||
**y
|
||||
: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
# comment 2
|
||||
*x
|
||||
:
|
||||
# comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
# comment 2
|
||||
*x,
|
||||
**y
|
||||
:
|
||||
# comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
# comment 2
|
||||
*x: # comment 3
|
||||
# comment 2
|
||||
*x
|
||||
: # comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
# comment 2
|
||||
*x,
|
||||
y
|
||||
: # comment 3
|
||||
x
|
||||
)
|
||||
|
||||
@@ -361,8 +531,9 @@ lambda *x: x
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment
|
||||
*x: x
|
||||
# comment
|
||||
*x
|
||||
: x
|
||||
)
|
||||
|
||||
lambda: ( # comment
|
||||
@@ -400,8 +571,9 @@ lambda: ( # comment
|
||||
|
||||
(
|
||||
lambda # 1
|
||||
# 2
|
||||
x: # 3
|
||||
# 2
|
||||
x
|
||||
: # 3
|
||||
# 4
|
||||
# 5
|
||||
# 6
|
||||
@@ -409,10 +581,481 @@ lambda: ( # comment
|
||||
)
|
||||
|
||||
(
|
||||
lambda x,
|
||||
# comment
|
||||
y: z
|
||||
lambda # 1
|
||||
# 2
|
||||
x, # 3
|
||||
# 4
|
||||
y
|
||||
: # 5
|
||||
# 6
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
x,
|
||||
# comment
|
||||
y
|
||||
: z
|
||||
)
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: (
|
||||
lambda y: lambda z: x
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ z # Trailing
|
||||
) # Trailing
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: lambda y: lambda z: [
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
z,
|
||||
] # Trailing
|
||||
# Trailing
|
||||
|
||||
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
|
||||
*args, **kwargs
|
||||
), e=1, f=2, g=2: d
|
||||
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/8179
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda
|
||||
self,
|
||||
*args,
|
||||
**kwargs
|
||||
: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs),
|
||||
)
|
||||
|
||||
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda
|
||||
self,
|
||||
araa,
|
||||
kkkwargs,
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
args,
|
||||
kwargs,
|
||||
e=1,
|
||||
f=2,
|
||||
g=2
|
||||
: d,
|
||||
g=10,
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
### Output 2
|
||||
```
|
||||
indent-style = space
|
||||
line-width = 88
|
||||
indent-width = 4
|
||||
quote-style = Double
|
||||
magic-trailing-comma = Respect
|
||||
preview = Enabled
|
||||
```
|
||||
|
||||
```py
|
||||
# Leading
|
||||
lambda x: x # Trailing
|
||||
# Trailing
|
||||
|
||||
# Leading
|
||||
lambda x, y: x # Trailing
|
||||
# Trailing
|
||||
|
||||
# Leading
|
||||
lambda x, y: x, y # Trailing
|
||||
# Trailing
|
||||
|
||||
# Leading
|
||||
lambda x, /, y: x # Trailing
|
||||
# Trailing
|
||||
|
||||
# Leading
|
||||
lambda x: lambda y: lambda z: x # Trailing
|
||||
# Trailing
|
||||
|
||||
# Leading
|
||||
lambda x: lambda y: lambda z: (x, y, z) # Trailing
|
||||
# Trailing
|
||||
|
||||
# Leading
|
||||
lambda x: lambda y: lambda z: (x, y, z) # Trailing
|
||||
# Trailing
|
||||
|
||||
# Leading
|
||||
lambda x: (
|
||||
lambda y: (
|
||||
lambda z: (x, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, z)
|
||||
)
|
||||
) # Trailing
|
||||
# Trailing
|
||||
|
||||
a = (
|
||||
lambda: # Dangling
|
||||
1
|
||||
)
|
||||
|
||||
a = (
|
||||
lambda
|
||||
x, # Dangling
|
||||
y
|
||||
: 1
|
||||
)
|
||||
|
||||
# Regression test: lambda empty arguments ranges were too long, leading to unstable
|
||||
# formatting
|
||||
(
|
||||
lambda: ( #
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# lambda arguments don't have parentheses, so we never add a magic trailing comma ...
|
||||
def f(
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = lambda x: (
|
||||
y
|
||||
),
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
# ...but we do preserve a trailing comma after the arguments
|
||||
a = lambda b,: 0
|
||||
|
||||
lambda a,: 0
|
||||
lambda *args,: 0
|
||||
lambda **kwds,: 0
|
||||
lambda a, *args,: 0
|
||||
lambda a, **kwds,: 0
|
||||
lambda *args, b,: 0
|
||||
lambda *, b,: 0
|
||||
lambda *args, **kwds,: 0
|
||||
lambda a, *args, b,: 0
|
||||
lambda a, *, b,: 0
|
||||
lambda a, *args, **kwds,: 0
|
||||
lambda *args, b, **kwds,: 0
|
||||
lambda *, b, **kwds,: 0
|
||||
lambda a, *args, b, **kwds,: 0
|
||||
lambda a, *, b, **kwds,: 0
|
||||
lambda a, /: a
|
||||
lambda a, /, c: a
|
||||
|
||||
# Dangling comments without parameters.
|
||||
(
|
||||
lambda: # 3
|
||||
None
|
||||
)
|
||||
|
||||
(
|
||||
lambda:
|
||||
# 3
|
||||
None
|
||||
)
|
||||
|
||||
(
|
||||
lambda: # 1
|
||||
# 2
|
||||
# 3
|
||||
# 4
|
||||
None # 5
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment
|
||||
*x
|
||||
: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment
|
||||
*x,
|
||||
**y
|
||||
: x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
# comment 2
|
||||
*x
|
||||
:
|
||||
# comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment 1
|
||||
# comment 2
|
||||
*x,
|
||||
**y
|
||||
:
|
||||
# comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
# comment 2
|
||||
*x
|
||||
: # comment 3
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # comment 1
|
||||
# comment 2
|
||||
*x,
|
||||
y
|
||||
: # comment 3
|
||||
x
|
||||
)
|
||||
|
||||
lambda *x: x
|
||||
|
||||
(
|
||||
lambda
|
||||
# comment
|
||||
*x
|
||||
: x
|
||||
)
|
||||
|
||||
lambda: ( # comment
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda: # comment
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda:
|
||||
# comment
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda: # comment
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda:
|
||||
# comment
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda: # comment
|
||||
( # comment
|
||||
x
|
||||
)
|
||||
)
|
||||
|
||||
(
|
||||
lambda # 1
|
||||
# 2
|
||||
x
|
||||
: # 3
|
||||
# 4
|
||||
# 5
|
||||
# 6
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda # 1
|
||||
# 2
|
||||
x, # 3
|
||||
# 4
|
||||
y
|
||||
: # 5
|
||||
# 6
|
||||
x
|
||||
)
|
||||
|
||||
(
|
||||
lambda
|
||||
x,
|
||||
# comment
|
||||
y
|
||||
: z
|
||||
)
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: (
|
||||
lambda y: (
|
||||
lambda z: (
|
||||
x
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ y
|
||||
+ z
|
||||
)
|
||||
) # Trailing
|
||||
) # Trailing
|
||||
|
||||
|
||||
# Leading
|
||||
lambda x: (
|
||||
lambda y: (
|
||||
lambda z: [
|
||||
x,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
y,
|
||||
z,
|
||||
]
|
||||
)
|
||||
) # Trailing
|
||||
# Trailing
|
||||
|
||||
lambda self, araa, kkkwargs=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(
|
||||
*args, **kwargs
|
||||
), e=1, f=2, g=2: d
|
||||
|
||||
|
||||
# Regression tests for https://github.com/astral-sh/ruff/issues/8179
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda
|
||||
self,
|
||||
*args,
|
||||
**kwargs
|
||||
: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(*args, **kwargs),
|
||||
)
|
||||
|
||||
|
||||
def a():
|
||||
return b(
|
||||
c,
|
||||
d,
|
||||
e,
|
||||
f=lambda
|
||||
self,
|
||||
araa,
|
||||
kkkwargs,
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
args,
|
||||
kwargs,
|
||||
e=1,
|
||||
f=2,
|
||||
g=2
|
||||
: d,
|
||||
g=10,
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/optional_parentheses_comments.py
|
||||
---
|
||||
## Input
|
||||
```py
|
||||
comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top.
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
## Parenthesized
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
)
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
## Expression and statement comments
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbb # c
|
||||
) # d
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvv # c
|
||||
) # d
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
) # d
|
||||
|
||||
## Strings
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv" # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv" # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv" # c
|
||||
|
||||
# Always parenthesize if implicit concatenated
|
||||
____aaa = (
|
||||
"aaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvv"
|
||||
) # c
|
||||
|
||||
## Numbers
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = 1111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = 1111111111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = 11111111111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
## Breaking left
|
||||
|
||||
# Should break `[a]` first
|
||||
____[a] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
____[
|
||||
a
|
||||
] = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # cc
|
||||
)
|
||||
|
||||
(
|
||||
# some weird comments
|
||||
____[aaaaaaaaa]
|
||||
# some weird comments 2
|
||||
) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
# Preserve trailing assignment comments when the expression has own line comments
|
||||
____aaa = (
|
||||
# leading
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv
|
||||
# trailing
|
||||
) # cc
|
||||
|
||||
def setUpTestData(cls):
|
||||
cls.happening = (
|
||||
Happening.objects.create()
|
||||
) # make sure the defaults are working (#20158)
|
||||
|
||||
def setUpTestData(cls):
|
||||
cls.happening = (
|
||||
Happening.objects.create # make sure the defaults are working (#20158)
|
||||
)
|
||||
|
||||
if True:
|
||||
if True:
|
||||
if True:
|
||||
# Black layout
|
||||
model.config.use_cache = (
|
||||
False # FSTM still requires this hack -> FSTM should probably be refactored s
|
||||
)
|
||||
|
||||
## Annotated Assign
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____a : a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
)
|
||||
|
||||
# 88 characters
|
||||
____a: a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____a: a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
_a: a[b] = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
## Augmented Assign
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
)
|
||||
|
||||
# 88 characters
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
## Return
|
||||
|
||||
def test():
|
||||
# 88 characters unparenthesized
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
def test2():
|
||||
# 88 characters
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
|
||||
def test3():
|
||||
# 89 characters parenthesized (collapse)
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvv # c
|
||||
|
||||
## Return Parenthesized
|
||||
|
||||
def test4():
|
||||
# 88 characters unparenthesized
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
)
|
||||
|
||||
def test5():
|
||||
# 88 characters
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
)
|
||||
|
||||
def test6():
|
||||
# 89 characters parenthesized (collapse)
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvv # c
|
||||
)
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Output
|
||||
```py
|
||||
comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top.
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
## Parenthesized
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
## Expression and statement comments
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbb # c # d
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvv # c # d
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c # d
|
||||
|
||||
## Strings
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv" # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv" # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv" # c
|
||||
|
||||
# Always parenthesize if implicit concatenated
|
||||
____aaa = (
|
||||
"aaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvv"
|
||||
) # c
|
||||
|
||||
## Numbers
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aaa = 1111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
# 88 characters
|
||||
____aaa = (
|
||||
1111111111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aaa = 11111111111111111111111111111111111111111111111111111111111111111111111111111111 # c
|
||||
|
||||
## Breaking left
|
||||
|
||||
# Should break `[a]` first
|
||||
____[
|
||||
a
|
||||
] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
____[
|
||||
a
|
||||
] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # cc
|
||||
|
||||
(
|
||||
# some weird comments
|
||||
____[aaaaaaaaa]
|
||||
# some weird comments 2
|
||||
) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
|
||||
# Preserve trailing assignment comments when the expression has own line comments
|
||||
____aaa = (
|
||||
# leading
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv
|
||||
# trailing
|
||||
) # cc
|
||||
|
||||
|
||||
def setUpTestData(cls):
|
||||
cls.happening = (
|
||||
Happening.objects.create()
|
||||
) # make sure the defaults are working (#20158)
|
||||
|
||||
|
||||
def setUpTestData(cls):
|
||||
cls.happening = (
|
||||
Happening.objects.create # make sure the defaults are working (#20158)
|
||||
)
|
||||
|
||||
|
||||
if True:
|
||||
if True:
|
||||
if True:
|
||||
# Black layout
|
||||
model.config.use_cache = False # FSTM still requires this hack -> FSTM should probably be refactored s
|
||||
|
||||
## Annotated Assign
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____a: a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____a: a = (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
_a: a[
|
||||
b
|
||||
] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
## Augmented Assign
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
# 88 characters unparenthesized
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvv # c
|
||||
|
||||
# 88 characters
|
||||
____aa += (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvv # c
|
||||
)
|
||||
|
||||
# 89 characters parenthesized (collapse)
|
||||
____aa += aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c
|
||||
|
||||
## Return
|
||||
|
||||
|
||||
def test():
|
||||
# 88 characters unparenthesized
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
|
||||
def test2():
|
||||
# 88 characters
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
)
|
||||
|
||||
|
||||
def test3():
|
||||
# 89 characters parenthesized (collapse)
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvv # c
|
||||
|
||||
|
||||
## Return Parenthesized
|
||||
|
||||
|
||||
def test4():
|
||||
# 88 characters unparenthesized
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvv # c
|
||||
|
||||
|
||||
def test5():
|
||||
# 88 characters
|
||||
return (
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvv # c
|
||||
)
|
||||
|
||||
|
||||
def test6():
|
||||
# 89 characters parenthesized (collapse)
|
||||
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvv # c
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -164,9 +164,7 @@ for converter in connection.ops.get_db_converters(
|
||||
pass
|
||||
|
||||
|
||||
aaa = (
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb # awkward comment
|
||||
)
|
||||
aaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb # awkward comment
|
||||
|
||||
|
||||
def test():
|
||||
@@ -202,13 +200,9 @@ if True:
|
||||
if True:
|
||||
if True:
|
||||
# Black layout
|
||||
model.config.use_cache = (
|
||||
False # FSTM still requires this hack -> FSTM should probably be refactored s
|
||||
)
|
||||
model.config.use_cache = False # FSTM still requires this hack -> FSTM should probably be refactored s
|
||||
# Ruff layout
|
||||
model.config.use_cache = (
|
||||
False
|
||||
) # FSTM still requires this hack -> FSTM should probably be refactored s
|
||||
model.config.use_cache = False # FSTM still requires this hack -> FSTM should probably be refactored s
|
||||
|
||||
|
||||
# Regression test for https://github.com/astral-sh/ruff/issues/7463
|
||||
|
||||
@@ -146,9 +146,7 @@ list_with_parenthesized_elements5 = [
|
||||
(2), # trailing outer
|
||||
]
|
||||
|
||||
nested_parentheses1 = (
|
||||
1 # i # j
|
||||
) # k
|
||||
nested_parentheses1 = 1 # i # j # k
|
||||
nested_parentheses2 = [
|
||||
(
|
||||
1 # i
|
||||
|
||||
@@ -81,6 +81,7 @@ natively, including:
|
||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [flake8-todos](https://pypi.org/project/flake8-todos/)
|
||||
- [flake8-trio](https://pypi.org/project/flake8-trio/) ([#8451](https://github.com/astral-sh/ruff/issues/8451))
|
||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
|
||||
@@ -185,6 +186,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [flake8-todos](https://pypi.org/project/flake8-todos/)
|
||||
- [flake8-trio](https://pypi.org/project/flake8-trio/) ([#8451](https://github.com/astral-sh/ruff/issues/8451))
|
||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
PyYAML==6.0
|
||||
PyYAML==6.0.1
|
||||
black==23.10.0
|
||||
mkdocs==1.5.0
|
||||
git+ssh://git@github.com/astral-sh/mkdocs-material-insiders.git@38c0b8187325c3bab386b666daf3518ac036f2f4
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
PyYAML==6.0
|
||||
PyYAML==6.0.1
|
||||
black==23.10.0
|
||||
mkdocs==1.5.0
|
||||
mkdocs-material==9.1.18
|
||||
|
||||
@@ -107,6 +107,7 @@ export default function SourceEditor({
|
||||
<Editor
|
||||
beforeMount={handleMount}
|
||||
options={{
|
||||
fixedOverflowWidgets: true,
|
||||
readOnly: false,
|
||||
minimap: { enabled: false },
|
||||
fontSize: 14,
|
||||
|
||||
@@ -28,8 +28,7 @@ html,
|
||||
|
||||
@font-face {
|
||||
font-family: "Alliance Text";
|
||||
src:
|
||||
url("../fonts/Alliance-TextRegular.woff2") format("woff2"),
|
||||
src: url("../fonts/Alliance-TextRegular.woff2") format("woff2"),
|
||||
url("../fonts/Alliance-TextRegular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
@@ -38,8 +37,7 @@ html,
|
||||
|
||||
@font-face {
|
||||
font-family: "Alliance Text";
|
||||
src:
|
||||
url("../fonts/Alliance-TextMedium.woff2") format("woff2"),
|
||||
src: url("../fonts/Alliance-TextMedium.woff2") format("woff2"),
|
||||
url("../fonts/Alliance-TextMedium.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
@@ -48,8 +46,7 @@ html,
|
||||
|
||||
@font-face {
|
||||
font-family: "Alliance Platt";
|
||||
src:
|
||||
url("../fonts/Alliance-PlattMedium.woff2") format("woff2"),
|
||||
src: url("../fonts/Alliance-PlattMedium.woff2") format("woff2"),
|
||||
url("../fonts/Alliance-PlattMedium.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
@@ -58,8 +55,7 @@ html,
|
||||
|
||||
@font-face {
|
||||
font-family: "Alliance Platt";
|
||||
src:
|
||||
url("../fonts/Alliance-PlattRegular.woff2") format("woff2"),
|
||||
src: url("../fonts/Alliance-PlattRegular.woff2") format("woff2"),
|
||||
url("../fonts/Alliance-PlattRegular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
@@ -11,9 +11,13 @@ def markdown_project_section(
|
||||
) -> list[str]:
|
||||
return markdown_details(
|
||||
summary=f'<a href="{project.repo.url}">{project.repo.fullname}</a> ({title})',
|
||||
# Show the command used for the check
|
||||
preface="<pre>ruff " + " ".join(options.to_ruff_args()) + "</pre>",
|
||||
content=content,
|
||||
preface=(
|
||||
# Show the command used for the check if the options are non-default
|
||||
"<pre>ruff " + " ".join(options.to_ruff_args()) + "</pre>"
|
||||
if options != type(options)()
|
||||
else None
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -24,12 +28,13 @@ def markdown_plus_minus(added: int, removed: int) -> str:
|
||||
return f"+{added} -{removed}"
|
||||
|
||||
|
||||
def markdown_details(summary: str, preface: str, content: str | list[str]):
|
||||
def markdown_details(summary: str, content: str | list[str], preface: str):
|
||||
lines = []
|
||||
lines.append(f"<details><summary>{summary}</summary>")
|
||||
lines.append("<p>")
|
||||
lines.append(preface)
|
||||
lines.append("</p>")
|
||||
if preface:
|
||||
lines.append("<p>")
|
||||
lines.append(preface)
|
||||
lines.append("</p>")
|
||||
lines.append("<p>")
|
||||
lines.append("")
|
||||
|
||||
|
||||
7
ruff.schema.json
generated
7
ruff.schema.json
generated
@@ -2903,6 +2903,9 @@
|
||||
"NPY001",
|
||||
"NPY002",
|
||||
"NPY003",
|
||||
"NPY2",
|
||||
"NPY20",
|
||||
"NPY201",
|
||||
"NURSERY",
|
||||
"PD",
|
||||
"PD0",
|
||||
@@ -3465,6 +3468,10 @@
|
||||
"TID251",
|
||||
"TID252",
|
||||
"TID253",
|
||||
"TRIO",
|
||||
"TRIO1",
|
||||
"TRIO10",
|
||||
"TRIO100",
|
||||
"TRY",
|
||||
"TRY0",
|
||||
"TRY00",
|
||||
|
||||
@@ -36,16 +36,44 @@ def get_mapping_data() -> dict:
|
||||
return json.loads(json.loads(content))
|
||||
|
||||
|
||||
def format_number(number: int) -> str:
|
||||
"""Underscore-separate the digits of a number."""
|
||||
# For unknown historical reasons, numbers greater than 100,000 were
|
||||
# underscore-delimited in the generated file, so we now preserve that property to
|
||||
# avoid unnecessary churn.
|
||||
if number > 100000:
|
||||
number = str(number)
|
||||
number = "_".join(number[i : i + 3] for i in range(0, len(number), 3))
|
||||
return f"{number}_u32"
|
||||
|
||||
return f"{number}u32"
|
||||
|
||||
|
||||
def format_confusables_rs(raw_data: dict[str, list[int]]) -> str:
|
||||
"""Format the downloaded data into a Rust source file."""
|
||||
# The input data contains duplicate entries
|
||||
# The input data contains duplicate entries.
|
||||
flattened_items: set[tuple[int, int]] = set()
|
||||
for _category, items in raw_data.items():
|
||||
assert len(items) % 2 == 0, "Expected pairs of items"
|
||||
for i in range(0, len(items), 2):
|
||||
flattened_items.add((items[i], items[i + 1]))
|
||||
|
||||
tuples = [f" {left}u32 => {right},\n" for left, right in sorted(flattened_items)]
|
||||
tuples = [
|
||||
f" {format_number(left)} => {right},\n"
|
||||
for left, right in sorted(flattened_items)
|
||||
]
|
||||
|
||||
# Add some additional confusable pairs that are not included in the VS Code data,
|
||||
# as they're unicode-to-unicode confusables, not unicode-to-ASCII confusables.
|
||||
confusable_units = [
|
||||
# ANGSTROM SIGN → LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
("0x212B", "0x00C5"),
|
||||
# OHM SIGN → GREEK CAPITAL LETTER OMEGA
|
||||
("0x2126", "0x03A9"),
|
||||
# MICRO SIGN → GREEK SMALL LETTER MU
|
||||
("0x00B5", "0x03BC"),
|
||||
]
|
||||
tuples += [f" {left} => {right},\n" for left, right in confusable_units]
|
||||
|
||||
print(f"{len(tuples)} confusable tuples.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user