Compare commits

...

28 Commits

Author SHA1 Message Date
konstin
8d54302e05 Import cases dir from black tests 2023-11-10 13:45:30 +01:00
Charlie Marsh
036b6bc0bd Document context manager breaking deviation vs. Black (#8597)
Closes https://github.com/astral-sh/ruff/issues/8180.
Closes https://github.com/astral-sh/ruff/issues/8580.
Closes https://github.com/astral-sh/ruff/issues/7441.
2023-11-10 04:32:29 +00:00
Dhruv Manilawala
d5606b7705 Consider the new f-string tokens for flake8-commas (#8582)
## Summary

This fixes the bug where the `flake8-commas` rules weren't taking the
new f-string tokens into account.

## Test Plan

Add new test cases around f-strings for all of `flake8-commas`'s rules.

fixes: #8556
2023-11-10 09:49:14 +05:30
Charlie Marsh
7968e190dd Write unchanged, excluded files to stdout when read via stdin (#8596)
## Summary

When you run Ruff via stdin, and pass `format` or `check --fix`, we
typically write the changed or unchanged contents to stdout. It turns
out we forgot to do this when the file is _excluded_, so if you run
`ruff format /path/to/excluded/file.py`, we don't write _anything_ to
`stdout`. This led to a bug in the LSP whereby we deleted file contents
for third-party files.

The right thing to do here is write back the unchanged contents, as it
should always be safe to write the output of stdout back to a file.
2023-11-09 23:15:01 -05:00
Charlie Marsh
346a828db2 Add a BindingKind for WithItem variables (#8594) 2023-11-09 22:44:49 -05:00
Charlie Marsh
0ac124acef Make unpacked assignment a flag rather than a BindingKind (#8595)
## Summary

An assignment can be _both_ (e.g.) a loop variable _and_ assigned via
unpacking. In other words, unpacking is a quality of an assignment, not
a _kind_.
2023-11-09 21:41:30 -05:00
Adrian
4ebd0bd31e Support local and dynamic class- and static-method decorators (#8592)
## Summary

This brings ruff's behavior in line with what `pep8-naming` already does
and thus closes #8397.

I had initially implemented this to look at the last segment of a dotted
path only when the entry in the `*-decorators` setting started with a
`.`, but in the end I thought it's better to remain consistent w/
`pep8-naming` and doing a match against the last segment of the
decorator name in any case.

If you prefer to diverge from this in favor of less ambiguity in the
configuration let me know and I'll change it so you would need to put
e.g. `.expression` in the `classmethod-decorators` list.

## Test Plan

Tested against the file in the issue linked below, plus the new testcase
added in this PR.
2023-11-10 02:04:25 +00:00
Zanie Blue
565ddebb15 Improve detection of TYPE_CHECKING blocks imported from typing_extensions or _typeshed (#8429)
~Improves detection of types imported from `typing_extensions`. Removes
the hard-coded list of supported types in `typing_extensions`; instead
assuming all types could be imported from `typing`, `_typeshed`, or
`typing_extensions`.~

~The typing extensions package appears to re-export types even if they
do not need modification.~


Adds detection of `if typing_extensions.TYPE_CHECKING` blocks. Avoids
inserting a new `if TYPE_CHECKING` block and `from typing import
TYPE_CHECKING` if `typing_extensions.TYPE_CHECKING` is used (closes
https://github.com/astral-sh/ruff/issues/8427)

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-11-09 12:21:03 -06:00
Dhruv Manilawala
9d167a1f5c Slice source code instead of generating it for EM fixes (#7746)
## Summary

This PR fixes the bug where the generated fix for `EM*` rules would
replace a
triple-quoted (f-)string with a single-quoted (f-)string. This changes
the
semantic of the string in case it contains a single-quoted string
literal. This
is especially evident with f-strings where the expression could contain
another
string within it. For example,

```python
f"""normal {"another"} normal"""
```

## Test Plan

Add test case for triple-quoted string and update the snapshots.

fixes: #6988
fixes: #7736
2023-11-09 05:22:15 +00:00
Charlie Marsh
9e184a9067 Revert "Avoid inserting trailing commas within f-strings" (#8576)
Reverts astral-sh/ruff#8574. This caused a bunch of ecosystem changes --
needs more work.
2023-11-09 05:02:04 +00:00
Charlie Marsh
9d1027c239 Fix permalink to convention setting (#8575) 2023-11-09 04:50:32 +00:00
Charlie Marsh
f499f0ca60 Avoid inserting trailing commas within f-strings (#8574)
Closes https://github.com/astral-sh/ruff/issues/8556.
2023-11-08 23:25:23 -05:00
Charlie Marsh
722687ad72 Detect runtime-evaluated base classes defined in the current file (#8572)
Closes https://github.com/astral-sh/ruff/issues/8250.

Closes https://github.com/astral-sh/ruff/issues/5486.
2023-11-08 22:38:06 -05:00
Dhruv Manilawala
4760af3dcb Avoid FURB113 autofix if comments are present (#8494)
This PR avoids creating the fix for `FURB113` if there are comments in
between the `append` calls.

fixes: #8105
2023-11-09 03:10:11 +00:00
doolio
4fdf97a95c Apply consistent code block labels (#8563)
This ensures the python label is used for all python code blocks for
consistency.

## Test Plan

Visual inspection of all changes via git client ensuring no other
changes were made in error.
2023-11-09 01:49:24 +00:00
doolio
0ea1076f85 Add missing config tabs (#8558) 2023-11-09 01:49:06 +00:00
Zanie Blue
3956f38999 Prepare release 0.1.5 (#8570)
[Rendered
CHANGELOG](https://github.com/astral-sh/ruff/blob/release/015/CHANGELOG.md#015)
2023-11-08 16:00:57 -06:00
Zanie Blue
fe9727ac38 Add rooster release management configuration and instructions (#8567)
I'd rather not be the only one who can easily generate our changelog
entries so I invested some time to get Rooster a bit further along and
add instructions.
2023-11-08 13:08:19 -06:00
Dosenpfand
3ebaca5246 Doc: Fix link to isort known-first-party (#8562) 2023-11-08 11:12:11 -05:00
Felix Williams
7391f74cbc Add hidden --extension to override inference of source type from file extension (#8373)
## Summary

This PR addresses the incompatibility with `jupyterlab-lsp` +
`python-lsp-ruff` arising from the inference of source type from file
extension, raised in #6847.

In particular it follows the suggestion in
https://github.com/astral-sh/ruff/issues/6847#issuecomment-1765724679 to
specify a mapping from file extension to source type.

The source types are

- python
- pyi
- ipynb

Usage:

```sh
ruff check --no-cache --stdin-filename Untitled.ipynb --extension ipynb:python
```

Unlike the original suggestion, `:` instead of `=` is used to associate
file extensions to language since that is what is used with
`--per-file-ignores` which is an existing option that accepts a mapping.

## Test Plan

2 tests added to `integration_test.rs` to ensure the override works as
expected

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-11-08 08:02:40 +05:30
Charlie Marsh
71e93a9fa4 Only flag flake8-trio rule when trio is present (#8550)
## Summary

Hoping to avoid some false positives by narrowing the scope of
https://github.com/astral-sh/ruff/pull/8534.
2023-11-07 22:27:58 +00:00
Kar Petrosyan
e2c7b1ece6 [TRIO] Add TRIO109 rule (#8534)
## Summary

Adds TRIO109 from the [flake8-trio
plugin](https://github.com/Zac-HD/flake8-trio).
Relates to: https://github.com/astral-sh/ruff/issues/8451
2023-11-07 17:13:01 -05:00
Charlie Marsh
621e98f452 Improve detail link contrast in dark mode (#8548)
Use our light-mode styling for links in that context.

<img width="627" alt="Screen Shot 2023-11-07 at 4 34 48 PM"
src="https://github.com/astral-sh/ruff/assets/1309177/1e30c3ac-18e2-4663-876c-75c6f8b67d53">

Closes https://github.com/astral-sh/ruff/issues/8519.
2023-11-07 21:41:34 +00:00
Kar Petrosyan
0126f74c29 Add TRIO110 rule (#8537)
## Summary

Adds TRIO110 from the [flake8-trio
plugin](https://github.com/Zac-HD/flake8-trio).
Relates to: https://github.com/astral-sh/ruff/issues/8451
2023-11-07 21:27:19 +00:00
Chaojie
fce9f63418 [flake8-bandit] Implement mako-templates (S702) (#8533)
See: https://github.com/astral-sh/ruff/issues/1646.
2023-11-07 20:58:43 +00:00
Charlie Marsh
ce549e75bc Update pre-commit documentation (#8545)
I got some feedback on Mastodon that it wasn't clear how to use the
linter and formatter together in pre-commit (mostly in the pre-commit
repo's documentation, which is even less clear, but the two should be
consistent).
2023-11-07 18:40:13 +00:00
Lukasz Piatkowski
03303a9edd Account for selector specificity when merging extend_unsafe_fixes and override extend_safe_fixes (#8444)
## Summary

Prior to this change `extend_unsafe_fixes` took precedence over
`extend_safe_fixes` selectors, so any conflicts were resolved in favour
of `extend_unsafe_fixes`. Thanks to that ruff were conservatively
assuming that if configs conlict the fix corresponding to selected rule
will be treated as unsafe.

After this change we take into account Specificity of the selectors. For
conflicts between selectors of the same Specificity we will treat the
corresponding fixes as unsafe. But if the conflicting selectors are of
different specificity the more specific one will win.

## Test Plan

Tests were added for the `FixSafetyTable` struct. The
`check_extend_unsafe_fixes_conflict_with_extend_safe_fixes_by_specificity`
integration test was added to test conflicting rules of different
specificity.

Fixes #8404

---------

Co-authored-by: Zanie <contact@zanie.dev>
2023-11-07 10:33:40 -06:00
Zanie Blue
7873ca38e5 Update applicability messages for clarity in tests (#8541)
These names are only ever displayed internally right now and we could be
clearer in our test snapshots.

The diff is kind of scary because all of the tests fixtures are updated.
2023-11-07 16:11:43 +00:00
1147 changed files with 48963 additions and 3780 deletions

29
.github/release.yml vendored
View File

@@ -1,29 +0,0 @@
# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
changelog:
exclude:
labels:
- internal
- documentation
categories:
- title: Breaking Changes
labels:
- breaking
- title: Rules
labels:
- rule
- title: Settings
labels:
- configuration
- cli
- title: Bug Fixes
labels:
- bug
- title: Formatter
labels:
- formatter
- title: Preview
labels:
- preview
- title: Other Changes
labels:
- "*"

View File

@@ -1,5 +1,54 @@
# Changelog
## 0.1.5
### Preview features
- \[`flake8-bandit`\] Implement `mako-templates` (`S702`) ([#8533](https://github.com/astral-sh/ruff/pull/8533))
- \[`flake8-trio`\] Implement `TRIO105` ([#8490](https://github.com/astral-sh/ruff/pull/8490))
- \[`flake8-trio`\] Implement `TRIO109` ([#8534](https://github.com/astral-sh/ruff/pull/8534))
- \[`flake8-trio`\] Implement `TRIO110` ([#8537](https://github.com/astral-sh/ruff/pull/8537))
- \[`flake8-trio`\] Implement `TRIO115` ([#8486](https://github.com/astral-sh/ruff/pull/8486))
- \[`refurb`\] Implement `type-none-comparison` (`FURB169`) ([#8487](https://github.com/astral-sh/ruff/pull/8487))
- Flag all comparisons against builtin types in `E721` ([#8491](https://github.com/astral-sh/ruff/pull/8491))
- Make `SIM118` fix as safe when the expression is a known dictionary ([#8525](https://github.com/astral-sh/ruff/pull/8525))
### Formatter
- Fix multiline lambda expression statement formatting ([#8466](https://github.com/astral-sh/ruff/pull/8466))
### CLI
- Add hidden `--extension` to override inference of source type from file extension ([#8373](https://github.com/astral-sh/ruff/pull/8373))
### Configuration
- Account for selector specificity when merging `extend_unsafe_fixes` and `override extend_safe_fixes` ([#8444](https://github.com/astral-sh/ruff/pull/8444))
- Add support for disabling cache with `RUFF_NO_CACHE` environment variable ([#8538](https://github.com/astral-sh/ruff/pull/8538))
### Bug fixes
- \[`E721`\] Flag comparisons to `memoryview` ([#8485](https://github.com/astral-sh/ruff/pull/8485))
- Allow collapsed-ellipsis bodies in other statements ([#8499](https://github.com/astral-sh/ruff/pull/8499))
- Avoid `D301` autofix for `u` prefixed strings ([#8495](https://github.com/astral-sh/ruff/pull/8495))
- Only flag `flake8-trio` rules when `trio` import is present ([#8550](https://github.com/astral-sh/ruff/pull/8550))
- Reject more syntactically invalid Python programs ([#8524](https://github.com/astral-sh/ruff/pull/8524))
- Avoid raising `TRIO115` violations for `trio.sleep(...)` calls with non-number values ([#8532](https://github.com/astral-sh/ruff/pull/8532))
- Fix `F841` false negative on assignment to multiple variables ([#8489](https://github.com/astral-sh/ruff/pull/8489))
### Documentation
- Fix link to isort `known-first-party` ([#8562](https://github.com/astral-sh/ruff/pull/8562))
- Add notes on fix safety to a few rules ([#8500](https://github.com/astral-sh/ruff/pull/8500))
- Add missing toml config tabs ([#8512](https://github.com/astral-sh/ruff/pull/8512))
- Add instructions for configuration of Emacs ([#8488](https://github.com/astral-sh/ruff/pull/8488))
- Improve detail link contrast in dark mode ([#8548](https://github.com/astral-sh/ruff/pull/8548))
- Fix typo in example ([#8506](https://github.com/astral-sh/ruff/pull/8506))
- Added tabs for configuration files in the documentation ([#8480](https://github.com/astral-sh/ruff/pull/8480))
- Recommend `project.requires-python` over `target-version` ([#8513](https://github.com/astral-sh/ruff/pull/8513))
- Add singleton escape hatch to `B008` documentation ([#8501](https://github.com/astral-sh/ruff/pull/8501))
- Fix tab configuration docs ([#8502](https://github.com/astral-sh/ruff/pull/8502))
## 0.1.4
### Preview features

View File

@@ -315,9 +315,18 @@ even patch releases may contain [non-backwards-compatible changes](https://semve
### Creating a new release
1. Update the version with `rg 0.0.269 --files-with-matches | xargs sed -i 's/0.0.269/0.0.270/g'`
1. Update `BREAKING_CHANGES.md`
1. Create a PR with the version and `BREAKING_CHANGES.md` updated
We use an experimental in-house tool for managing releases.
1. Install `rooster`: `pip install git+https://github.com/zanieb/rooster@main`
1. Run `rooster release`; this command will:
- Generate a changelog entry in `CHANGELOG.md`
- Update versions in `pyproject.toml` and `Cargo.toml`
- Update references to versions in the `README.md` and documentation
1. The changelog should then be editorialized for consistency
- Often labels will be missing from pull requests they will need to be manually organized into the proper section
- Changes should be edited to be user-facing descriptions, avoiding internal details
1. Highlight any breaking changes in `BREAKING_CHANGES.md`
1. Create a pull request with the changelog and version updates
1. Merge the PR
1. Run the release workflow with the version number (without starting `v`) as input. Make sure
main has your merged PR as last commit
@@ -330,7 +339,11 @@ even patch releases may contain [non-backwards-compatible changes](https://semve
1. Attach artifacts to draft GitHub release
1. Trigger downstream repositories. This can fail non-catastrophically, as we can run any
downstream jobs manually if needed.
1. Create release notes in GitHub UI and promote from draft.
1. Publish the GitHub release
1. Open the draft release in the GitHub release section
1. Copy the changelog for the release into the GitHub release
- See previous releases for formatting of section headers
1. Generate the contributor list with `rooster contributors` and add to the release notes
1. If needed, [update the schemastore](https://github.com/charliermarsh/ruff/blob/main/scripts/update_schemastore.py)
1. If needed, update the `ruff-lsp` and `ruff-vscode` repositories.

8
Cargo.lock generated
View File

@@ -810,7 +810,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.1.4"
version = "0.1.5"
dependencies = [
"anyhow",
"clap",
@@ -2060,7 +2060,7 @@ dependencies = [
[[package]]
name = "ruff_cli"
version = "0.1.4"
version = "0.1.5"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -2196,7 +2196,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.1.4"
version = "0.1.5"
dependencies = [
"aho-corasick",
"annotate-snippets 0.9.1",
@@ -2447,7 +2447,7 @@ dependencies = [
[[package]]
name = "ruff_shrinking"
version = "0.1.4"
version = "0.1.5"
dependencies = [
"anyhow",
"clap",

View File

@@ -150,11 +150,12 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.1.4
rev: v0.1.5
hooks:
# Run the Ruff linter.
# Run the linter.
- id: ruff
# Run the Ruff formatter.
args: [ --fix ]
# Run the formatter.
- id: ruff-format
```

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.1.4"
version = "0.1.5"
description = """
Convert Flake8 configuration files to Ruff configuration files.
"""

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_cli"
version = "0.1.4"
version = "0.1.5"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -8,8 +8,8 @@ use ruff_linter::line_width::LineLength;
use ruff_linter::logging::LogLevel;
use ruff_linter::registry::Rule;
use ruff_linter::settings::types::{
FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion, SerializationFormat,
UnsafeFixes,
ExtensionPair, FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion,
SerializationFormat, UnsafeFixes,
};
use ruff_linter::{RuleParser, RuleSelector, RuleSelectorParser};
use ruff_workspace::configuration::{Configuration, RuleSelection};
@@ -351,6 +351,9 @@ pub struct CheckCommand {
conflicts_with = "watch",
)]
pub show_settings: bool,
/// List of mappings from file extension to language (one of ["python", "ipynb", "pyi"]).
#[arg(long, value_delimiter = ',', hide = true)]
pub extension: Option<Vec<ExtensionPair>>,
/// Dev-only argument to show fixes
#[arg(long, hide = true)]
pub ecosystem_ci: bool,
@@ -535,6 +538,7 @@ impl CheckCommand {
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
output_format: self.output_format,
show_fixes: resolve_bool_arg(self.show_fixes, self.no_show_fixes),
extension: self.extension,
},
)
}
@@ -647,6 +651,7 @@ pub struct CliOverrides {
pub force_exclude: Option<bool>,
pub output_format: Option<SerializationFormat>,
pub show_fixes: Option<bool>,
pub extension: Option<Vec<ExtensionPair>>,
}
impl ConfigurationTransformer for CliOverrides {
@@ -731,6 +736,9 @@ impl ConfigurationTransformer for CliOverrides {
if let Some(target_version) = &self.target_version {
config.target_version = Some(*target_version);
}
if let Some(extension) = &self.extension {
config.lint.extension = Some(extension.clone().into_iter().collect());
}
config
}

View File

@@ -30,6 +30,7 @@ use crate::diagnostics::Diagnostics;
use crate::panic::catch_unwind;
/// Run the linter over a collection of files.
#[allow(clippy::too_many_arguments)]
pub(crate) fn check(
files: &[PathBuf],
pyproject_config: &PyprojectConfig,
@@ -184,6 +185,7 @@ pub(crate) fn check(
/// Wraps [`lint_path`](crate::diagnostics::lint_path) in a [`catch_unwind`](std::panic::catch_unwind) and emits
/// a diagnostic if the linting the file panics.
#[allow(clippy::too_many_arguments)]
fn lint_path(
path: &Path,
package: Option<&Path>,

View File

@@ -8,7 +8,7 @@ use ruff_workspace::resolver::{match_exclusion, python_file_at_path, PyprojectCo
use crate::args::CliOverrides;
use crate::diagnostics::{lint_stdin, Diagnostics};
use crate::stdin::read_from_stdin;
use crate::stdin::{parrot_stdin, read_from_stdin};
/// Run the linter over a single file, read from `stdin`.
pub(crate) fn check_stdin(
@@ -21,6 +21,9 @@ pub(crate) fn check_stdin(
if pyproject_config.settings.file_resolver.force_exclude {
if let Some(filename) = filename {
if !python_file_at_path(filename, pyproject_config, overrides)? {
if fix_mode.is_apply() {
parrot_stdin()?;
}
return Ok(Diagnostics::default());
}
@@ -29,14 +32,17 @@ pub(crate) fn check_stdin(
.file_name()
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
{
if fix_mode.is_apply() {
parrot_stdin()?;
}
return Ok(Diagnostics::default());
}
}
}
let stdin = read_from_stdin()?;
let package_root = filename.and_then(Path::parent).and_then(|path| {
packaging::detect_package_root(path, &pyproject_config.settings.linter.namespace_packages)
});
let stdin = read_from_stdin()?;
let mut diagnostics = lint_stdin(
filename,
package_root,

View File

@@ -15,7 +15,7 @@ use crate::commands::format::{
FormatResult, FormattedSource,
};
use crate::resolve::resolve;
use crate::stdin::read_from_stdin;
use crate::stdin::{parrot_stdin, read_from_stdin};
use crate::ExitStatus;
/// Run the formatter over a single file, read from `stdin`.
@@ -34,6 +34,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
if pyproject_config.settings.file_resolver.force_exclude {
if let Some(filename) = cli.stdin_filename.as_deref() {
if !python_file_at_path(filename, &pyproject_config, overrides)? {
if mode.is_write() {
parrot_stdin()?;
}
return Ok(ExitStatus::Success);
}
@@ -42,6 +45,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
.file_name()
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
{
if mode.is_write() {
parrot_stdin()?;
}
return Ok(ExitStatus::Success);
}
}
@@ -50,6 +56,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
let path = cli.stdin_filename.as_deref();
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
if mode.is_write() {
parrot_stdin()?;
}
return Ok(ExitStatus::Success);
};

View File

@@ -17,13 +17,13 @@ use ruff_linter::logging::DisplayParseError;
use ruff_linter::message::Message;
use ruff_linter::pyproject_toml::lint_pyproject_toml;
use ruff_linter::registry::AsRule;
use ruff_linter::settings::types::UnsafeFixes;
use ruff_linter::settings::types::{ExtensionMapping, UnsafeFixes};
use ruff_linter::settings::{flags, LinterSettings};
use ruff_linter::source_kind::{SourceError, SourceKind};
use ruff_linter::{fs, IOError, SyntaxError};
use ruff_notebook::{Notebook, NotebookError, NotebookIndex};
use ruff_python_ast::imports::ImportMap;
use ruff_python_ast::{SourceType, TomlSourceType};
use ruff_python_ast::{PySourceType, SourceType, TomlSourceType};
use ruff_source_file::{LineIndex, SourceCode, SourceFileBuilder};
use ruff_text_size::{TextRange, TextSize};
use ruff_workspace::Settings;
@@ -177,6 +177,11 @@ impl AddAssign for FixMap {
}
}
fn override_source_type(path: Option<&Path>, extension: &ExtensionMapping) -> Option<PySourceType> {
let ext = path?.extension()?.to_str()?;
extension.get(ext).map(PySourceType::from)
}
/// Lint the source code at the given `Path`.
pub(crate) fn lint_path(
path: &Path,
@@ -221,31 +226,35 @@ pub(crate) fn lint_path(
debug!("Checking: {}", path.display());
let source_type = match SourceType::from(path) {
SourceType::Toml(TomlSourceType::Pyproject) => {
let messages = if settings
.rules
.iter_enabled()
.any(|rule_code| rule_code.lint_source().is_pyproject_toml())
{
let contents = match std::fs::read_to_string(path).map_err(SourceError::from) {
Ok(contents) => contents,
Err(err) => {
return Ok(Diagnostics::from_source_error(&err, Some(path), settings));
}
let source_type = match override_source_type(Some(path), &settings.extension) {
Some(source_type) => source_type,
None => match SourceType::from(path) {
SourceType::Toml(TomlSourceType::Pyproject) => {
let messages = if settings
.rules
.iter_enabled()
.any(|rule_code| rule_code.lint_source().is_pyproject_toml())
{
let contents = match std::fs::read_to_string(path).map_err(SourceError::from) {
Ok(contents) => contents,
Err(err) => {
return Ok(Diagnostics::from_source_error(&err, Some(path), settings));
}
};
let source_file =
SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
lint_pyproject_toml(source_file, settings)
} else {
vec![]
};
let source_file = SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
lint_pyproject_toml(source_file, settings)
} else {
vec![]
};
return Ok(Diagnostics {
messages,
..Diagnostics::default()
});
}
SourceType::Toml(_) => return Ok(Diagnostics::default()),
SourceType::Python(source_type) => source_type,
return Ok(Diagnostics {
messages,
..Diagnostics::default()
});
}
SourceType::Toml(_) => return Ok(Diagnostics::default()),
SourceType::Python(source_type) => source_type,
},
};
// Extract the sources from the file.
@@ -370,8 +379,15 @@ pub(crate) fn lint_stdin(
fix_mode: flags::FixMode,
) -> Result<Diagnostics> {
// TODO(charlie): Support `pyproject.toml`.
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
return Ok(Diagnostics::default());
let source_type = if let Some(source_type) =
override_source_type(path, &settings.linter.extension)
{
source_type
} else {
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
return Ok(Diagnostics::default());
};
source_type
};
// Extract the sources from the file.

View File

@@ -1,5 +1,5 @@
use std::io;
use std::io::Read;
use std::io::{Read, Write};
/// Read a string from `stdin`.
pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
@@ -7,3 +7,11 @@ pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
io::stdin().lock().read_to_string(&mut buffer)?;
Ok(buffer)
}
/// Read bytes from `stdin` and write them to `stdout`.
pub(crate) fn parrot_stdin() -> Result<(), io::Error> {
let mut buffer = String::new();
io::stdin().lock().read_to_string(&mut buffer)?;
io::stdout().write_all(buffer.as_bytes())?;
Ok(())
}

View File

@@ -320,6 +320,11 @@ if __name__ == '__main__':
exit_code: 0
----- stdout -----
from test import say_hy
if __name__ == '__main__':
say_hy("dear Ruff contributor")
----- stderr -----
"###);
Ok(())

View File

@@ -320,6 +320,119 @@ fn stdin_fix_jupyter() {
Found 2 errors (2 fixed, 0 remaining).
"###);
}
#[test]
fn stdin_override_parser_ipynb() {
let args = ["--extension", "py:ipynb", "--stdin-filename", "Jupyter.py"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin(r#"{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "dccc687c-96e2-4604-b957-a8a89b5bec06",
"metadata": {},
"outputs": [],
"source": [
"import os"
]
},
{
"cell_type": "markdown",
"id": "19e1b029-f516-4662-a9b9-623b93edac1a",
"metadata": {},
"source": [
"Foo"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "cdce7b92-b0fb-4c02-86f6-e233b26fa84f",
"metadata": {},
"outputs": [],
"source": [
"import sys"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "e40b33d2-7fe4-46c5-bdf0-8802f3052565",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1\n"
]
}
],
"source": [
"print(1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a1899bc8-d46f-4ec0-b1d1-e1ca0f04bf60",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}"#), @r###"
success: false
exit_code: 1
----- stdout -----
Jupyter.py:cell 1:1:8: F401 [*] `os` imported but unused
Jupyter.py:cell 3:1:8: F401 [*] `sys` imported but unused
Found 2 errors.
[*] 2 fixable with the `--fix` option.
----- stderr -----
"###);
}
#[test]
fn stdin_override_parser_py() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(["--extension", "ipynb:python", "--stdin-filename", "F401.ipynb"])
.pass_stdin("import os\n"), @r###"
success: false
exit_code: 1
----- stdout -----
F401.ipynb:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 fixable with the `--fix` option.
----- stderr -----
"###);
}
#[test]
fn stdin_fix_when_not_fixable_should_still_print_contents() {
@@ -1407,3 +1520,47 @@ extend-safe-fixes = ["UP034"]
Ok(())
}
#[test]
fn check_extend_unsafe_fixes_conflict_with_extend_safe_fixes_by_specificity() -> Result<()> {
// Adding a rule to one option with a more specific selector should override the other option
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
target-version = "py310"
[lint]
extend-unsafe-fixes = ["UP", "UP034"]
extend-safe-fixes = ["UP03"]
"#,
)?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["check", "--config"])
.arg(&ruff_toml)
.arg("-")
.args([
"--output-format",
"text",
"--no-cache",
"--select",
"F601,UP018,UP034,UP038",
])
.pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\nprint(str('foo'))\nisinstance(x, (int, str))\n"),
@r###"
success: false
exit_code: 1
----- stdout -----
-:1:14: F601 Dictionary key literal `'a'` repeated
-:2:7: UP034 Avoid extraneous parentheses
-:3:7: UP018 Unnecessary `str` call (rewrite as a literal)
-:4:1: UP038 [*] Use `X | Y` in `isinstance` call instead of `(X, Y)`
Found 4 errors.
[*] 1 fixable with the `--fix` option (3 hidden fixes can be enabled with the `--unsafe-fixes` option).
----- stderr -----
"###);
Ok(())
}

View File

@@ -12,7 +12,7 @@ use crate::edit::Edit;
pub enum Applicability {
/// The fix is unsafe and should only be displayed for manual application by the user.
/// The fix is likely to be incorrect or the resulting code may have invalid syntax.
Display,
DisplayOnly,
/// The fix is unsafe and should only be applied with user opt-in.
/// The fix may be what the user intended, but it is uncertain; the resulting code will have valid syntax.
@@ -87,22 +87,22 @@ impl Fix {
}
}
/// Create a new [`Fix`] that should only [display](Applicability::Display) and not apply from an [`Edit`] element .
pub fn display_edit(edit: Edit) -> Self {
/// Create a new [`Fix`] that should only [display](Applicability::DisplayOnly) and not apply from an [`Edit`] element .
pub fn display_only_edit(edit: Edit) -> Self {
Self {
edits: vec![edit],
applicability: Applicability::Display,
applicability: Applicability::DisplayOnly,
isolation_level: IsolationLevel::default(),
}
}
/// Create a new [`Fix`] that should only [display](Applicability::Display) and not apply from multiple [`Edit`] elements.
pub fn display_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
/// Create a new [`Fix`] that should only [display](Applicability::DisplayOnly) and not apply from multiple [`Edit`] elements.
pub fn display_only_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
edits.sort_by_key(|edit| (edit.start(), edit.end()));
Self {
edits,
applicability: Applicability::Display,
applicability: Applicability::DisplayOnly,
isolation_level: IsolationLevel::default(),
}
}

View File

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

View File

@@ -0,0 +1,9 @@
from mako.template import Template
from mako import template
import mako
Template("hello")
mako.template.Template("hern")
template.Template("hern")

View File

@@ -639,3 +639,18 @@ foo = namedtuple(
:20
],
)
# F-strings
kwargs.pop("remove", f"this {trailing_comma}",)
raise Exception(
"first", extra=f"Add trailing comma here ->"
)
assert False, f"<- This is not a trailing comma"
f"""This is a test. {
"Another sentence."
if True else
"Don't add a trailing comma here ->"
}"""

View File

@@ -58,3 +58,33 @@ def f_fix_indentation_check(foo):
# Report these, but don't fix them
if foo: raise RuntimeError("This is an example exception")
if foo: x = 1; raise RuntimeError("This is an example exception")
def f_triple_quoted_string():
raise RuntimeError(f"""This is an {"example"} exception""")
def f_multi_line_string():
raise RuntimeError(
"first"
"second"
)
def f_multi_line_string2():
raise RuntimeError(
"This is an {example} exception".format(
example="example"
)
)
def f_multi_line_string2():
raise RuntimeError(
(
"This is an "
"{example} exception"
).format(
example="example"
)
)

View File

@@ -0,0 +1,13 @@
import trio
async def func():
...
async def func(timeout):
...
async def func(timeout=10):
...

View File

@@ -0,0 +1,16 @@
import trio
async def func():
while True:
await trio.sleep(10)
async def func():
while True:
await trio.sleep_until(10)
async def func():
while True:
trio.sleep(10)

View File

@@ -172,3 +172,14 @@ def f():
from module import Member
x: Member = 1
def f():
from typing_extensions import TYPE_CHECKING
from pandas import y
if TYPE_CHECKING:
_type = x
elif True:
_type = y

View File

@@ -0,0 +1,10 @@
from __future__ import annotations
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:
from pandas import DataFrame
def example() -> DataFrame:
pass

View File

@@ -0,0 +1,10 @@
from __future__ import annotations
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:
from pandas import DataFrame
def example() -> DataFrame:
x = DataFrame()

View File

@@ -37,3 +37,9 @@ if False:
if 0:
x: List
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:
pass # TCH005

View File

@@ -0,0 +1,11 @@
from __future__ import annotations
from collections.abc import Sequence
class MyBaseClass:
pass
class Foo(MyBaseClass):
foo: Sequence

View File

@@ -0,0 +1,9 @@
from __future__ import annotations
from collections.abc import Sequence
from module.direct import MyBaseClass
class Foo(MyBaseClass):
foo: Sequence

View File

@@ -0,0 +1,7 @@
from __future__ import annotations
from collections.abc import Sequence
class Foo(MyBaseClass):
foo: Sequence

View File

@@ -0,0 +1,11 @@
from __future__ import annotations
from collections.abc import Sequence # TCH003
class MyBaseClass:
pass
class Foo(MyBaseClass):
foo: Sequence

View File

@@ -0,0 +1,9 @@
from __future__ import annotations
from typing_extensions import Self
def func():
from pandas import DataFrame
df: DataFrame

View File

@@ -0,0 +1,9 @@
from __future__ import annotations
import typing_extensions
def func():
from pandas import DataFrame
df: DataFrame

View File

@@ -63,3 +63,33 @@ class PosOnlyClass:
def bad_method_pos_only(this, blah, /, self, something: str):
pass
class ModelClass:
@hybrid_property
def bad(cls):
pass
@bad.expression
def bad(self):
pass
@bad.wtf
def bad(cls):
pass
@hybrid_property
def good(self):
pass
@good.expression
def good(cls):
pass
@good.wtf
def good(self):
pass
@foobar.thisisstatic
def badstatic(foo):
pass

View File

@@ -123,6 +123,15 @@ def yes_six(x: list):
x.append(2)
if True:
# FURB113
nums.append(1)
# comment
nums.append(2)
# comment
nums.append(3)
# Non-errors.
nums.append(1)

View File

@@ -571,6 +571,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::Jinja2AutoescapeFalse) {
flake8_bandit::rules::jinja2_autoescape_false(checker, call);
}
if checker.enabled(Rule::MakoTemplates) {
flake8_bandit::rules::mako_templates(checker, call);
}
if checker.enabled(Rule::HardcodedPasswordFuncArg) {
flake8_bandit::rules::hardcoded_password_func_arg(checker, keywords);
}

View File

@@ -356,6 +356,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range());
}
}
if checker.enabled(Rule::TrioAsyncFunctionWithTimeout) {
flake8_trio::rules::async_function_with_timeout(checker, function_def);
}
#[cfg(feature = "unreachable-code")]
if checker.enabled(Rule::UnreachableCode) {
checker
@@ -1206,7 +1209,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
flake8_trio::rules::timeout_without_await(checker, with_stmt, items);
}
}
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
Stmt::While(while_stmt @ ast::StmtWhile { body, orelse, .. }) => {
if checker.enabled(Rule::FunctionUsesLoopVariable) {
flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Stmt(stmt));
}
@@ -1216,6 +1219,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::TryExceptInLoop) {
perflint::rules::try_except_in_loop(checker, body);
}
if checker.enabled(Rule::TrioUnneededSleep) {
flake8_trio::rules::unneeded_sleep(checker, while_stmt);
}
}
Stmt::For(
for_stmt @ ast::StmtFor {

View File

@@ -1415,7 +1415,7 @@ impl<'a> Checker<'a> {
// subsequent nodes are evaluated in the inner scope.
//
// For example, given:
// ```py
// ```python
// class A:
// T = range(10)
//
@@ -1423,7 +1423,7 @@ impl<'a> Checker<'a> {
// ```
//
// Conceptually, this is compiled as:
// ```py
// ```python
// class A:
// T = range(10)
//
@@ -1615,38 +1615,28 @@ impl<'a> Checker<'a> {
fn handle_node_store(&mut self, id: &'a str, expr: &Expr) {
let parent = self.semantic.current_statement();
let mut flags = BindingFlags::empty();
if helpers::is_unpacking_assignment(parent, expr) {
flags.insert(BindingFlags::UNPACKED_ASSIGNMENT);
}
// Match the left-hand side of an annotated assignment, like `x` in `x: int`.
if matches!(
parent,
Stmt::AnnAssign(ast::StmtAnnAssign { value: None, .. })
) && !self.semantic.in_annotation()
{
self.add_binding(
id,
expr.range(),
BindingKind::Annotation,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::Annotation, flags);
return;
}
if parent.is_for_stmt() {
self.add_binding(
id,
expr.range(),
BindingKind::LoopVar,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::LoopVar, flags);
return;
}
if helpers::is_unpacking_assignment(parent, expr) {
self.add_binding(
id,
expr.range(),
BindingKind::UnpackedAssignment,
BindingFlags::empty(),
);
if parent.is_with_stmt() {
self.add_binding(id, expr.range(), BindingKind::WithItemVar, flags);
return;
}
@@ -1681,7 +1671,6 @@ impl<'a> Checker<'a> {
let (all_names, all_flags) =
extract_all_names(parent, |name| self.semantic.is_builtin(name));
let mut flags = BindingFlags::empty();
if all_flags.intersects(DunderAllFlags::INVALID_OBJECT) {
flags |= BindingFlags::INVALID_ALL_OBJECT;
}
@@ -1705,21 +1694,11 @@ impl<'a> Checker<'a> {
.current_expressions()
.any(Expr::is_named_expr_expr)
{
self.add_binding(
id,
expr.range(),
BindingKind::NamedExprAssignment,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::NamedExprAssignment, flags);
return;
}
self.add_binding(
id,
expr.range(),
BindingKind::Assignment,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::Assignment, flags);
}
fn handle_node_delete(&mut self, expr: &'a Expr) {

View File

@@ -141,7 +141,7 @@ pub(crate) fn check_tokens(
Rule::TrailingCommaOnBareTuple,
Rule::ProhibitedTrailingComma,
]) {
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator);
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator, indexer);
}
if settings.rules.enabled(Rule::ExtraneousParentheses) {

View File

@@ -293,6 +293,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
// flake8-trio
(Flake8Trio, "100") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioTimeoutWithoutAwait),
(Flake8Trio, "105") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioSyncCall),
(Flake8Trio, "109") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioAsyncFunctionWithTimeout),
(Flake8Trio, "110") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioUnneededSleep),
(Flake8Trio, "115") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioZeroSleepCall),
// flake8-builtins
@@ -629,6 +631,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bandit, "609") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnixCommandWildcardInjection),
(Flake8Bandit, "612") => (RuleGroup::Stable, rules::flake8_bandit::rules::LoggingConfigInsecureListen),
(Flake8Bandit, "701") => (RuleGroup::Stable, rules::flake8_bandit::rules::Jinja2AutoescapeFalse),
(Flake8Bandit, "702") => (RuleGroup::Preview, rules::flake8_bandit::rules::MakoTemplates),
// flake8-boolean-trap
(Flake8BooleanTrap, "001") => (RuleGroup::Stable, rules::flake8_boolean_trap::rules::BooleanTypeHintPositionalArgument),

View File

@@ -189,7 +189,7 @@ impl<'a> Insertion<'a> {
Tok::NonLogicalNewline => {}
Tok::Indent => {
// This is like:
// ```py
// ```python
// if True:
// pass
// ```

View File

@@ -132,11 +132,7 @@ impl<'a> Importer<'a> {
)?;
// Import the `TYPE_CHECKING` symbol from the typing module.
let (type_checking_edit, type_checking) = self.get_or_import_symbol(
&ImportRequest::import_from("typing", "TYPE_CHECKING"),
at,
semantic,
)?;
let (type_checking_edit, type_checking) = self.get_or_import_type_checking(at, semantic)?;
// Add the import to a `TYPE_CHECKING` block.
let add_import_edit = if let Some(block) = self.preceding_type_checking_block(at) {
@@ -161,6 +157,30 @@ impl<'a> Importer<'a> {
})
}
/// Generate an [`Edit`] to reference `typing.TYPE_CHECKING`. Returns the [`Edit`] necessary to
/// make the symbol available in the current scope along with the bound name of the symbol.
fn get_or_import_type_checking(
&self,
at: TextSize,
semantic: &SemanticModel,
) -> Result<(Edit, String), ResolutionError> {
for module in semantic.typing_modules() {
if let Some((edit, name)) = self.get_symbol(
&ImportRequest::import_from(module, "TYPE_CHECKING"),
at,
semantic,
)? {
return Ok((edit, name));
}
}
self.import_symbol(
&ImportRequest::import_from("typing", "TYPE_CHECKING"),
at,
semantic,
)
}
/// Generate an [`Edit`] to reference the given symbol. Returns the [`Edit`] necessary to make
/// the symbol available in the current scope along with the bound name of the symbol.
///
@@ -209,7 +229,7 @@ impl<'a> Importer<'a> {
// We also add a no-op edit to force conflicts with any other fixes that might try to
// remove the import. Consider:
//
// ```py
// ```python
// import sys
//
// quit()

View File

@@ -8,7 +8,7 @@ use itertools::Itertools;
use log::error;
use rustc_hash::FxHashMap;
use ruff_diagnostics::{Applicability, Diagnostic};
use ruff_diagnostics::Diagnostic;
use ruff_python_ast::imports::ImportMap;
use ruff_python_ast::PySourceType;
use ruff_python_codegen::Stylist;
@@ -268,24 +268,13 @@ pub fn check_path(
}
// Update fix applicability to account for overrides
if !settings.extend_safe_fixes.is_empty() || !settings.extend_unsafe_fixes.is_empty() {
if !settings.fix_safety.is_empty() {
for diagnostic in &mut diagnostics {
if let Some(fix) = diagnostic.fix.take() {
// Enforce demotions over promotions so if someone puts a rule in both we are conservative
if fix.applicability().is_safe()
&& settings
.extend_unsafe_fixes
.contains(diagnostic.kind.rule())
{
diagnostic.set_fix(fix.with_applicability(Applicability::Unsafe));
} else if fix.applicability().is_unsafe()
&& settings.extend_safe_fixes.contains(diagnostic.kind.rule())
{
diagnostic.set_fix(fix.with_applicability(Applicability::Safe));
} else {
// Retain the existing fix (will be dropped from `.take()` otherwise)
diagnostic.set_fix(fix);
}
let fixed_applicability = settings
.fix_safety
.resolve_applicability(diagnostic.kind.rule(), fix.applicability());
diagnostic.set_fix(fix.with_applicability(fixed_applicability));
}
}
}

View File

@@ -54,9 +54,9 @@ impl Display for Diff<'_> {
let message = match self.fix.applicability() {
// TODO(zanieb): Adjust this messaging once it's user-facing
Applicability::Safe => "Fix",
Applicability::Unsafe => "Suggested fix",
Applicability::Display => "Possible fix",
Applicability::Safe => "Safe fix",
Applicability::Unsafe => "Unsafe fix",
Applicability::DisplayOnly => "Display-only fix",
};
writeln!(f, " {}", message.blue())?;

View File

@@ -245,10 +245,10 @@ impl Renamer {
| BindingKind::Argument
| BindingKind::TypeParam
| BindingKind::NamedExprAssignment
| BindingKind::UnpackedAssignment
| BindingKind::Assignment
| BindingKind::BoundException
| BindingKind::LoopVar
| BindingKind::WithItemVar
| BindingKind::Global
| BindingKind::Nonlocal(_)
| BindingKind::ClassDefinition(_)

View File

@@ -66,7 +66,7 @@ pub(crate) fn commented_out_code(
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
let mut diagnostic = Diagnostic::new(CommentedOutCode, *range);
diagnostic.set_fix(Fix::display_edit(Edit::range_deletion(
diagnostic.set_fix(Fix::display_only_edit(Edit::range_deletion(
locator.full_lines_range(*range),
)));
diagnostics.push(diagnostic);

View File

@@ -10,7 +10,7 @@ ERA001.py:1:1: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
1 |-#import os
2 1 | # from foo import junk
3 2 | #a = 3
@@ -26,7 +26,7 @@ ERA001.py:2:1: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
1 1 | #import os
2 |-# from foo import junk
3 2 | #a = 3
@@ -44,7 +44,7 @@ ERA001.py:3:1: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
1 1 | #import os
2 2 | # from foo import junk
3 |-#a = 3
@@ -63,7 +63,7 @@ ERA001.py:5:1: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
2 2 | # from foo import junk
3 3 | #a = 3
4 4 | a = 4
@@ -82,7 +82,7 @@ ERA001.py:13:5: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
10 10 |
11 11 | # This is a real comment.
12 12 | # # This is a (nested) comment.
@@ -100,7 +100,7 @@ ERA001.py:21:5: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
18 18 |
19 19 | class A():
20 20 | pass
@@ -120,7 +120,7 @@ ERA001.py:26:5: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
23 23 |
24 24 | dictionary = {
25 25 | # "key1": 123, # noqa: ERA001
@@ -139,7 +139,7 @@ ERA001.py:27:5: ERA001 Found commented-out code
|
= help: Remove commented-out code
Possible fix
Display-only fix
24 24 | dictionary = {
25 25 | # "key1": 123, # noqa: ERA001
26 26 | # "key2": 456,

View File

@@ -252,7 +252,7 @@ annotation_presence.py:159:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
156 156 |
157 157 | class Foo:
158 158 | @decorator()
@@ -272,7 +272,7 @@ annotation_presence.py:165:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
162 162 |
163 163 | # Regression test for: https://github.com/astral-sh/ruff/issues/7711
164 164 | class Class:

View File

@@ -11,7 +11,7 @@ mypy_init_return.py:5:9: ANN204 [*] Missing return type annotation for special m
|
= help: Add `None` return type
Suggested fix
Unsafe fix
2 2 |
3 3 | # Error
4 4 | class Foo:
@@ -31,7 +31,7 @@ mypy_init_return.py:11:9: ANN204 [*] Missing return type annotation for special
|
= help: Add `None` return type
Suggested fix
Unsafe fix
8 8 |
9 9 | # Error
10 10 | class Foo:
@@ -59,7 +59,7 @@ mypy_init_return.py:47:9: ANN204 [*] Missing return type annotation for special
|
= help: Add `None` return type
Suggested fix
Unsafe fix
44 44 | # Error used to be ok for a moment since the mere presence
45 45 | # of a vararg falsely indicated that the function has a typed argument.
46 46 | class Foo:

View File

@@ -10,7 +10,7 @@ simple_magic_methods.py:2:9: ANN204 [*] Missing return type annotation for speci
|
= help: Add `None` return type
Suggested fix
Unsafe fix
1 1 | class Foo:
2 |- def __str__(self):
2 |+ def __str__(self) -> str:
@@ -28,7 +28,7 @@ simple_magic_methods.py:5:9: ANN204 [*] Missing return type annotation for speci
|
= help: Add `None` return type
Suggested fix
Unsafe fix
2 2 | def __str__(self):
3 3 | ...
4 4 |
@@ -48,7 +48,7 @@ simple_magic_methods.py:8:9: ANN204 [*] Missing return type annotation for speci
|
= help: Add `None` return type
Suggested fix
Unsafe fix
5 5 | def __repr__(self):
6 6 | ...
7 7 |
@@ -68,7 +68,7 @@ simple_magic_methods.py:11:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
8 8 | def __len__(self):
9 9 | ...
10 10 |
@@ -88,7 +88,7 @@ simple_magic_methods.py:14:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
11 11 | def __length_hint__(self):
12 12 | ...
13 13 |
@@ -108,7 +108,7 @@ simple_magic_methods.py:17:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
14 14 | def __init__(self):
15 15 | ...
16 16 |
@@ -128,7 +128,7 @@ simple_magic_methods.py:20:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
17 17 | def __del__(self):
18 18 | ...
19 19 |
@@ -148,7 +148,7 @@ simple_magic_methods.py:23:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
20 20 | def __bool__(self):
21 21 | ...
22 22 |
@@ -168,7 +168,7 @@ simple_magic_methods.py:26:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
23 23 | def __bytes__(self):
24 24 | ...
25 25 |
@@ -188,7 +188,7 @@ simple_magic_methods.py:29:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
26 26 | def __format__(self, format_spec):
27 27 | ...
28 28 |
@@ -208,7 +208,7 @@ simple_magic_methods.py:32:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
29 29 | def __contains__(self, item):
30 30 | ...
31 31 |
@@ -228,7 +228,7 @@ simple_magic_methods.py:35:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
32 32 | def __complex__(self):
33 33 | ...
34 34 |
@@ -248,7 +248,7 @@ simple_magic_methods.py:38:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
35 35 | def __int__(self):
36 36 | ...
37 37 |
@@ -268,7 +268,7 @@ simple_magic_methods.py:41:9: ANN204 [*] Missing return type annotation for spec
|
= help: Add `None` return type
Suggested fix
Unsafe fix
38 38 | def __float__(self):
39 39 | ...
40 40 |

View File

@@ -28,6 +28,7 @@ mod tests {
#[test_case(Rule::HardcodedTempFile, Path::new("S108.py"))]
#[test_case(Rule::HashlibInsecureHashFunction, Path::new("S324.py"))]
#[test_case(Rule::Jinja2AutoescapeFalse, Path::new("S701.py"))]
#[test_case(Rule::MakoTemplates, Path::new("S702.py"))]
#[test_case(Rule::LoggingConfigInsecureListen, Path::new("S612.py"))]
#[test_case(Rule::ParamikoCall, Path::new("S601.py"))]
#[test_case(Rule::RequestWithNoCertValidation, Path::new("S501.py"))]

View File

@@ -0,0 +1,57 @@
use crate::checkers::ast::Checker;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast};
use ruff_text_size::Ranged;
/// ## What it does
/// Checks for uses of the `mako` templates.
///
/// ## Why is this bad?
/// Mako templates allow HTML and JavaScript rendering by default, and are
/// inherently open to XSS attacks. Ensure variables in all templates are
/// properly sanitized via the `n`, `h` or `x` flags (depending on context).
/// For example, to HTML escape the variable `data`, use `${ data |h }`.
///
/// ## Example
/// ```python
/// from mako.template import Template
///
/// Template("hello")
/// ```
///
/// Use instead:
/// ```python
/// from mako.template import Template
///
/// Template("hello |h")
/// ```
///
/// ## References
/// - [Mako documentation](https://www.makotemplates.org/)
/// - [OpenStack security: Cross site scripting XSS](https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html)
/// - [Common Weakness Enumeration: CWE-80](https://cwe.mitre.org/data/definitions/80.html)
#[violation]
pub struct MakoTemplates;
impl Violation for MakoTemplates {
#[derive_message_formats]
fn message(&self) -> String {
format!(
"Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks"
)
}
}
/// S702
pub(crate) fn mako_templates(checker: &mut Checker, call: &ast::ExprCall) {
if checker
.semantic()
.resolve_call_path(&call.func)
.is_some_and(|call_path| matches!(call_path.as_slice(), ["mako", "template", "Template"]))
{
checker
.diagnostics
.push(Diagnostic::new(MakoTemplates, call.func.range()));
}
}

View File

@@ -11,6 +11,7 @@ pub(crate) use hardcoded_tmp_directory::*;
pub(crate) use hashlib_insecure_hash_functions::*;
pub(crate) use jinja2_autoescape_false::*;
pub(crate) use logging_config_insecure_listen::*;
pub(crate) use mako_templates::*;
pub(crate) use paramiko_calls::*;
pub(crate) use request_with_no_cert_validation::*;
pub(crate) use request_without_timeout::*;
@@ -37,6 +38,7 @@ mod hardcoded_tmp_directory;
mod hashlib_insecure_hash_functions;
mod jinja2_autoescape_false;
mod logging_config_insecure_listen;
mod mako_templates;
mod paramiko_calls;
mod request_with_no_cert_validation;
mod request_without_timeout;

View File

@@ -0,0 +1,28 @@
---
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
---
S702.py:6:1: S702 Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks
|
6 | Template("hello")
| ^^^^^^^^ S702
7 |
8 | mako.template.Template("hern")
|
S702.py:8:1: S702 Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks
|
6 | Template("hello")
7 |
8 | mako.template.Template("hern")
| ^^^^^^^^^^^^^^^^^^^^^^ S702
9 | template.Template("hern")
|
S702.py:9:1: S702 Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks
|
8 | mako.template.Template("hern")
9 | template.Template("hern")
| ^^^^^^^^^^^^^^^^^ S702
|

View File

@@ -12,7 +12,7 @@ B004.py:3:8: B004 [*] Using `hasattr(x, "__call__")` to test if x is callable is
|
= help: Replace with `callable()`
Fix
Safe fix
1 1 | def this_is_a_bug():
2 2 | o = object()
3 |- if hasattr(o, "__call__"):

View File

@@ -12,7 +12,7 @@ B006_1.py:3:22: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
1 1 | # Docstring followed by a newline
2 2 |
3 |-def foobar(foor, bar={}):

View File

@@ -12,7 +12,7 @@ B006_2.py:4:22: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
1 1 | # Docstring followed by whitespace with no newline
2 2 | # Regression test for https://github.com/astral-sh/ruff/issues/7155
3 3 |

View File

@@ -10,7 +10,7 @@ B006_3.py:4:22: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
1 1 | # Docstring with no newline
2 2 |
3 3 |

View File

@@ -10,7 +10,7 @@ B006_4.py:7:26: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
4 4 |
5 5 |
6 6 | class FormFeedIndent:

View File

@@ -9,7 +9,7 @@ B006_5.py:5:49: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
2 2 | # https://github.com/astral-sh/ruff/issues/7616
3 3 |
4 4 |
@@ -30,7 +30,7 @@ B006_5.py:9:61: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
6 6 | import os
7 7 |
8 8 |
@@ -53,7 +53,7 @@ B006_5.py:15:50: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
12 12 | return 2
13 13 |
14 14 |
@@ -76,7 +76,7 @@ B006_5.py:21:54: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
18 18 | import itertools
19 19 |
20 20 |
@@ -98,7 +98,7 @@ B006_5.py:25:55: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
22 22 | from os import path
23 23 |
24 24 |
@@ -121,7 +121,7 @@ B006_5.py:30:66: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
27 27 | from sys import version_info
28 28 |
29 29 |
@@ -144,7 +144,7 @@ B006_5.py:35:59: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
32 32 | from sys import version_info
33 33 |
34 34 |
@@ -167,7 +167,7 @@ B006_5.py:40:49: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
37 37 | import os
38 38 |
39 39 |
@@ -190,7 +190,7 @@ B006_5.py:45:49: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
42 42 | import os; import sys
43 43 |
44 44 |
@@ -212,7 +212,7 @@ B006_5.py:50:49: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
47 47 | import os; import sys; x = 1
48 48 |
49 49 |
@@ -234,7 +234,7 @@ B006_5.py:55:49: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
52 52 | import os; import sys
53 53 |
54 54 |
@@ -255,7 +255,7 @@ B006_5.py:59:49: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
56 56 | import os; import sys
57 57 |
58 58 |
@@ -275,7 +275,7 @@ B006_5.py:63:49: B006 [*] Do not use mutable data structures for argument defaul
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
60 60 | import os; import sys; x = 1
61 61 |
62 62 |

View File

@@ -11,7 +11,7 @@ B006_6.py:4:22: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
1 1 | # Import followed by whitespace with no newline
2 2 | # Same as B006_2.py, but import instead of docstring
3 3 |

View File

@@ -11,7 +11,7 @@ B006_7.py:4:22: B006 [*] Do not use mutable data structures for argument default
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
1 1 | # Import with no newline
2 2 | # Same as B006_3.py, but import instead of docstring
3 3 |

View File

@@ -9,7 +9,7 @@ B006_B008.py:63:25: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
60 60 | # Flag mutable literals/comprehensions
61 61 |
62 62 |
@@ -29,7 +29,7 @@ B006_B008.py:67:30: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
64 64 | ...
65 65 |
66 66 |
@@ -51,7 +51,7 @@ B006_B008.py:73:52: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
70 70 |
71 71 | class Foo:
72 72 | @staticmethod
@@ -74,7 +74,7 @@ B006_B008.py:77:31: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
74 74 | pass
75 75 |
76 76 |
@@ -105,7 +105,7 @@ B006_B008.py:85:20: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
82 82 | def single_line_func_wrong(value = {}): ...
83 83 |
84 84 |
@@ -125,7 +125,7 @@ B006_B008.py:89:20: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
86 86 | ...
87 87 |
88 88 |
@@ -145,7 +145,7 @@ B006_B008.py:93:32: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
90 90 | ...
91 91 |
92 92 |
@@ -165,7 +165,7 @@ B006_B008.py:97:26: B006 [*] Do not use mutable data structures for argument def
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
94 94 | ...
95 95 |
96 96 |
@@ -186,7 +186,7 @@ B006_B008.py:102:46: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
99 99 |
100 100 |
101 101 | # N.B. we're also flagging the function call in the comprehension
@@ -206,7 +206,7 @@ B006_B008.py:106:46: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
103 103 | pass
104 104 |
105 105 |
@@ -226,7 +226,7 @@ B006_B008.py:110:45: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
107 107 | pass
108 108 |
109 109 |
@@ -246,7 +246,7 @@ B006_B008.py:114:33: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
111 111 | pass
112 112 |
113 113 |
@@ -268,7 +268,7 @@ B006_B008.py:239:20: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
236 236 |
237 237 | # B006 and B008
238 238 | # We should handle arbitrary nesting of these B008.
@@ -290,7 +290,7 @@ B006_B008.py:276:27: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
273 273 |
274 274 |
275 275 | def mutable_annotations(
@@ -317,7 +317,7 @@ B006_B008.py:277:35: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
274 274 |
275 275 | def mutable_annotations(
276 276 | a: list[int] | None = [],
@@ -343,7 +343,7 @@ B006_B008.py:278:62: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
275 275 | def mutable_annotations(
276 276 | a: list[int] | None = [],
277 277 | b: Optional[Dict[int, int]] = {},
@@ -368,7 +368,7 @@ B006_B008.py:279:80: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
276 276 | a: list[int] | None = [],
277 277 | b: Optional[Dict[int, int]] = {},
278 278 | c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
@@ -389,7 +389,7 @@ B006_B008.py:284:52: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
281 281 | pass
282 282 |
283 283 |
@@ -411,7 +411,7 @@ B006_B008.py:288:52: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
285 285 | """Docstring"""
286 286 |
287 287 |
@@ -432,7 +432,7 @@ B006_B008.py:293:52: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
290 290 | ...
291 291 |
292 292 |
@@ -453,7 +453,7 @@ B006_B008.py:297:52: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
294 294 | """Docstring"""; ...
295 295 |
296 296 |
@@ -476,7 +476,7 @@ B006_B008.py:302:52: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
299 299 | ...
300 300 |
301 301 |
@@ -508,7 +508,7 @@ B006_B008.py:313:52: B006 [*] Do not use mutable data structures for argument de
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
310 310 | """Docstring"""
311 311 |
312 312 |

View File

@@ -21,7 +21,7 @@ B007.py:18:13: B007 [*] Loop control variable `k` not used within loop body
|
= help: Rename unused `k` to `_k`
Suggested fix
Unsafe fix
15 15 |
16 16 | for i in range(10):
17 17 | for j in range(10):
@@ -47,7 +47,7 @@ B007.py:30:13: B007 [*] Loop control variable `k` not used within loop body
|
= help: Rename unused `k` to `_k`
Suggested fix
Unsafe fix
27 27 | yield i, (j, (k, l))
28 28 |
29 29 |
@@ -110,7 +110,7 @@ B007.py:52:14: B007 [*] Loop control variable `bar` not used within loop body
|
= help: Rename unused `bar` to `_bar`
Suggested fix
Unsafe fix
49 49 |
50 50 | def f():
51 51 | # Fixable.
@@ -142,7 +142,7 @@ B007.py:68:14: B007 [*] Loop control variable `bar` not used within loop body
|
= help: Rename unused `bar` to `_bar`
Suggested fix
Unsafe fix
65 65 |
66 66 | def f():
67 67 | # Fixable.

View File

@@ -11,7 +11,7 @@ B009_B010.py:19:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
16 16 | getattr(foo, "__123abc")
17 17 |
18 18 | # Invalid usage
@@ -32,7 +32,7 @@ B009_B010.py:20:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
17 17 |
18 18 | # Invalid usage
19 19 | getattr(foo, "bar")
@@ -53,7 +53,7 @@ B009_B010.py:21:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
18 18 | # Invalid usage
19 19 | getattr(foo, "bar")
20 20 | getattr(foo, "_123abc")
@@ -74,7 +74,7 @@ B009_B010.py:22:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
19 19 | getattr(foo, "bar")
20 20 | getattr(foo, "_123abc")
21 21 | getattr(foo, "__123abc__")
@@ -95,7 +95,7 @@ B009_B010.py:23:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
20 20 | getattr(foo, "_123abc")
21 21 | getattr(foo, "__123abc__")
22 22 | getattr(foo, "abc123")
@@ -116,7 +116,7 @@ B009_B010.py:24:15: B009 [*] Do not call `getattr` with a constant attribute val
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
21 21 | getattr(foo, "__123abc__")
22 22 | getattr(foo, "abc123")
23 23 | getattr(foo, r"abc123")
@@ -137,7 +137,7 @@ B009_B010.py:25:4: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
22 22 | getattr(foo, "abc123")
23 23 | getattr(foo, r"abc123")
24 24 | _ = lambda x: getattr(x, "bar")
@@ -158,7 +158,7 @@ B009_B010.py:27:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
24 24 | _ = lambda x: getattr(x, "bar")
25 25 | if getattr(x, "bar"):
26 26 | pass
@@ -179,7 +179,7 @@ B009_B010.py:28:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
25 25 | if getattr(x, "bar"):
26 26 | pass
27 27 | getattr(1, "real")
@@ -200,7 +200,7 @@ B009_B010.py:29:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
26 26 | pass
27 27 | getattr(1, "real")
28 28 | getattr(1., "real")
@@ -221,7 +221,7 @@ B009_B010.py:30:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
27 27 | getattr(1, "real")
28 28 | getattr(1., "real")
29 29 | getattr(1.0, "real")
@@ -242,7 +242,7 @@ B009_B010.py:31:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
28 28 | getattr(1., "real")
29 29 | getattr(1.0, "real")
30 30 | getattr(1j, "real")
@@ -263,7 +263,7 @@ B009_B010.py:32:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
29 29 | getattr(1.0, "real")
30 30 | getattr(1j, "real")
31 31 | getattr(True, "real")
@@ -284,7 +284,7 @@ B009_B010.py:33:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
30 30 | getattr(1j, "real")
31 31 | getattr(True, "real")
32 32 | getattr(x := 1, "real")
@@ -304,7 +304,7 @@ B009_B010.py:34:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
31 31 | getattr(True, "real")
32 32 | getattr(x := 1, "real")
33 33 | getattr(x + y, "real")
@@ -326,7 +326,7 @@ B009_B010.py:58:8: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
55 55 | setattr(foo.bar, r"baz", None)
56 56 |
57 57 | # Regression test for: https://github.com/astral-sh/ruff/issues/7455#issuecomment-1722458885
@@ -345,7 +345,7 @@ B009_B010.py:65:1: B009 [*] Do not call `getattr` with a constant attribute valu
|
= help: Replace `getattr` with attribute access
Fix
Safe fix
62 62 | setattr(*foo, "bar", None)
63 63 |
64 64 | # Regression test for: https://github.com/astral-sh/ruff/issues/7455#issuecomment-1739800901

View File

@@ -11,7 +11,7 @@ B009_B010.py:50:1: B010 [*] Do not call `setattr` with a constant attribute valu
|
= help: Replace `setattr` with assignment
Fix
Safe fix
47 47 | pass
48 48 |
49 49 | # Invalid usage
@@ -32,7 +32,7 @@ B009_B010.py:51:1: B010 [*] Do not call `setattr` with a constant attribute valu
|
= help: Replace `setattr` with assignment
Fix
Safe fix
48 48 |
49 49 | # Invalid usage
50 50 | setattr(foo, "bar", None)
@@ -53,7 +53,7 @@ B009_B010.py:52:1: B010 [*] Do not call `setattr` with a constant attribute valu
|
= help: Replace `setattr` with assignment
Fix
Safe fix
49 49 | # Invalid usage
50 50 | setattr(foo, "bar", None)
51 51 | setattr(foo, "_123abc", None)
@@ -74,7 +74,7 @@ B009_B010.py:53:1: B010 [*] Do not call `setattr` with a constant attribute valu
|
= help: Replace `setattr` with assignment
Fix
Safe fix
50 50 | setattr(foo, "bar", None)
51 51 | setattr(foo, "_123abc", None)
52 52 | setattr(foo, "__123abc__", None)
@@ -94,7 +94,7 @@ B009_B010.py:54:1: B010 [*] Do not call `setattr` with a constant attribute valu
|
= help: Replace `setattr` with assignment
Fix
Safe fix
51 51 | setattr(foo, "_123abc", None)
52 52 | setattr(foo, "__123abc__", None)
53 53 | setattr(foo, "abc123", None)
@@ -115,7 +115,7 @@ B009_B010.py:55:1: B010 [*] Do not call `setattr` with a constant attribute valu
|
= help: Replace `setattr` with assignment
Fix
Safe fix
52 52 | setattr(foo, "__123abc__", None)
53 53 | setattr(foo, "abc123", None)
54 54 | setattr(foo, r"abc123", None)

View File

@@ -11,7 +11,7 @@ B011.py:8:8: B011 [*] Do not `assert False` (`python -O` removes these calls), r
|
= help: Replace `assert False`
Suggested fix
Unsafe fix
5 5 | """
6 6 |
7 7 | assert 1 != 2
@@ -29,7 +29,7 @@ B011.py:10:8: B011 [*] Do not `assert False` (`python -O` removes these calls),
|
= help: Replace `assert False`
Suggested fix
Unsafe fix
7 7 | assert 1 != 2
8 8 | assert False
9 9 | assert 1 != 2, "message"

View File

@@ -12,7 +12,7 @@ B013.py:5:8: B013 [*] A length-one tuple literal is redundant in exception handl
|
= help: Replace with `except ValueError`
Fix
Safe fix
2 2 |
3 3 | try:
4 4 | pass
@@ -33,7 +33,7 @@ B013.py:11:8: B013 [*] A length-one tuple literal is redundant in exception hand
|
= help: Replace with `except retriable_exceptions`
Fix
Safe fix
8 8 | pass
9 9 | except (ImportError, TypeError):
10 10 | pass
@@ -53,7 +53,7 @@ B013.py:13:7: B013 [*] A length-one tuple literal is redundant in exception hand
|
= help: Replace with `except ValueError`
Fix
Safe fix
10 10 | pass
11 11 | except (*retriable_exceptions,):
12 12 | pass

View File

@@ -12,7 +12,7 @@ B014.py:17:8: B014 [*] Exception handler with duplicate exception: `OSError`
|
= help: De-duplicate exceptions
Fix
Safe fix
14 14 |
15 15 | try:
16 16 | pass
@@ -33,7 +33,7 @@ B014.py:28:8: B014 [*] Exception handler with duplicate exception: `MyError`
|
= help: De-duplicate exceptions
Fix
Safe fix
25 25 |
26 26 | try:
27 27 | pass
@@ -54,7 +54,7 @@ B014.py:49:8: B014 [*] Exception handler with duplicate exception: `re.error`
|
= help: De-duplicate exceptions
Fix
Safe fix
46 46 |
47 47 | try:
48 48 | pass
@@ -74,7 +74,7 @@ B014.py:82:8: B014 [*] Exception handler with duplicate exception: `ValueError`
|
= help: De-duplicate exceptions
Fix
Safe fix
79 79 | # Regression test for: https://github.com/astral-sh/ruff/issues/6412
80 80 | try:
81 81 | pass
@@ -94,7 +94,7 @@ B014.py:89:7: B014 [*] Exception handler with duplicate exception: `re.error`
|
= help: De-duplicate exceptions
Fix
Safe fix
86 86 | # Regression test for: https://github.com/astral-sh/ruff/issues/7455#issuecomment-1739801758
87 87 | try:
88 88 | pas

View File

@@ -9,7 +9,7 @@ B006_extended.py:17:55: B006 [*] Do not use mutable data structures for argument
|
= help: Replace with `None`; initialize within function
Suggested fix
Unsafe fix
14 14 | ...
15 15 |
16 16 |

View File

@@ -3,6 +3,7 @@ use itertools::Itertools;
use ruff_diagnostics::{AlwaysFixableViolation, Violation};
use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_index::Indexer;
use ruff_python_parser::lexer::{LexResult, Spanned};
use ruff_python_parser::Tok;
use ruff_source_file::Locator;
@@ -29,22 +30,33 @@ enum TokenType {
/// Simplified token specialized for the task.
#[derive(Copy, Clone)]
struct Token<'tok> {
type_: TokenType,
// Underlying token.
spanned: Option<&'tok Spanned>,
struct Token {
r#type: TokenType,
range: TextRange,
}
impl<'tok> Token<'tok> {
const fn irrelevant() -> Token<'static> {
Token {
type_: TokenType::Irrelevant,
spanned: None,
}
impl Ranged for Token {
fn range(&self) -> TextRange {
self.range
}
}
impl Token {
fn new(r#type: TokenType, range: TextRange) -> Self {
Self { r#type, range }
}
const fn from_spanned(spanned: &'tok Spanned) -> Token<'tok> {
let type_ = match &spanned.0 {
fn irrelevant() -> Token {
Token {
r#type: TokenType::Irrelevant,
range: TextRange::default(),
}
}
}
impl From<&Spanned> for Token {
fn from(spanned: &Spanned) -> Self {
let r#type = match &spanned.0 {
Tok::NonLogicalNewline => TokenType::NonLogicalNewline,
Tok::Newline => TokenType::Newline,
Tok::For => TokenType::For,
@@ -63,8 +75,8 @@ impl<'tok> Token<'tok> {
_ => TokenType::Irrelevant,
};
Self {
spanned: Some(spanned),
type_,
range: spanned.1,
r#type,
}
}
}
@@ -92,14 +104,14 @@ enum ContextType {
/// Comma context - described a comma-delimited "situation".
#[derive(Copy, Clone)]
struct Context {
type_: ContextType,
r#type: ContextType,
num_commas: u32,
}
impl Context {
const fn new(type_: ContextType) -> Self {
const fn new(r#type: ContextType) -> Self {
Self {
type_,
r#type,
num_commas: 0,
}
}
@@ -222,21 +234,49 @@ pub(crate) fn trailing_commas(
diagnostics: &mut Vec<Diagnostic>,
tokens: &[LexResult],
locator: &Locator,
indexer: &Indexer,
) {
let mut fstrings = 0u32;
let tokens = tokens
.iter()
.flatten()
// Completely ignore comments -- they just interfere with the logic.
.filter(|&r| !matches!(r, (Tok::Comment(_), _)))
.map(Token::from_spanned);
.filter_map(|spanned @ (tok, tok_range)| match tok {
// Completely ignore comments -- they just interfere with the logic.
Tok::Comment(_) => None,
// F-strings are handled as `String` token type with the complete range
// of the outermost f-string. This means that the expression inside the
// f-string is not checked for trailing commas.
Tok::FStringStart => {
fstrings = fstrings.saturating_add(1);
None
}
Tok::FStringEnd => {
fstrings = fstrings.saturating_sub(1);
if fstrings == 0 {
indexer
.fstring_ranges()
.outermost(tok_range.start())
.map(|range| Token::new(TokenType::String, range))
} else {
None
}
}
_ => {
if fstrings == 0 {
Some(Token::from(spanned))
} else {
None
}
}
});
let tokens = [Token::irrelevant(), Token::irrelevant()]
.into_iter()
.chain(tokens);
// Collapse consecutive newlines to the first one -- trailing commas are
// added before the first newline.
let tokens = tokens.coalesce(|previous, current| {
if previous.type_ == TokenType::NonLogicalNewline
&& current.type_ == TokenType::NonLogicalNewline
if previous.r#type == TokenType::NonLogicalNewline
&& current.r#type == TokenType::NonLogicalNewline
{
Ok(previous)
} else {
@@ -249,8 +289,8 @@ pub(crate) fn trailing_commas(
for (prev_prev, prev, token) in tokens.tuple_windows() {
// Update the comma context stack.
match token.type_ {
TokenType::OpeningBracket => match (prev.type_, prev_prev.type_) {
match token.r#type {
TokenType::OpeningBracket => match (prev.r#type, prev_prev.r#type) {
(TokenType::Named, TokenType::Def) => {
stack.push(Context::new(ContextType::FunctionParameters));
}
@@ -261,7 +301,7 @@ pub(crate) fn trailing_commas(
stack.push(Context::new(ContextType::Tuple));
}
},
TokenType::OpeningSquareBracket => match prev.type_ {
TokenType::OpeningSquareBracket => match prev.r#type {
TokenType::ClosingBracket | TokenType::Named | TokenType::String => {
stack.push(Context::new(ContextType::Subscript));
}
@@ -288,8 +328,8 @@ pub(crate) fn trailing_commas(
let context = &stack[stack.len() - 1];
// Is it allowed to have a trailing comma before this token?
let comma_allowed = token.type_ == TokenType::ClosingBracket
&& match context.type_ {
let comma_allowed = token.r#type == TokenType::ClosingBracket
&& match context.r#type {
ContextType::No => false,
ContextType::FunctionParameters => true,
ContextType::CallArguments => true,
@@ -304,22 +344,21 @@ pub(crate) fn trailing_commas(
};
// Is prev a prohibited trailing comma?
let comma_prohibited = prev.type_ == TokenType::Comma && {
let comma_prohibited = prev.r#type == TokenType::Comma && {
// Is `(1,)` or `x[1,]`?
let is_singleton_tuplish =
matches!(context.type_, ContextType::Subscript | ContextType::Tuple)
matches!(context.r#type, ContextType::Subscript | ContextType::Tuple)
&& context.num_commas <= 1;
// There was no non-logical newline, so prohibit (except in `(1,)` or `x[1,]`).
if comma_allowed && !is_singleton_tuplish {
true
// Lambdas not handled by comma_allowed so handle it specially.
} else {
context.type_ == ContextType::LambdaParameters && token.type_ == TokenType::Colon
context.r#type == ContextType::LambdaParameters && token.r#type == TokenType::Colon
}
};
if comma_prohibited {
let comma = prev.spanned.unwrap();
let mut diagnostic = Diagnostic::new(ProhibitedTrailingComma, comma.1);
let mut diagnostic = Diagnostic::new(ProhibitedTrailingComma, prev.range());
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(diagnostic.range())));
diagnostics.push(diagnostic);
}
@@ -327,10 +366,9 @@ pub(crate) fn trailing_commas(
// Is prev a prohibited trailing comma on a bare tuple?
// Approximation: any comma followed by a statement-ending newline.
let bare_comma_prohibited =
prev.type_ == TokenType::Comma && token.type_ == TokenType::Newline;
prev.r#type == TokenType::Comma && token.r#type == TokenType::Newline;
if bare_comma_prohibited {
let comma = prev.spanned.unwrap();
diagnostics.push(Diagnostic::new(TrailingCommaOnBareTuple, comma.1));
diagnostics.push(Diagnostic::new(TrailingCommaOnBareTuple, prev.range()));
}
// Comma is required if:
@@ -339,40 +377,37 @@ pub(crate) fn trailing_commas(
// - Not already present,
// - Not on an empty (), {}, [].
let comma_required = comma_allowed
&& prev.type_ == TokenType::NonLogicalNewline
&& prev.r#type == TokenType::NonLogicalNewline
&& !matches!(
prev_prev.type_,
prev_prev.r#type,
TokenType::Comma
| TokenType::OpeningBracket
| TokenType::OpeningSquareBracket
| TokenType::OpeningCurlyBracket
);
if comma_required {
let missing_comma = prev_prev.spanned.unwrap();
let mut diagnostic = Diagnostic::new(
MissingTrailingComma,
TextRange::empty(missing_comma.1.end()),
);
let mut diagnostic =
Diagnostic::new(MissingTrailingComma, TextRange::empty(prev_prev.end()));
// Create a replacement that includes the final bracket (or other token),
// rather than just inserting a comma at the end. This prevents the UP034 fix
// removing any brackets in the same linter pass - doing both at the same time could
// lead to a syntax error.
let contents = locator.slice(missing_comma.1);
let contents = locator.slice(prev_prev.range());
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format!("{contents},"),
missing_comma.1,
prev_prev.range(),
)));
diagnostics.push(diagnostic);
}
// Pop the current context if the current token ended it.
// The top context is never popped (if unbalanced closing brackets).
let pop_context = match context.type_ {
let pop_context = match context.r#type {
// Lambda terminated by `:`.
ContextType::LambdaParameters => token.type_ == TokenType::Colon,
ContextType::LambdaParameters => token.r#type == TokenType::Colon,
// All others terminated by a closing bracket.
// flake8-commas doesn't verify that it matches the opening...
_ => token.type_ == TokenType::ClosingBracket,
_ => token.r#type == TokenType::ClosingBracket,
};
if pop_context && stack.len() > 1 {
stack.pop();

View File

@@ -12,7 +12,7 @@ COM81.py:4:18: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
1 1 | # ==> bad_function_call.py <==
2 2 | bad_function_call(
3 3 | param1='test',
@@ -32,7 +32,7 @@ COM81.py:10:6: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
7 7 | bad_list = [
8 8 | 1,
9 9 | 2,
@@ -53,7 +53,7 @@ COM81.py:16:6: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
13 13 | bad_list_with_comment = [
14 14 | 1,
15 15 | 2,
@@ -72,7 +72,7 @@ COM81.py:23:6: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
20 20 | bad_list_with_extra_empty = [
21 21 | 1,
22 22 | 2,
@@ -159,7 +159,7 @@ COM81.py:70:8: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
67 67 | pass
68 68 |
69 69 | {'foo': foo}['foo'](
@@ -178,7 +178,7 @@ COM81.py:78:8: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
75 75 | )
76 76 |
77 77 | (foo)(
@@ -197,7 +197,7 @@ COM81.py:86:8: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
83 83 | )
84 84 |
85 85 | [foo][0](
@@ -217,7 +217,7 @@ COM81.py:152:6: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
149 149 |
150 150 | # ==> keyword_before_parenth_form/base_bad.py <==
151 151 | from x import (
@@ -237,7 +237,7 @@ COM81.py:158:11: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
155 155 | assert(
156 156 | SyntaxWarning,
157 157 | ThrownHere,
@@ -258,7 +258,7 @@ COM81.py:293:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
290 290 |
291 291 | # ==> multiline_bad_dict.py <==
292 292 | multiline_bad_dict = {
@@ -279,7 +279,7 @@ COM81.py:304:14: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
301 301 |
302 302 | def func_bad(
303 303 | a = 3,
@@ -300,7 +300,7 @@ COM81.py:310:14: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
307 307 |
308 308 | # ==> multiline_bad_function_one_param.py <==
309 309 | def func(
@@ -319,7 +319,7 @@ COM81.py:316:10: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
313 313 |
314 314 |
315 315 | func(
@@ -339,7 +339,7 @@ COM81.py:322:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
319 319 | # ==> multiline_bad_or_dict.py <==
320 320 | multiline_bad_or_dict = {
321 321 | "good": True or False,
@@ -359,7 +359,7 @@ COM81.py:368:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
365 365 |
366 366 | multiline_index_access[
367 367 | "probably fine",
@@ -379,7 +379,7 @@ COM81.py:375:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
372 372 | "fine",
373 373 | "fine",
374 374 | :
@@ -399,7 +399,7 @@ COM81.py:404:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
401 401 | "fine",
402 402 | "fine"
403 403 | :
@@ -419,7 +419,7 @@ COM81.py:432:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
429 429 | "fine"
430 430 | :
431 431 | "fine",
@@ -439,7 +439,7 @@ COM81.py:485:21: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
482 482 | )
483 483 |
484 484 | # ==> prohibited.py <==
@@ -460,7 +460,7 @@ COM81.py:487:13: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
484 484 | # ==> prohibited.py <==
485 485 | foo = ['a', 'b', 'c',]
486 486 |
@@ -480,7 +480,7 @@ COM81.py:489:18: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
486 486 |
487 487 | bar = { a: b,}
488 488 |
@@ -501,7 +501,7 @@ COM81.py:494:6: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
491 491 |
492 492 | (0,)
493 493 |
@@ -522,7 +522,7 @@ COM81.py:496:21: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
493 493 |
494 494 | (0, 1,)
495 495 |
@@ -543,7 +543,7 @@ COM81.py:498:13: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
495 495 |
496 496 | foo = ['a', 'b', 'c', ]
497 497 |
@@ -563,7 +563,7 @@ COM81.py:500:18: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
497 497 |
498 498 | bar = { a: b, }
499 499 |
@@ -584,7 +584,7 @@ COM81.py:505:6: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
502 502 |
503 503 | (0, )
504 504 |
@@ -605,7 +605,7 @@ COM81.py:511:10: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
508 508 |
509 509 | image[:,]
510 510 |
@@ -626,7 +626,7 @@ COM81.py:513:9: COM819 [*] Trailing comma prohibited
|
= help: Remove trailing comma
Fix
Safe fix
510 510 |
511 511 | image[:,:,]
512 512 |
@@ -647,7 +647,7 @@ COM81.py:519:13: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
516 516 | def function(
517 517 | foo,
518 518 | bar,
@@ -668,7 +668,7 @@ COM81.py:526:10: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
523 523 | def function(
524 524 | foo,
525 525 | bar,
@@ -689,7 +689,7 @@ COM81.py:534:16: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
531 531 | foo,
532 532 | bar,
533 533 | *args,
@@ -709,7 +709,7 @@ COM81.py:541:13: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
538 538 | result = function(
539 539 | foo,
540 540 | bar,
@@ -729,7 +729,7 @@ COM81.py:547:24: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
544 544 | result = function(
545 545 | foo,
546 546 | bar,
@@ -750,7 +750,7 @@ COM81.py:554:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
551 551 | ham,
552 552 | spam,
553 553 | *args,
@@ -769,7 +769,7 @@ COM81.py:561:13: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
558 558 | # In python 3.5 if it's not a function def, commas are mandatory.
559 559 |
560 560 | foo(
@@ -788,7 +788,7 @@ COM81.py:565:13: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
562 562 | )
563 563 |
564 564 | {
@@ -807,7 +807,7 @@ COM81.py:573:10: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
570 570 | )
571 571 |
572 572 | {
@@ -826,7 +826,7 @@ COM81.py:577:10: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
574 574 | }
575 575 |
576 576 | [
@@ -847,7 +847,7 @@ COM81.py:583:10: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
580 580 | def foo(
581 581 | ham,
582 582 | spam,
@@ -868,7 +868,7 @@ COM81.py:590:13: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
587 587 | def foo(
588 588 | ham,
589 589 | spam,
@@ -889,7 +889,7 @@ COM81.py:598:15: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
595 595 | ham,
596 596 | spam,
597 597 | *args,
@@ -909,7 +909,7 @@ COM81.py:627:20: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
624 624 | result = function(
625 625 | foo,
626 626 | bar,
@@ -929,7 +929,7 @@ COM81.py:632:42: COM812 [*] Trailing comma missing
|
= help: Add trailing comma
Fix
Safe fix
629 629 |
630 630 | # Make sure the COM812 and UP034 rules don't fix simultaneously and cause a syntax error.
631 631 | the_first_one = next(
@@ -939,4 +939,43 @@ COM81.py:632:42: COM812 [*] Trailing comma missing
634 634 |
635 635 | foo = namedtuple(
COM81.py:644:46: COM819 [*] Trailing comma prohibited
|
643 | # F-strings
644 | kwargs.pop("remove", f"this {trailing_comma}",)
| ^ COM819
645 |
646 | raise Exception(
|
= help: Remove trailing comma
Safe fix
641 641 | )
642 642 |
643 643 | # F-strings
644 |-kwargs.pop("remove", f"this {trailing_comma}",)
644 |+kwargs.pop("remove", f"this {trailing_comma}")
645 645 |
646 646 | raise Exception(
647 647 | "first", extra=f"Add trailing comma here ->"
COM81.py:647:49: COM812 [*] Trailing comma missing
|
646 | raise Exception(
647 | "first", extra=f"Add trailing comma here ->"
| COM812
648 | )
|
= help: Add trailing comma
Safe fix
644 644 | kwargs.pop("remove", f"this {trailing_comma}",)
645 645 |
646 646 | raise Exception(
647 |- "first", extra=f"Add trailing comma here ->"
647 |+ "first", extra=f"Add trailing comma here ->",
648 648 | )
649 649 |
650 650 | assert False, f"<- This is not a trailing comma"

View File

@@ -10,7 +10,7 @@ C400.py:1:5: C400 [*] Unnecessary generator (rewrite as a `list` comprehension)
|
= help: Rewrite as a `list` comprehension
Suggested fix
Unsafe fix
1 |-x = list(x for x in range(3))
1 |+x = [x for x in range(3)]
2 2 | x = list(
@@ -28,7 +28,7 @@ C400.py:2:5: C400 [*] Unnecessary generator (rewrite as a `list` comprehension)
|
= help: Rewrite as a `list` comprehension
Suggested fix
Unsafe fix
1 1 | x = list(x for x in range(3))
2 |-x = list(
2 |+x = [

View File

@@ -10,7 +10,7 @@ C401.py:1:5: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
1 |-x = set(x for x in range(3))
1 |+x = {x for x in range(3)}
2 2 | x = set(x for x in range(3))
@@ -27,7 +27,7 @@ C401.py:2:5: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
1 1 | x = set(x for x in range(3))
2 |-x = set(x for x in range(3))
2 |+x = {x for x in range(3)}
@@ -46,7 +46,7 @@ C401.py:3:8: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
1 1 | x = set(x for x in range(3))
2 2 | x = set(x for x in range(3))
3 |-y = f"{set(a if a < 6 else 0 for a in range(3))}"
@@ -65,7 +65,7 @@ C401.py:4:17: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
1 1 | x = set(x for x in range(3))
2 2 | x = set(x for x in range(3))
3 3 | y = f"{set(a if a < 6 else 0 for a in range(3))}"
@@ -84,7 +84,7 @@ C401.py:5:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
2 2 | x = set(x for x in range(3))
3 3 | y = f"{set(a if a < 6 else 0 for a in range(3))}"
4 4 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3)))
@@ -103,7 +103,7 @@ C401.py:12:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
9 9 | return x
10 10 |
11 11 |
@@ -123,7 +123,7 @@ C401.py:13:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
10 10 |
11 11 |
12 12 | print(f'Hello {set(a for a in "abc")} World')
@@ -144,7 +144,7 @@ C401.py:14:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
11 11 |
12 12 | print(f'Hello {set(a for a in "abc")} World')
13 13 | print(f"Hello {set(a for a in 'abc')} World")
@@ -164,7 +164,7 @@ C401.py:15:10: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
12 12 | print(f'Hello {set(a for a in "abc")} World')
13 13 | print(f"Hello {set(a for a in 'abc')} World")
14 14 | print(f"Hello {set(f(a) for a in 'abc')} World")
@@ -184,7 +184,7 @@ C401.py:15:34: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
12 12 | print(f'Hello {set(a for a in "abc")} World')
13 13 | print(f"Hello {set(a for a in 'abc')} World")
14 14 | print(f"Hello {set(f(a) for a in 'abc')} World")
@@ -205,7 +205,7 @@ C401.py:16:11: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
13 13 | print(f"Hello {set(a for a in 'abc')} World")
14 14 | print(f"Hello {set(f(a) for a in 'abc')} World")
15 15 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}")
@@ -226,7 +226,7 @@ C401.py:16:35: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
13 13 | print(f"Hello {set(a for a in 'abc')} World")
14 14 | print(f"Hello {set(f(a) for a in 'abc')} World")
15 15 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}")
@@ -245,7 +245,7 @@ C401.py:20:12: C401 [*] Unnecessary generator (rewrite as a `set` comprehension)
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
17 17 |
18 18 | # The fix generated for this diagnostic is incorrect, as we add additional space
19 19 | # around the set comprehension.

View File

@@ -10,7 +10,7 @@ C402.py:1:1: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
1 |-dict((x, x) for x in range(3))
1 |+{x: x for x in range(3)}
2 2 | dict(
@@ -29,7 +29,7 @@ C402.py:2:1: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
1 1 | dict((x, x) for x in range(3))
2 |-dict(
3 |- (x, x) for x in range(3)
@@ -52,7 +52,7 @@ C402.py:6:8: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
3 3 | (x, x) for x in range(3)
4 4 | )
5 5 | dict(((x, x) for x in range(3)), z=3)
@@ -73,7 +73,7 @@ C402.py:7:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
4 4 | )
5 5 | dict(((x, x) for x in range(3)), z=3)
6 6 | y = f'{dict((x, x) for x in range(3))}'
@@ -94,7 +94,7 @@ C402.py:8:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
5 5 | dict(((x, x) for x in range(3)), z=3)
6 6 | y = f'{dict((x, x) for x in range(3))}'
7 7 | print(f'Hello {dict((x, x) for x in range(3))} World')
@@ -114,7 +114,7 @@ C402.py:9:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
6 6 | y = f'{dict((x, x) for x in range(3))}'
7 7 | print(f'Hello {dict((x, x) for x in range(3))} World')
8 8 | print(f"Hello {dict((x, x) for x in 'abc')} World")
@@ -135,7 +135,7 @@ C402.py:10:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
7 7 | print(f'Hello {dict((x, x) for x in range(3))} World')
8 8 | print(f"Hello {dict((x, x) for x in 'abc')} World")
9 9 | print(f'Hello {dict((x, x) for x in "abc")} World')
@@ -155,7 +155,7 @@ C402.py:12:4: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
9 9 | print(f'Hello {dict((x, x) for x in "abc")} World')
10 10 | print(f'Hello {dict((x,x) for x in "abc")} World')
11 11 |
@@ -175,7 +175,7 @@ C402.py:12:37: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
9 9 | print(f'Hello {dict((x, x) for x in "abc")} World')
10 10 | print(f'Hello {dict((x,x) for x in "abc")} World')
11 11 |
@@ -195,7 +195,7 @@ C402.py:13:5: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
10 10 | print(f'Hello {dict((x,x) for x in "abc")} World')
11 11 |
12 12 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}'
@@ -215,7 +215,7 @@ C402.py:13:38: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
10 10 | print(f'Hello {dict((x,x) for x in "abc")} World')
11 11 |
12 12 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}'
@@ -236,7 +236,7 @@ C402.py:18:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
15 15 | def f(x):
16 16 | return x
17 17 |
@@ -256,7 +256,7 @@ C402.py:21:1: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension)
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
18 18 | print(f'Hello {dict((x,f(x)) for x in "abc")} World')
19 19 |
20 20 | # Regression test for: https://github.com/astral-sh/ruff/issues/7086

View File

@@ -10,7 +10,7 @@ C403.py:1:5: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` compr
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
1 |-s = set([x for x in range(3)])
1 |+s = {x for x in range(3)}
2 2 | s = set(
@@ -30,7 +30,7 @@ C403.py:2:5: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` compr
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
1 1 | s = set([x for x in range(3)])
2 |-s = set(
3 |- [x for x in range(3)]
@@ -52,7 +52,7 @@ C403.py:6:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` compr
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
3 3 | [x for x in range(3)]
4 4 | )
5 5 |
@@ -72,7 +72,7 @@ C403.py:7:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` compr
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
4 4 | )
5 5 |
6 6 | s = f"{set([x for x in 'ab'])}"
@@ -93,7 +93,7 @@ C403.py:12:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comp
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
9 9 | def f(x):
10 10 | return x
11 11 |
@@ -113,7 +113,7 @@ C403.py:14:9: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comp
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
11 11 |
12 12 | s = f"{set([f(x) for x in 'ab'])}"
13 13 |
@@ -131,7 +131,7 @@ C403.py:14:34: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` com
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
11 11 |
12 12 | s = f"{set([f(x) for x in 'ab'])}"
13 13 |
@@ -147,7 +147,7 @@ C403.py:15:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comp
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
12 12 | s = f"{set([f(x) for x in 'ab'])}"
13 13 |
14 14 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }"
@@ -162,7 +162,7 @@ C403.py:15:33: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` com
|
= help: Rewrite as a `set` comprehension
Suggested fix
Unsafe fix
12 12 | s = f"{set([f(x) for x in 'ab'])}"
13 13 |
14 14 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }"

View File

@@ -9,7 +9,7 @@ C404.py:1:1: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comp
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
1 |-dict([(i, i) for i in range(3)])
1 |+{i: i for i in range(3)}
2 2 | dict([(i, i) for i in range(3)], z=4)
@@ -27,7 +27,7 @@ C404.py:7:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comp
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
4 4 | def f(x):
5 5 | return x
6 6 |
@@ -47,7 +47,7 @@ C404.py:8:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comp
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
5 5 | return x
6 6 |
7 7 | f'{dict([(s,s) for s in "ab"])}'
@@ -67,7 +67,7 @@ C404.py:9:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comp
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
6 6 |
7 7 | f'{dict([(s,s) for s in "ab"])}'
8 8 | f"{dict([(s,s) for s in 'ab'])}"
@@ -88,7 +88,7 @@ C404.py:10:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` com
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
7 7 | f'{dict([(s,s) for s in "ab"])}'
8 8 | f"{dict([(s,s) for s in 'ab'])}"
9 9 | f"{dict([(s, s) for s in 'ab'])}"
@@ -108,7 +108,7 @@ C404.py:12:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` com
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
9 9 | f"{dict([(s, s) for s in 'ab'])}"
10 10 | f"{dict([(s,f(s)) for s in 'ab'])}"
11 11 |
@@ -128,7 +128,7 @@ C404.py:12:34: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` co
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
9 9 | f"{dict([(s, s) for s in 'ab'])}"
10 10 | f"{dict([(s,f(s)) for s in 'ab'])}"
11 11 |
@@ -148,7 +148,7 @@ C404.py:13:5: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` com
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
10 10 | f"{dict([(s,f(s)) for s in 'ab'])}"
11 11 |
12 12 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}'
@@ -168,7 +168,7 @@ C404.py:13:35: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` co
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
10 10 | f"{dict([(s,f(s)) for s in 'ab'])}"
11 11 |
12 12 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}'
@@ -186,7 +186,7 @@ C404.py:16:14: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` co
|
= help: Rewrite as a `dict` comprehension
Suggested fix
Unsafe fix
13 13 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }'
14 14 |
15 15 | # Regression test for: https://github.com/astral-sh/ruff/issues/7087

View File

@@ -10,7 +10,7 @@ C405.py:1:1: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
1 |-set([1, 2])
1 |+{1, 2}
2 2 | set((1, 2))
@@ -27,7 +27,7 @@ C405.py:2:1: C405 [*] Unnecessary `tuple` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
1 1 | set([1, 2])
2 |-set((1, 2))
2 |+{1, 2}
@@ -46,7 +46,7 @@ C405.py:3:1: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
1 1 | set([1, 2])
2 2 | set((1, 2))
3 |-set([])
@@ -66,7 +66,7 @@ C405.py:4:1: C405 [*] Unnecessary `tuple` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
1 1 | set([1, 2])
2 2 | set((1, 2))
3 3 | set([])
@@ -88,7 +88,7 @@ C405.py:6:1: C405 [*] Unnecessary `tuple` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
3 3 | set([])
4 4 | set(())
5 5 | set()
@@ -111,7 +111,7 @@ C405.py:7:1: C405 [*] Unnecessary `tuple` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
4 4 | set(())
5 5 | set()
6 6 | set((1,))
@@ -137,7 +137,7 @@ C405.py:10:1: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
7 7 | set((
8 8 | 1,
9 9 | ))
@@ -163,7 +163,7 @@ C405.py:13:1: C405 [*] Unnecessary `tuple` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
10 10 | set([
11 11 | 1,
12 12 | ])
@@ -188,7 +188,7 @@ C405.py:16:1: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
13 13 | set(
14 14 | (1,)
15 15 | )
@@ -211,7 +211,7 @@ C405.py:19:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
16 16 | set(
17 17 | [1,]
18 18 | )
@@ -231,7 +231,7 @@ C405.py:20:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
17 17 | [1,]
18 18 | )
19 19 | f"{set([1,2,3])}"
@@ -252,7 +252,7 @@ C405.py:21:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
18 18 | )
19 19 | f"{set([1,2,3])}"
20 20 | f"{set(['a', 'b'])}"
@@ -273,7 +273,7 @@ C405.py:23:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
20 20 | f"{set(['a', 'b'])}"
21 21 | f'{set(["a", "b"])}'
22 22 |
@@ -294,7 +294,7 @@ C405.py:23:22: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
20 20 | f"{set(['a', 'b'])}"
21 21 | f'{set(["a", "b"])}'
22 22 |
@@ -314,7 +314,7 @@ C405.py:24:5: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
21 21 | f'{set(["a", "b"])}'
22 22 |
23 23 | f"{set(['a', 'b']) - set(['a'])}"
@@ -333,7 +333,7 @@ C405.py:24:23: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
21 21 | f'{set(["a", "b"])}'
22 22 |
23 23 | f"{set(['a', 'b']) - set(['a'])}"
@@ -352,7 +352,7 @@ C405.py:25:6: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
22 22 |
23 23 | f"{set(['a', 'b']) - set(['a'])}"
24 24 | f"{ set(['a', 'b']) - set(['a']) }"
@@ -370,7 +370,7 @@ C405.py:25:24: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
22 22 |
23 23 | f"{set(['a', 'b']) - set(['a'])}"
24 24 | f"{ set(['a', 'b']) - set(['a']) }"
@@ -387,7 +387,7 @@ C405.py:26:7: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
23 23 | f"{set(['a', 'b']) - set(['a'])}"
24 24 | f"{ set(['a', 'b']) - set(['a']) }"
25 25 | f"a {set(['a', 'b']) - set(['a'])} b"
@@ -403,7 +403,7 @@ C405.py:26:25: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal)
|
= help: Rewrite as a `set` literal
Suggested fix
Unsafe fix
23 23 | f"{set(['a', 'b']) - set(['a'])}"
24 24 | f"{ set(['a', 'b']) - set(['a']) }"
25 25 | f"a {set(['a', 'b']) - set(['a'])} b"

View File

@@ -10,7 +10,7 @@ C406.py:1:6: C406 [*] Unnecessary `list` literal (rewrite as a `dict` literal)
|
= help: Rewrite as a `dict` literal
Suggested fix
Unsafe fix
1 |-d1 = dict([(1, 2)])
1 |+d1 = {1: 2}
2 2 | d2 = dict(((1, 2),))
@@ -27,7 +27,7 @@ C406.py:2:6: C406 [*] Unnecessary `tuple` literal (rewrite as a `dict` literal)
|
= help: Rewrite as a `dict` literal
Suggested fix
Unsafe fix
1 1 | d1 = dict([(1, 2)])
2 |-d2 = dict(((1, 2),))
2 |+d2 = {1: 2,}
@@ -46,7 +46,7 @@ C406.py:3:6: C406 [*] Unnecessary `list` literal (rewrite as a `dict` literal)
|
= help: Rewrite as a `dict` literal
Suggested fix
Unsafe fix
1 1 | d1 = dict([(1, 2)])
2 2 | d2 = dict(((1, 2),))
3 |-d3 = dict([])
@@ -64,7 +64,7 @@ C406.py:4:6: C406 [*] Unnecessary `tuple` literal (rewrite as a `dict` literal)
|
= help: Rewrite as a `dict` literal
Suggested fix
Unsafe fix
1 1 | d1 = dict([(1, 2)])
2 2 | d2 = dict(((1, 2),))
3 3 | d3 = dict([])

View File

@@ -10,7 +10,7 @@ C408.py:1:5: C408 [*] Unnecessary `tuple` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
1 |-t = tuple()
1 |+t = ()
2 2 | l = list()
@@ -27,7 +27,7 @@ C408.py:2:5: C408 [*] Unnecessary `list` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
1 1 | t = tuple()
2 |-l = list()
2 |+l = []
@@ -46,7 +46,7 @@ C408.py:3:6: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
1 1 | t = tuple()
2 2 | l = list()
3 |-d1 = dict()
@@ -65,7 +65,7 @@ C408.py:4:6: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
1 1 | t = tuple()
2 2 | l = list()
3 3 | d1 = dict()
@@ -86,7 +86,7 @@ C408.py:14:4: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
11 11 |
12 12 | a = list()
13 13 |
@@ -106,7 +106,7 @@ C408.py:15:4: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
12 12 | a = list()
13 13 |
14 14 | f"{dict(x='y')}"
@@ -126,7 +126,7 @@ C408.py:16:4: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
13 13 |
14 14 | f"{dict(x='y')}"
15 15 | f'{dict(x="y")}'
@@ -147,7 +147,7 @@ C408.py:17:6: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
14 14 | f"{dict(x='y')}"
15 15 | f'{dict(x="y")}'
16 16 | f"{dict()}"
@@ -168,7 +168,7 @@ C408.py:19:4: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
16 16 | f"{dict()}"
17 17 | f"a {dict()} b"
18 18 |
@@ -189,7 +189,7 @@ C408.py:19:18: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
16 16 | f"{dict()}"
17 17 | f"a {dict()} b"
18 18 |
@@ -209,7 +209,7 @@ C408.py:20:5: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
17 17 | f"a {dict()} b"
18 18 |
19 19 | f"{dict(x='y') | dict(y='z')}"
@@ -228,7 +228,7 @@ C408.py:20:19: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
17 17 | f"a {dict()} b"
18 18 |
19 19 | f"{dict(x='y') | dict(y='z')}"
@@ -247,7 +247,7 @@ C408.py:21:6: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
18 18 |
19 19 | f"{dict(x='y') | dict(y='z')}"
20 20 | f"{ dict(x='y') | dict(y='z') }"
@@ -265,7 +265,7 @@ C408.py:21:20: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
18 18 |
19 19 | f"{dict(x='y') | dict(y='z')}"
20 20 | f"{ dict(x='y') | dict(y='z') }"
@@ -282,7 +282,7 @@ C408.py:22:7: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
19 19 | f"{dict(x='y') | dict(y='z')}"
20 20 | f"{ dict(x='y') | dict(y='z') }"
21 21 | f"a {dict(x='y') | dict(y='z')} b"
@@ -298,7 +298,7 @@ C408.py:22:21: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
19 19 | f"{dict(x='y') | dict(y='z')}"
20 20 | f"{ dict(x='y') | dict(y='z') }"
21 21 | f"a {dict(x='y') | dict(y='z')} b"

View File

@@ -10,7 +10,7 @@ C408.py:1:5: C408 [*] Unnecessary `tuple` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
1 |-t = tuple()
1 |+t = ()
2 2 | l = list()
@@ -27,7 +27,7 @@ C408.py:2:5: C408 [*] Unnecessary `list` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
1 1 | t = tuple()
2 |-l = list()
2 |+l = []
@@ -46,7 +46,7 @@ C408.py:3:6: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
1 1 | t = tuple()
2 2 | l = list()
3 |-d1 = dict()
@@ -65,7 +65,7 @@ C408.py:16:4: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
13 13 |
14 14 | f"{dict(x='y')}"
15 15 | f'{dict(x="y")}'
@@ -86,7 +86,7 @@ C408.py:17:6: C408 [*] Unnecessary `dict` call (rewrite as a literal)
|
= help: Rewrite as a literal
Suggested fix
Unsafe fix
14 14 | f"{dict(x='y')}"
15 15 | f'{dict(x="y")}'
16 16 | f"{dict()}"

View File

@@ -10,7 +10,7 @@ C409.py:1:6: C409 [*] Unnecessary `list` literal passed to `tuple()` (rewrite as
|
= help: Rewrite as a `tuple` literal
Suggested fix
Unsafe fix
1 |-t1 = tuple([])
1 |+t1 = ()
2 2 | t2 = tuple([1, 2])
@@ -27,7 +27,7 @@ C409.py:2:6: C409 [*] Unnecessary `list` literal passed to `tuple()` (rewrite as
|
= help: Rewrite as a `tuple` literal
Suggested fix
Unsafe fix
1 1 | t1 = tuple([])
2 |-t2 = tuple([1, 2])
2 |+t2 = (1, 2)
@@ -46,7 +46,7 @@ C409.py:3:6: C409 [*] Unnecessary `tuple` literal passed to `tuple()` (remove th
|
= help: Remove outer `tuple` call
Suggested fix
Unsafe fix
1 1 | t1 = tuple([])
2 2 | t2 = tuple([1, 2])
3 |-t3 = tuple((1, 2))
@@ -70,7 +70,7 @@ C409.py:4:6: C409 [*] Unnecessary `list` literal passed to `tuple()` (rewrite as
|
= help: Rewrite as a `tuple` literal
Suggested fix
Unsafe fix
1 1 | t1 = tuple([])
2 2 | t2 = tuple([1, 2])
3 3 | t3 = tuple((1, 2))
@@ -96,7 +96,7 @@ C409.py:8:6: C409 [*] Unnecessary `tuple` literal passed to `tuple()` (remove th
|
= help: Remove outer `tuple` call
Suggested fix
Unsafe fix
5 5 | 1,
6 6 | 2
7 7 | ])

View File

@@ -10,7 +10,7 @@ C410.py:1:6: C410 [*] Unnecessary `list` literal passed to `list()` (remove the
|
= help: Remove outer `list` call
Suggested fix
Unsafe fix
1 |-l1 = list([1, 2])
1 |+l1 = [1, 2]
2 2 | l2 = list((1, 2))
@@ -27,7 +27,7 @@ C410.py:2:6: C410 [*] Unnecessary `tuple` literal passed to `list()` (rewrite as
|
= help: Rewrite as a `list` literal
Suggested fix
Unsafe fix
1 1 | l1 = list([1, 2])
2 |-l2 = list((1, 2))
2 |+l2 = [1, 2]
@@ -44,7 +44,7 @@ C410.py:3:6: C410 [*] Unnecessary `list` literal passed to `list()` (remove the
|
= help: Remove outer `list` call
Suggested fix
Unsafe fix
1 1 | l1 = list([1, 2])
2 2 | l2 = list((1, 2))
3 |-l3 = list([])
@@ -60,7 +60,7 @@ C410.py:4:6: C410 [*] Unnecessary `tuple` literal passed to `list()` (rewrite as
|
= help: Rewrite as a `list` literal
Suggested fix
Unsafe fix
1 1 | l1 = list([1, 2])
2 2 | l2 = list((1, 2))
3 3 | l3 = list([])

View File

@@ -9,7 +9,7 @@ C411.py:2:1: C411 [*] Unnecessary `list` call (remove the outer call to `list()`
|
= help: Remove outer `list` call
Suggested fix
Unsafe fix
1 1 | x = [1, 2, 3]
2 |-list([i for i in x])
2 |+[i for i in x]

View File

@@ -12,7 +12,7 @@ C413.py:3:1: C413 [*] Unnecessary `list` call around `sorted()`
|
= help: Remove unnecessary `list` call
Fix
Safe fix
1 1 | x = [2, 3, 1]
2 2 | list(x)
3 |-list(sorted(x))
@@ -32,7 +32,7 @@ C413.py:4:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
1 1 | x = [2, 3, 1]
2 2 | list(x)
3 3 | list(sorted(x))
@@ -53,7 +53,7 @@ C413.py:5:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
2 2 | list(x)
3 3 | list(sorted(x))
4 4 | reversed(sorted(x))
@@ -74,7 +74,7 @@ C413.py:6:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
3 3 | list(sorted(x))
4 4 | reversed(sorted(x))
5 5 | reversed(sorted(x, key=lambda e: e))
@@ -95,7 +95,7 @@ C413.py:7:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
4 4 | reversed(sorted(x))
5 5 | reversed(sorted(x, key=lambda e: e))
6 6 | reversed(sorted(x, reverse=True))
@@ -116,7 +116,7 @@ C413.py:8:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
5 5 | reversed(sorted(x, key=lambda e: e))
6 6 | reversed(sorted(x, reverse=True))
7 7 | reversed(sorted(x, key=lambda e: e, reverse=True))
@@ -137,7 +137,7 @@ C413.py:9:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
6 6 | reversed(sorted(x, reverse=True))
7 7 | reversed(sorted(x, key=lambda e: e, reverse=True))
8 8 | reversed(sorted(x, reverse=True, key=lambda e: e))
@@ -157,7 +157,7 @@ C413.py:10:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
7 7 | reversed(sorted(x, key=lambda e: e, reverse=True))
8 8 | reversed(sorted(x, reverse=True, key=lambda e: e))
9 9 | reversed(sorted(x, reverse=False))
@@ -178,7 +178,7 @@ C413.py:11:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
8 8 | reversed(sorted(x, reverse=True, key=lambda e: e))
9 9 | reversed(sorted(x, reverse=False))
10 10 | reversed(sorted(x, reverse=x))
@@ -197,7 +197,7 @@ C413.py:14:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
11 11 | reversed(sorted(x, reverse=not x))
12 12 |
13 13 | # Regression test for: https://github.com/astral-sh/ruff/issues/7289
@@ -216,7 +216,7 @@ C413.py:15:1: C413 [*] Unnecessary `reversed` call around `sorted()`
|
= help: Remove unnecessary `reversed` call
Suggested fix
Unsafe fix
12 12 |
13 13 | # Regression test for: https://github.com/astral-sh/ruff/issues/7289
14 14 | reversed(sorted(i for i in range(42)))

View File

@@ -11,7 +11,7 @@ C414.py:2:1: C414 [*] Unnecessary `list` call within `list()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
1 1 | x = [1, 2, 3]
2 |-list(list(x))
2 |+list(x)
@@ -30,7 +30,7 @@ C414.py:3:1: C414 [*] Unnecessary `tuple` call within `list()`
|
= help: Remove the inner `tuple` call
Suggested fix
Unsafe fix
1 1 | x = [1, 2, 3]
2 2 | list(list(x))
3 |-list(tuple(x))
@@ -50,7 +50,7 @@ C414.py:4:1: C414 [*] Unnecessary `list` call within `tuple()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
1 1 | x = [1, 2, 3]
2 2 | list(list(x))
3 3 | list(tuple(x))
@@ -71,7 +71,7 @@ C414.py:5:1: C414 [*] Unnecessary `tuple` call within `tuple()`
|
= help: Remove the inner `tuple` call
Suggested fix
Unsafe fix
2 2 | list(list(x))
3 3 | list(tuple(x))
4 4 | tuple(list(x))
@@ -92,7 +92,7 @@ C414.py:6:1: C414 [*] Unnecessary `set` call within `set()`
|
= help: Remove the inner `set` call
Suggested fix
Unsafe fix
3 3 | list(tuple(x))
4 4 | tuple(list(x))
5 5 | tuple(tuple(x))
@@ -113,7 +113,7 @@ C414.py:7:1: C414 [*] Unnecessary `list` call within `set()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
4 4 | tuple(list(x))
5 5 | tuple(tuple(x))
6 6 | set(set(x))
@@ -134,7 +134,7 @@ C414.py:8:1: C414 [*] Unnecessary `tuple` call within `set()`
|
= help: Remove the inner `tuple` call
Suggested fix
Unsafe fix
5 5 | tuple(tuple(x))
6 6 | set(set(x))
7 7 | set(list(x))
@@ -155,7 +155,7 @@ C414.py:9:1: C414 [*] Unnecessary `sorted` call within `set()`
|
= help: Remove the inner `sorted` call
Suggested fix
Unsafe fix
6 6 | set(set(x))
7 7 | set(list(x))
8 8 | set(tuple(x))
@@ -176,7 +176,7 @@ C414.py:10:1: C414 [*] Unnecessary `sorted` call within `set()`
|
= help: Remove the inner `sorted` call
Suggested fix
Unsafe fix
7 7 | set(list(x))
8 8 | set(tuple(x))
9 9 | set(sorted(x))
@@ -197,7 +197,7 @@ C414.py:11:1: C414 [*] Unnecessary `reversed` call within `set()`
|
= help: Remove the inner `reversed` call
Suggested fix
Unsafe fix
8 8 | set(tuple(x))
9 9 | set(sorted(x))
10 10 | set(sorted(x, key=lambda y: y))
@@ -218,7 +218,7 @@ C414.py:12:1: C414 [*] Unnecessary `list` call within `sorted()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
9 9 | set(sorted(x))
10 10 | set(sorted(x, key=lambda y: y))
11 11 | set(reversed(x))
@@ -239,7 +239,7 @@ C414.py:13:1: C414 [*] Unnecessary `tuple` call within `sorted()`
|
= help: Remove the inner `tuple` call
Suggested fix
Unsafe fix
10 10 | set(sorted(x, key=lambda y: y))
11 11 | set(reversed(x))
12 12 | sorted(list(x))
@@ -260,7 +260,7 @@ C414.py:14:1: C414 [*] Unnecessary `sorted` call within `sorted()`
|
= help: Remove the inner `sorted` call
Suggested fix
Unsafe fix
11 11 | set(reversed(x))
12 12 | sorted(list(x))
13 13 | sorted(tuple(x))
@@ -281,7 +281,7 @@ C414.py:15:1: C414 [*] Unnecessary `sorted` call within `sorted()`
|
= help: Remove the inner `sorted` call
Suggested fix
Unsafe fix
12 12 | sorted(list(x))
13 13 | sorted(tuple(x))
14 14 | sorted(sorted(x))
@@ -302,7 +302,7 @@ C414.py:16:1: C414 [*] Unnecessary `sorted` call within `sorted()`
|
= help: Remove the inner `sorted` call
Suggested fix
Unsafe fix
13 13 | sorted(tuple(x))
14 14 | sorted(sorted(x))
15 15 | sorted(sorted(x, key=foo, reverse=False), reverse=False, key=foo)
@@ -323,7 +323,7 @@ C414.py:17:1: C414 [*] Unnecessary `reversed` call within `sorted()`
|
= help: Remove the inner `reversed` call
Suggested fix
Unsafe fix
14 14 | sorted(sorted(x))
15 15 | sorted(sorted(x, key=foo, reverse=False), reverse=False, key=foo)
16 16 | sorted(sorted(x, reverse=True), reverse=True)
@@ -344,7 +344,7 @@ C414.py:18:1: C414 [*] Unnecessary `list` call within `sorted()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
15 15 | sorted(sorted(x, key=foo, reverse=False), reverse=False, key=foo)
16 16 | sorted(sorted(x, reverse=True), reverse=True)
17 17 | sorted(reversed(x))
@@ -370,7 +370,7 @@ C414.py:19:1: C414 [*] Unnecessary `list` call within `tuple()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
17 17 | sorted(reversed(x))
18 18 | sorted(list(x), key=lambda y: y)
19 19 | tuple(
@@ -394,7 +394,7 @@ C414.py:25:1: C414 [*] Unnecessary `set` call within `set()`
|
= help: Remove the inner `set` call
Suggested fix
Unsafe fix
22 22 | "o"]
23 23 | )
24 24 | )
@@ -415,7 +415,7 @@ C414.py:26:1: C414 [*] Unnecessary `list` call within `set()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
23 23 | )
24 24 | )
25 25 | set(set())
@@ -435,7 +435,7 @@ C414.py:27:1: C414 [*] Unnecessary `tuple` call within `set()`
|
= help: Remove the inner `tuple` call
Suggested fix
Unsafe fix
24 24 | )
25 25 | set(set())
26 26 | set(list())
@@ -456,7 +456,7 @@ C414.py:28:1: C414 [*] Unnecessary `reversed` call within `sorted()`
|
= help: Remove the inner `reversed` call
Suggested fix
Unsafe fix
25 25 | set(set())
26 26 | set(list())
27 27 | set(tuple())
@@ -482,7 +482,7 @@ C414.py:37:27: C414 [*] Unnecessary `list` call within `sorted()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
35 35 |
36 36 | # Preserve trailing comments.
37 37 | xxxxxxxxxxx_xxxxx_xxxxx = sorted(
@@ -505,7 +505,7 @@ C414.py:44:27: C414 [*] Unnecessary `list` call within `sorted()`
|
= help: Remove the inner `list` call
Suggested fix
Unsafe fix
42 42 | )
43 43 |
44 44 | xxxxxxxxxxx_xxxxx_xxxxx = sorted(

View File

@@ -12,7 +12,7 @@ C416.py:6:1: C416 [*] Unnecessary `list` comprehension (rewrite using `list()`)
|
= help: Rewrite using `list()`
Suggested fix
Unsafe fix
3 3 | z = [(1,), (2,), (3,)]
4 4 | d = {"a": 1, "b": 2, "c": 3}
5 5 |
@@ -32,7 +32,7 @@ C416.py:7:1: C416 [*] Unnecessary `set` comprehension (rewrite using `set()`)
|
= help: Rewrite using `set()`
Suggested fix
Unsafe fix
4 4 | d = {"a": 1, "b": 2, "c": 3}
5 5 |
6 6 | [i for i in x]
@@ -53,7 +53,7 @@ C416.py:8:1: C416 [*] Unnecessary `dict` comprehension (rewrite using `dict()`)
|
= help: Rewrite using `dict()`
Suggested fix
Unsafe fix
5 5 |
6 6 | [i for i in x]
7 7 | {i for i in x}
@@ -74,7 +74,7 @@ C416.py:9:1: C416 [*] Unnecessary `dict` comprehension (rewrite using `dict()`)
|
= help: Rewrite using `dict()`
Suggested fix
Unsafe fix
6 6 | [i for i in x]
7 7 | {i for i in x}
8 8 | {k: v for k, v in y}
@@ -94,7 +94,7 @@ C416.py:10:1: C416 [*] Unnecessary `list` comprehension (rewrite using `list()`)
|
= help: Rewrite using `list()`
Suggested fix
Unsafe fix
7 7 | {i for i in x}
8 8 | {k: v for k, v in y}
9 9 | {k: v for k, v in d.items()}
@@ -115,7 +115,7 @@ C416.py:11:1: C416 [*] Unnecessary `dict` comprehension (rewrite using `dict()`)
|
= help: Rewrite using `dict()`
Suggested fix
Unsafe fix
8 8 | {k: v for k, v in y}
9 9 | {k: v for k, v in d.items()}
10 10 | [(k, v) for k, v in d.items()]
@@ -133,7 +133,7 @@ C416.py:24:70: C416 [*] Unnecessary `list` comprehension (rewrite using `list()`
|
= help: Rewrite using `list()`
Suggested fix
Unsafe fix
21 21 | {k: v if v else None for k, v in y}
22 22 |
23 23 | # Regression test for: https://github.com/astral-sh/ruff/issues/7196

View File

@@ -12,7 +12,7 @@ C417.py:3:1: C417 [*] Unnecessary `map` usage (rewrite using a generator express
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
1 1 | # Errors.
2 2 | nums = [1, 2, 3]
3 |-map(lambda x: x + 1, nums)
@@ -32,7 +32,7 @@ C417.py:4:1: C417 [*] Unnecessary `map` usage (rewrite using a generator express
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
1 1 | # Errors.
2 2 | nums = [1, 2, 3]
3 3 | map(lambda x: x + 1, nums)
@@ -53,7 +53,7 @@ C417.py:5:1: C417 [*] Unnecessary `map` usage (rewrite using a `list` comprehens
|
= help: Replace `map` with a `list` comprehension
Suggested fix
Unsafe fix
2 2 | nums = [1, 2, 3]
3 3 | map(lambda x: x + 1, nums)
4 4 | map(lambda x: str(x), nums)
@@ -74,7 +74,7 @@ C417.py:6:1: C417 [*] Unnecessary `map` usage (rewrite using a `set` comprehensi
|
= help: Replace `map` with a `set` comprehension
Suggested fix
Unsafe fix
3 3 | map(lambda x: x + 1, nums)
4 4 | map(lambda x: str(x), nums)
5 5 | list(map(lambda x: x * 2, nums))
@@ -95,7 +95,7 @@ C417.py:7:1: C417 [*] Unnecessary `map` usage (rewrite using a `dict` comprehens
|
= help: Replace `map` with a `dict` comprehension
Suggested fix
Unsafe fix
4 4 | map(lambda x: str(x), nums)
5 5 | list(map(lambda x: x * 2, nums))
6 6 | set(map(lambda x: x % 2 == 0, nums))
@@ -116,7 +116,7 @@ C417.py:8:1: C417 [*] Unnecessary `map` usage (rewrite using a `dict` comprehens
|
= help: Replace `map` with a `dict` comprehension
Suggested fix
Unsafe fix
5 5 | list(map(lambda x: x * 2, nums))
6 6 | set(map(lambda x: x % 2 == 0, nums))
7 7 | dict(map(lambda v: (v, v**2), nums))
@@ -137,7 +137,7 @@ C417.py:9:1: C417 [*] Unnecessary `map` usage (rewrite using a generator express
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
6 6 | set(map(lambda x: x % 2 == 0, nums))
7 7 | dict(map(lambda v: (v, v**2), nums))
8 8 | dict(map(lambda v: [v, v**2], nums))
@@ -158,7 +158,7 @@ C417.py:10:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
7 7 | dict(map(lambda v: (v, v**2), nums))
8 8 | dict(map(lambda v: [v, v**2], nums))
9 9 | map(lambda: "const", nums)
@@ -179,7 +179,7 @@ C417.py:11:13: C417 [*] Unnecessary `map` usage (rewrite using a generator expre
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
8 8 | dict(map(lambda v: [v, v**2], nums))
9 9 | map(lambda: "const", nums)
10 10 | map(lambda _: 3.0, nums)
@@ -200,7 +200,7 @@ C417.py:12:5: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
9 9 | map(lambda: "const", nums)
10 10 | map(lambda _: 3.0, nums)
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
@@ -220,7 +220,7 @@ C417.py:13:14: C417 [*] Unnecessary `map` usage (rewrite using a generator expre
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
10 10 | map(lambda _: 3.0, nums)
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
12 12 | all(map(lambda v: isinstance(v, dict), nums))
@@ -241,7 +241,7 @@ C417.py:14:1: C417 [*] Unnecessary `map` usage (rewrite using a `list` comprehen
|
= help: Replace `map` with a `list` comprehension
Suggested fix
Unsafe fix
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
12 12 | all(map(lambda v: isinstance(v, dict), nums))
13 13 | filter(func, map(lambda v: v, nums))
@@ -260,7 +260,7 @@ C417.py:17:8: C417 [*] Unnecessary `map` usage (rewrite using a `set` comprehens
|
= help: Replace `map` with a `set` comprehension
Suggested fix
Unsafe fix
14 14 | list(map(lambda x, y: x * y, nums))
15 15 |
16 16 | # When inside f-string, then the fix should be surrounded by whitespace
@@ -281,7 +281,7 @@ C417.py:18:8: C417 [*] Unnecessary `map` usage (rewrite using a `dict` comprehen
|
= help: Replace `map` with a `dict` comprehension
Suggested fix
Unsafe fix
15 15 |
16 16 | # When inside f-string, then the fix should be surrounded by whitespace
17 17 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}"
@@ -301,7 +301,7 @@ C417.py:36:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
33 33 | map(lambda x: lambda: x, range(4))
34 34 |
35 35 | # Error: the `x` is overridden by the inner lambda.
@@ -321,7 +321,7 @@ C417.py:47:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
44 44 | dict(map(lambda k, v: (k, v), keys, values))
45 45 |
46 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
@@ -340,7 +340,7 @@ C417.py:48:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
45 45 |
46 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
47 47 | map(lambda x: x, y if y else z)
@@ -357,7 +357,7 @@ C417.py:49:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
|
= help: Replace `map` with a generator expression
Suggested fix
Unsafe fix
46 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
47 47 | map(lambda x: x, y if y else z)
48 48 | map(lambda x: x, (y if y else z))

View File

@@ -10,7 +10,7 @@ C418.py:1:1: C418 [*] Unnecessary `dict` literal passed to `dict()` (remove the
|
= help: Remove outer `dict` call
Suggested fix
Unsafe fix
1 |-dict({})
1 |+{}
2 2 | dict({'a': 1})
@@ -27,7 +27,7 @@ C418.py:2:1: C418 [*] Unnecessary `dict` literal passed to `dict()` (remove the
|
= help: Remove outer `dict` call
Suggested fix
Unsafe fix
1 1 | dict({})
2 |-dict({'a': 1})
2 |+{'a': 1}
@@ -46,7 +46,7 @@ C418.py:3:1: C418 [*] Unnecessary `dict` comprehension passed to `dict()` (remov
|
= help: Remove outer `dict` call
Suggested fix
Unsafe fix
1 1 | dict({})
2 2 | dict({'a': 1})
3 |-dict({'x': 1 for x in range(10)})
@@ -68,7 +68,7 @@ C418.py:4:1: C418 [*] Unnecessary `dict` comprehension passed to `dict()` (remov
|
= help: Remove outer `dict` call
Suggested fix
Unsafe fix
1 1 | dict({})
2 2 | dict({'a': 1})
3 3 | dict({'x': 1 for x in range(10)})

View File

@@ -10,7 +10,7 @@ C419.py:1:5: C419 [*] Unnecessary list comprehension.
|
= help: Remove unnecessary list comprehension
Suggested fix
Unsafe fix
1 |-any([x.id for x in bar])
1 |+any(x.id for x in bar)
2 2 | all([x.id for x in bar])
@@ -27,7 +27,7 @@ C419.py:2:5: C419 [*] Unnecessary list comprehension.
|
= help: Remove unnecessary list comprehension
Suggested fix
Unsafe fix
1 1 | any([x.id for x in bar])
2 |-all([x.id for x in bar])
2 |+all(x.id for x in bar)
@@ -46,7 +46,7 @@ C419.py:4:5: C419 [*] Unnecessary list comprehension.
|
= help: Remove unnecessary list comprehension
Suggested fix
Unsafe fix
1 1 | any([x.id for x in bar])
2 2 | all([x.id for x in bar])
3 3 | any( # first comment
@@ -67,7 +67,7 @@ C419.py:7:5: C419 [*] Unnecessary list comprehension.
|
= help: Remove unnecessary list comprehension
Suggested fix
Unsafe fix
4 4 | [x.id for x in bar], # second comment
5 5 | ) # third comment
6 6 | all( # first comment
@@ -88,7 +88,7 @@ C419.py:9:5: C419 [*] Unnecessary list comprehension.
|
= help: Remove unnecessary list comprehension
Suggested fix
Unsafe fix
6 6 | all( # first comment
7 7 | [x.id for x in bar], # second comment
8 8 | ) # third comment
@@ -115,7 +115,7 @@ C419.py:24:5: C419 [*] Unnecessary list comprehension.
|
= help: Remove unnecessary list comprehension
Suggested fix
Unsafe fix
21 21 |
22 22 | # Special comment handling
23 23 | any(
@@ -147,7 +147,7 @@ C419.py:35:5: C419 [*] Unnecessary list comprehension.
|
= help: Remove unnecessary list comprehension
Suggested fix
Unsafe fix
32 32 |
33 33 | # Weird case where the function call, opening bracket, and comment are all
34 34 | # on the same line.

View File

@@ -1,10 +1,11 @@
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Stmt};
use ruff_text_size::{Ranged, TextRange};
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
use ruff_source_file::Locator;
use ruff_text_size::Ranged;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::whitespace;
use ruff_python_codegen::{Generator, Stylist};
use ruff_python_codegen::Stylist;
use crate::checkers::ast::Checker;
use crate::registry::Rule;
@@ -196,7 +197,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
first,
indentation,
checker.stylist(),
checker.generator(),
checker.locator(),
));
}
}
@@ -216,7 +217,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
first,
indentation,
checker.stylist(),
checker.generator(),
checker.locator(),
));
}
}
@@ -241,7 +242,7 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
first,
indentation,
checker.stylist(),
checker.generator(),
checker.locator(),
));
}
}
@@ -269,28 +270,27 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
fn generate_fix(
stmt: &Stmt,
exc_arg: &Expr,
indentation: &str,
stmt_indentation: &str,
stylist: &Stylist,
generator: Generator,
locator: &Locator,
) -> Fix {
let assignment = Stmt::Assign(ast::StmtAssign {
targets: vec![Expr::Name(ast::ExprName {
id: "msg".into(),
ctx: ExprContext::Store,
range: TextRange::default(),
})],
value: Box::new(exc_arg.clone()),
range: TextRange::default(),
});
Fix::unsafe_edits(
Edit::insertion(
format!(
"{}{}{}",
generator.stmt(&assignment),
stylist.line_ending().as_str(),
indentation,
),
if locator.contains_line_break(exc_arg.range()) {
format!(
"msg = ({line_ending}{stmt_indentation}{indentation}{}{line_ending}{stmt_indentation}){line_ending}{stmt_indentation}",
locator.slice(exc_arg.range()),
line_ending = stylist.line_ending().as_str(),
indentation = stylist.indentation().as_str(),
)
} else {
format!(
"msg = {}{}{}",
locator.slice(exc_arg.range()),
stylist.line_ending().as_str(),
stmt_indentation,
)
},
stmt.start(),
),
[Edit::range_replacement(

View File

@@ -9,7 +9,7 @@ EM.py:5:24: EM101 [*] Exception must not use a string literal, assign to variabl
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
2 2 |
3 3 |
4 4 | def f_a():
@@ -29,7 +29,7 @@ EM.py:18:24: EM102 [*] Exception must not use an f-string literal, assign to var
|
= help: Assign to variable; remove f-string literal
Suggested fix
Unsafe fix
15 15 |
16 16 | def f_b():
17 17 | example = "example"
@@ -48,7 +48,7 @@ EM.py:22:24: EM103 [*] Exception must not use a `.format()` string directly, ass
|
= help: Assign to variable; remove `.format()` string
Suggested fix
Unsafe fix
19 19 |
20 20 |
21 21 | def f_c():
@@ -77,7 +77,7 @@ EM.py:39:24: EM101 [*] Exception must not use a string literal, assign to variab
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
36 36 | def nested():
37 37 | msg = "hello"
38 38 |
@@ -107,7 +107,7 @@ EM.py:51:28: EM101 [*] Exception must not use a string literal, assign to variab
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
48 48 |
49 49 | def f_fix_indentation_check(foo):
50 50 | if foo:
@@ -128,7 +128,7 @@ EM.py:54:32: EM102 [*] Exception must not use an f-string literal, assign to var
|
= help: Assign to variable; remove f-string literal
Suggested fix
Unsafe fix
51 51 | raise RuntimeError("This is an example exception")
52 52 | else:
53 53 | if foo == "foo":
@@ -148,7 +148,7 @@ EM.py:55:24: EM103 [*] Exception must not use a `.format()` string directly, ass
|
= help: Assign to variable; remove `.format()` string
Suggested fix
Unsafe fix
52 52 | else:
53 53 | if foo == "foo":
54 54 | raise RuntimeError(f"This is an exception: {foo}")
@@ -177,4 +177,86 @@ EM.py:60:35: EM101 Exception must not use a string literal, assign to variable f
|
= help: Assign to variable; remove string literal
EM.py:64:24: EM102 [*] Exception must not use an f-string literal, assign to variable first
|
63 | def f_triple_quoted_string():
64 | raise RuntimeError(f"""This is an {"example"} exception""")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
|
= help: Assign to variable; remove f-string literal
Unsafe fix
61 61 |
62 62 |
63 63 | def f_triple_quoted_string():
64 |- raise RuntimeError(f"""This is an {"example"} exception""")
64 |+ msg = f"""This is an {"example"} exception"""
65 |+ raise RuntimeError(msg)
65 66 |
66 67 |
67 68 | def f_multi_line_string():
EM.py:76:9: EM103 [*] Exception must not use a `.format()` string directly, assign to variable first
|
74 | def f_multi_line_string2():
75 | raise RuntimeError(
76 | "This is an {example} exception".format(
| _________^
77 | | example="example"
78 | | )
| |_________^ EM103
79 | )
|
= help: Assign to variable; remove `.format()` string
Unsafe fix
72 72 |
73 73 |
74 74 | def f_multi_line_string2():
75 |- raise RuntimeError(
75 |+ msg = (
76 76 | "This is an {example} exception".format(
77 77 | example="example"
78 78 | )
79 79 | )
80 |+ raise RuntimeError(
81 |+ msg
82 |+ )
80 83 |
81 84 |
82 85 | def f_multi_line_string2():
EM.py:84:9: EM103 [*] Exception must not use a `.format()` string directly, assign to variable first
|
82 | def f_multi_line_string2():
83 | raise RuntimeError(
84 | (
| _________^
85 | | "This is an "
86 | | "{example} exception"
87 | | ).format(
88 | | example="example"
89 | | )
| |_________^ EM103
90 | )
|
= help: Assign to variable; remove `.format()` string
Unsafe fix
80 80 |
81 81 |
82 82 | def f_multi_line_string2():
83 |- raise RuntimeError(
83 |+ msg = (
84 84 | (
85 85 | "This is an "
86 86 | "{example} exception"
--------------------------------------------------------------------------------
88 88 | example="example"
89 89 | )
90 90 | )
91 |+ raise RuntimeError(
92 |+ msg
93 |+ )

View File

@@ -9,7 +9,7 @@ EM.py:5:24: EM101 [*] Exception must not use a string literal, assign to variabl
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
2 2 |
3 3 |
4 4 | def f_a():
@@ -28,7 +28,7 @@ EM.py:9:24: EM101 [*] Exception must not use a string literal, assign to variabl
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
6 6 |
7 7 |
8 8 | def f_a_short():
@@ -47,7 +47,7 @@ EM.py:13:24: EM101 [*] Exception must not use a string literal, assign to variab
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
10 10 |
11 11 |
12 12 | def f_a_empty():
@@ -67,7 +67,7 @@ EM.py:18:24: EM102 [*] Exception must not use an f-string literal, assign to var
|
= help: Assign to variable; remove f-string literal
Suggested fix
Unsafe fix
15 15 |
16 16 | def f_b():
17 17 | example = "example"
@@ -86,7 +86,7 @@ EM.py:22:24: EM103 [*] Exception must not use a `.format()` string directly, ass
|
= help: Assign to variable; remove `.format()` string
Suggested fix
Unsafe fix
19 19 |
20 20 |
21 21 | def f_c():
@@ -115,7 +115,7 @@ EM.py:39:24: EM101 [*] Exception must not use a string literal, assign to variab
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
36 36 | def nested():
37 37 | msg = "hello"
38 38 |
@@ -145,7 +145,7 @@ EM.py:51:28: EM101 [*] Exception must not use a string literal, assign to variab
|
= help: Assign to variable; remove string literal
Suggested fix
Unsafe fix
48 48 |
49 49 | def f_fix_indentation_check(foo):
50 50 | if foo:
@@ -166,7 +166,7 @@ EM.py:54:32: EM102 [*] Exception must not use an f-string literal, assign to var
|
= help: Assign to variable; remove f-string literal
Suggested fix
Unsafe fix
51 51 | raise RuntimeError("This is an example exception")
52 52 | else:
53 53 | if foo == "foo":
@@ -186,7 +186,7 @@ EM.py:55:24: EM103 [*] Exception must not use a `.format()` string directly, ass
|
= help: Assign to variable; remove `.format()` string
Suggested fix
Unsafe fix
52 52 | else:
53 53 | if foo == "foo":
54 54 | raise RuntimeError(f"This is an exception: {foo}")
@@ -215,4 +215,114 @@ EM.py:60:35: EM101 Exception must not use a string literal, assign to variable f
|
= help: Assign to variable; remove string literal
EM.py:64:24: EM102 [*] Exception must not use an f-string literal, assign to variable first
|
63 | def f_triple_quoted_string():
64 | raise RuntimeError(f"""This is an {"example"} exception""")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
|
= help: Assign to variable; remove f-string literal
Unsafe fix
61 61 |
62 62 |
63 63 | def f_triple_quoted_string():
64 |- raise RuntimeError(f"""This is an {"example"} exception""")
64 |+ msg = f"""This is an {"example"} exception"""
65 |+ raise RuntimeError(msg)
65 66 |
66 67 |
67 68 | def f_multi_line_string():
EM.py:69:9: EM101 [*] Exception must not use a string literal, assign to variable first
|
67 | def f_multi_line_string():
68 | raise RuntimeError(
69 | "first"
| _________^
70 | | "second"
| |________________^ EM101
71 | )
|
= help: Assign to variable; remove string literal
Unsafe fix
65 65 |
66 66 |
67 67 | def f_multi_line_string():
68 |- raise RuntimeError(
68 |+ msg = (
69 69 | "first"
70 70 | "second"
71 71 | )
72 |+ raise RuntimeError(
73 |+ msg
74 |+ )
72 75 |
73 76 |
74 77 | def f_multi_line_string2():
EM.py:76:9: EM103 [*] Exception must not use a `.format()` string directly, assign to variable first
|
74 | def f_multi_line_string2():
75 | raise RuntimeError(
76 | "This is an {example} exception".format(
| _________^
77 | | example="example"
78 | | )
| |_________^ EM103
79 | )
|
= help: Assign to variable; remove `.format()` string
Unsafe fix
72 72 |
73 73 |
74 74 | def f_multi_line_string2():
75 |- raise RuntimeError(
75 |+ msg = (
76 76 | "This is an {example} exception".format(
77 77 | example="example"
78 78 | )
79 79 | )
80 |+ raise RuntimeError(
81 |+ msg
82 |+ )
80 83 |
81 84 |
82 85 | def f_multi_line_string2():
EM.py:84:9: EM103 [*] Exception must not use a `.format()` string directly, assign to variable first
|
82 | def f_multi_line_string2():
83 | raise RuntimeError(
84 | (
| _________^
85 | | "This is an "
86 | | "{example} exception"
87 | | ).format(
88 | | example="example"
89 | | )
| |_________^ EM103
90 | )
|
= help: Assign to variable; remove `.format()` string
Unsafe fix
80 80 |
81 81 |
82 82 | def f_multi_line_string2():
83 |- raise RuntimeError(
83 |+ msg = (
84 84 | (
85 85 | "This is an "
86 86 | "{example} exception"
--------------------------------------------------------------------------------
88 88 | example="example"
89 89 | )
90 90 | )
91 |+ raise RuntimeError(
92 |+ msg
93 |+ )

View File

@@ -8,7 +8,7 @@ EXE004_1.py:1:1: EXE004 [*] Avoid whitespace before shebang
|
= help: Remove whitespace before shebang
Fix
Safe fix
1 |- #!/usr/bin/python
1 |+#!/usr/bin/python

View File

@@ -9,7 +9,7 @@ EXE004_4.py:1:1: EXE004 [*] Avoid whitespace before shebang
|
= help: Remove whitespace before shebang
Fix
Safe fix
1 |-
2 |- #!/usr/bin/env python
1 |+#!/usr/bin/env python

View File

@@ -10,7 +10,7 @@ ISC.py:1:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
1 |-_ = "a" "b" "c"
1 |+_ = "ab" "c"
2 2 |
@@ -26,7 +26,7 @@ ISC.py:1:9: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
1 |-_ = "a" "b" "c"
1 |+_ = "a" "bc"
2 2 |
@@ -44,7 +44,7 @@ ISC.py:38:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
35 35 | b"def"
36 36 | )
37 37 |
@@ -68,7 +68,7 @@ ISC.py:40:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
38 38 | _ = """a""" """b"""
39 39 |
40 40 | _ = """a
@@ -89,7 +89,7 @@ ISC.py:44:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
41 41 | b""" """c
42 42 | d"""
43 43 |
@@ -143,7 +143,7 @@ ISC.py:52:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
49 49 |
50 50 | _ = 'a' "b"
51 51 |
@@ -163,7 +163,7 @@ ISC.py:64:10: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
61 61 | _ = foo + "abc" + bar
62 62 |
63 63 | # Multiple strings nested inside a f-string
@@ -183,7 +183,7 @@ ISC.py:64:14: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
61 61 | _ = foo + "abc" + bar
62 62 |
63 63 | # Multiple strings nested inside a f-string
@@ -204,7 +204,7 @@ ISC.py:65:14: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
62 62 |
63 63 | # Multiple strings nested inside a f-string
64 64 | _ = f"a {'b' 'c' 'd'} e"
@@ -244,7 +244,7 @@ ISC.py:72:14: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
69 69 | } jkl"""
70 70 |
71 71 | # Nested f-strings
@@ -265,7 +265,7 @@ ISC.py:73:10: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
70 70 |
71 71 | # Nested f-strings
72 72 | _ = "a" f"b {f"c" f"d"} e" "f"
@@ -286,7 +286,7 @@ ISC.py:73:20: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
70 70 |
71 71 | # Nested f-strings
72 72 | _ = "a" f"b {f"c" f"d"} e" "f"

View File

@@ -10,7 +10,7 @@ ISC.py:1:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
1 |-_ = "a" "b" "c"
1 |+_ = "ab" "c"
2 2 |
@@ -26,7 +26,7 @@ ISC.py:1:9: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
1 |-_ = "a" "b" "c"
1 |+_ = "a" "bc"
2 2 |
@@ -44,7 +44,7 @@ ISC.py:38:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
35 35 | b"def"
36 36 | )
37 37 |
@@ -68,7 +68,7 @@ ISC.py:40:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
38 38 | _ = """a""" """b"""
39 39 |
40 40 | _ = """a
@@ -89,7 +89,7 @@ ISC.py:44:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
41 41 | b""" """c
42 42 | d"""
43 43 |
@@ -143,7 +143,7 @@ ISC.py:52:5: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
49 49 |
50 50 | _ = 'a' "b"
51 51 |
@@ -163,7 +163,7 @@ ISC.py:64:10: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
61 61 | _ = foo + "abc" + bar
62 62 |
63 63 | # Multiple strings nested inside a f-string
@@ -183,7 +183,7 @@ ISC.py:64:14: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
61 61 | _ = foo + "abc" + bar
62 62 |
63 63 | # Multiple strings nested inside a f-string
@@ -204,7 +204,7 @@ ISC.py:65:14: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
62 62 |
63 63 | # Multiple strings nested inside a f-string
64 64 | _ = f"a {'b' 'c' 'd'} e"
@@ -244,7 +244,7 @@ ISC.py:72:14: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
69 69 | } jkl"""
70 70 |
71 71 | # Nested f-strings
@@ -265,7 +265,7 @@ ISC.py:73:10: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
70 70 |
71 71 | # Nested f-strings
72 72 | _ = "a" f"b {f"c" f"d"} e" "f"
@@ -286,7 +286,7 @@ ISC.py:73:20: ISC001 [*] Implicitly concatenated string literals on one line
|
= help: Combine string literals
Fix
Safe fix
70 70 |
71 71 | # Nested f-strings
72 72 | _ = "a" f"b {f"c" f"d"} e" "f"

View File

@@ -11,7 +11,7 @@ defaults.py:6:12: ICN001 [*] `altair` should be imported as `alt`
|
= help: Alias `altair` to `alt`
Suggested fix
Unsafe fix
3 3 |
4 4 |
5 5 | def unconventional():
@@ -43,7 +43,7 @@ defaults.py:8:12: ICN001 [*] `numpy` should be imported as `np`
|
= help: Alias `numpy` to `np`
Suggested fix
Unsafe fix
5 5 | def unconventional():
6 6 | import altair
7 7 | import matplotlib.pyplot
@@ -64,7 +64,7 @@ defaults.py:9:12: ICN001 [*] `pandas` should be imported as `pd`
|
= help: Alias `pandas` to `pd`
Suggested fix
Unsafe fix
6 6 | import altair
7 7 | import matplotlib.pyplot
8 8 | import numpy
@@ -85,7 +85,7 @@ defaults.py:10:12: ICN001 [*] `seaborn` should be imported as `sns`
|
= help: Alias `seaborn` to `sns`
Suggested fix
Unsafe fix
7 7 | import matplotlib.pyplot
8 8 | import numpy
9 9 | import pandas
@@ -105,7 +105,7 @@ defaults.py:11:12: ICN001 [*] `tkinter` should be imported as `tk`
|
= help: Alias `tkinter` to `tk`
Suggested fix
Unsafe fix
8 8 | import numpy
9 9 | import pandas
10 10 | import seaborn
@@ -124,7 +124,7 @@ defaults.py:12:12: ICN001 [*] `networkx` should be imported as `nx`
|
= help: Alias `networkx` to `nx`
Suggested fix
Unsafe fix
9 9 | import pandas
10 10 | import seaborn
11 11 | import tkinter
@@ -144,7 +144,7 @@ defaults.py:16:22: ICN001 [*] `altair` should be imported as `alt`
|
= help: Alias `altair` to `alt`
Suggested fix
Unsafe fix
13 13 |
14 14 |
15 15 | def unconventional_aliases():
@@ -165,7 +165,7 @@ defaults.py:17:33: ICN001 [*] `matplotlib.pyplot` should be imported as `plt`
|
= help: Alias `matplotlib.pyplot` to `plt`
Suggested fix
Unsafe fix
14 14 |
15 15 | def unconventional_aliases():
16 16 | import altair as altr
@@ -186,7 +186,7 @@ defaults.py:18:21: ICN001 [*] `numpy` should be imported as `np`
|
= help: Alias `numpy` to `np`
Suggested fix
Unsafe fix
15 15 | def unconventional_aliases():
16 16 | import altair as altr
17 17 | import matplotlib.pyplot as plot
@@ -207,7 +207,7 @@ defaults.py:19:22: ICN001 [*] `pandas` should be imported as `pd`
|
= help: Alias `pandas` to `pd`
Suggested fix
Unsafe fix
16 16 | import altair as altr
17 17 | import matplotlib.pyplot as plot
18 18 | import numpy as nmp
@@ -228,7 +228,7 @@ defaults.py:20:23: ICN001 [*] `seaborn` should be imported as `sns`
|
= help: Alias `seaborn` to `sns`
Suggested fix
Unsafe fix
17 17 | import matplotlib.pyplot as plot
18 18 | import numpy as nmp
19 19 | import pandas as pdas
@@ -248,7 +248,7 @@ defaults.py:21:23: ICN001 [*] `tkinter` should be imported as `tk`
|
= help: Alias `tkinter` to `tk`
Suggested fix
Unsafe fix
18 18 | import numpy as nmp
19 19 | import pandas as pdas
20 20 | import seaborn as sbrn
@@ -269,7 +269,7 @@ defaults.py:22:24: ICN001 [*] `networkx` should be imported as `nx`
|
= help: Alias `networkx` to `nx`
Suggested fix
Unsafe fix
19 19 | import pandas as pdas
20 20 | import seaborn as sbrn
21 21 | import tkinter as tkr

View File

@@ -12,7 +12,7 @@ tricky.py:7:16: ICN001 [*] `pandas` should be imported as `pd`
|
= help: Alias `pandas` to `pd`
Suggested fix
Unsafe fix
3 3 |
4 4 | def rename_global():
5 5 | try:

View File

@@ -12,7 +12,7 @@ LOG001.py:3:1: LOG001 [*] Use `logging.getLogger()` to instantiate loggers
|
= help: Replace with `logging.getLogger()`
Suggested fix
Unsafe fix
1 1 | import logging
2 2 |
3 |-logging.Logger(__name__)
@@ -29,7 +29,7 @@ LOG001.py:4:1: LOG001 [*] Use `logging.getLogger()` to instantiate loggers
|
= help: Replace with `logging.getLogger()`
Suggested fix
Unsafe fix
1 1 | import logging
2 2 |
3 3 | logging.Logger(__name__)

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