Compare commits

..

1 Commits

Author SHA1 Message Date
Zanie
105fb1c682 Refactor ecosystem checks into module 2023-10-23 11:55:14 -05:00
128 changed files with 1388 additions and 1161 deletions

22
Cargo.lock generated
View File

@@ -2259,7 +2259,6 @@ dependencies = [
"proc-macro2",
"quote",
"ruff_python_trivia",
"serde_derive_internals 0.29.0",
"syn 2.0.38",
]
@@ -2625,7 +2624,7 @@ checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals 0.26.0",
"serde_derive_internals",
"syn 1.0.109",
]
@@ -2665,9 +2664,9 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
[[package]]
name = "serde"
version = "1.0.189"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [
"serde_derive",
]
@@ -2685,9 +2684,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.189"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
@@ -2705,17 +2704,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "serde_derive_internals"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "serde_json"
version = "1.0.107"

View File

@@ -34,7 +34,7 @@ quote = { version = "1.0.23" }
regex = { version = "1.10.2" }
rustc-hash = { version = "1.1.0" }
schemars = { version = "0.8.15" }
serde = { version = "1.0.189", features = ["derive"] }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.107" }
shellexpand = { version = "3.0.0" }
similar = { version = "2.3.0", features = ["inline"] }

View File

@@ -17,8 +17,8 @@ use ruff_linter::settings::DEFAULT_SELECTORS;
use ruff_linter::warn_user;
use ruff_workspace::options::{
Flake8AnnotationsOptions, Flake8BugbearOptions, Flake8BuiltinsOptions, Flake8ErrMsgOptions,
Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8TidyImportsOptions, LintCommonOptions,
LintOptions, McCabeOptions, Options, Pep8NamingOptions, PydocstyleOptions,
Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8TidyImportsOptions, LintOptions,
McCabeOptions, Options, Pep8NamingOptions, PydocstyleOptions,
};
use ruff_workspace::pyproject::Pyproject;
@@ -99,7 +99,7 @@ pub(crate) fn convert(
// Parse each supported option.
let mut options = Options::default();
let mut lint_options = LintCommonOptions::default();
let mut lint_options = LintOptions::default();
let mut flake8_annotations = Flake8AnnotationsOptions::default();
let mut flake8_bugbear = Flake8BugbearOptions::default();
let mut flake8_builtins = Flake8BuiltinsOptions::default();
@@ -433,11 +433,8 @@ pub(crate) fn convert(
}
}
if lint_options != LintCommonOptions::default() {
options.lint = Some(LintOptions {
common: lint_options,
..LintOptions::default()
});
if lint_options != LintOptions::default() {
options.lint = Some(lint_options);
}
// Create the pyproject.toml.
@@ -468,9 +465,7 @@ mod tests {
use ruff_linter::rules::flake8_quotes;
use ruff_linter::rules::pydocstyle::settings::Convention;
use ruff_linter::settings::types::PythonVersion;
use ruff_workspace::options::{
Flake8QuotesOptions, LintCommonOptions, LintOptions, Options, PydocstyleOptions,
};
use ruff_workspace::options::{Flake8QuotesOptions, LintOptions, Options, PydocstyleOptions};
use ruff_workspace::pyproject::Pyproject;
use crate::converter::DEFAULT_SELECTORS;
@@ -480,8 +475,8 @@ mod tests {
use super::super::plugin::Plugin;
use super::convert;
fn lint_default_options(plugins: impl IntoIterator<Item = RuleSelector>) -> LintCommonOptions {
LintCommonOptions {
fn lint_default_options(plugins: impl IntoIterator<Item = RuleSelector>) -> LintOptions {
LintOptions {
ignore: Some(vec![]),
select: Some(
DEFAULT_SELECTORS
@@ -491,7 +486,7 @@ mod tests {
.sorted_by_key(RuleSelector::prefix_and_code)
.collect(),
),
..LintCommonOptions::default()
..LintOptions::default()
}
}
@@ -503,10 +498,7 @@ mod tests {
None,
);
let expected = Pyproject::new(Options {
lint: Some(LintOptions {
common: lint_default_options([]),
..LintOptions::default()
}),
lint: Some(lint_default_options([])),
..Options::default()
});
assert_eq!(actual, expected);
@@ -524,10 +516,7 @@ mod tests {
);
let expected = Pyproject::new(Options {
line_length: Some(LineLength::try_from(100).unwrap()),
lint: Some(LintOptions {
common: lint_default_options([]),
..LintOptions::default()
}),
lint: Some(lint_default_options([])),
..Options::default()
});
assert_eq!(actual, expected);
@@ -545,10 +534,7 @@ mod tests {
);
let expected = Pyproject::new(Options {
line_length: Some(LineLength::try_from(100).unwrap()),
lint: Some(LintOptions {
common: lint_default_options([]),
..LintOptions::default()
}),
lint: Some(lint_default_options([])),
..Options::default()
});
assert_eq!(actual, expected);
@@ -565,10 +551,7 @@ mod tests {
Some(vec![]),
);
let expected = Pyproject::new(Options {
lint: Some(LintOptions {
common: lint_default_options([]),
..LintOptions::default()
}),
lint: Some(lint_default_options([])),
..Options::default()
});
assert_eq!(actual, expected);
@@ -586,16 +569,13 @@ mod tests {
);
let expected = Pyproject::new(Options {
lint: Some(LintOptions {
common: LintCommonOptions {
flake8_quotes: Some(Flake8QuotesOptions {
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
multiline_quotes: None,
docstring_quotes: None,
avoid_escape: None,
}),
..lint_default_options([])
},
..LintOptions::default()
flake8_quotes: Some(Flake8QuotesOptions {
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
multiline_quotes: None,
docstring_quotes: None,
avoid_escape: None,
}),
..lint_default_options([])
}),
..Options::default()
});
@@ -617,15 +597,12 @@ mod tests {
);
let expected = Pyproject::new(Options {
lint: Some(LintOptions {
common: LintCommonOptions {
pydocstyle: Some(PydocstyleOptions {
convention: Some(Convention::Numpy),
ignore_decorators: None,
property_decorators: None,
}),
..lint_default_options([Linter::Pydocstyle.into()])
},
..LintOptions::default()
pydocstyle: Some(PydocstyleOptions {
convention: Some(Convention::Numpy),
ignore_decorators: None,
property_decorators: None,
}),
..lint_default_options([Linter::Pydocstyle.into()])
}),
..Options::default()
});
@@ -644,16 +621,13 @@ mod tests {
);
let expected = Pyproject::new(Options {
lint: Some(LintOptions {
common: LintCommonOptions {
flake8_quotes: Some(Flake8QuotesOptions {
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
multiline_quotes: None,
docstring_quotes: None,
avoid_escape: None,
}),
..lint_default_options([Linter::Flake8Quotes.into()])
},
..LintOptions::default()
flake8_quotes: Some(Flake8QuotesOptions {
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
multiline_quotes: None,
docstring_quotes: None,
avoid_escape: None,
}),
..lint_default_options([Linter::Flake8Quotes.into()])
}),
..Options::default()
});
@@ -674,10 +648,7 @@ mod tests {
);
let expected = Pyproject::new(Options {
target_version: Some(PythonVersion::Py38),
lint: Some(LintOptions {
common: lint_default_options([]),
..LintOptions::default()
}),
lint: Some(lint_default_options([])),
..Options::default()
});
assert_eq!(actual, expected);

View File

@@ -366,15 +366,6 @@ pub struct FormatCommand {
respect_gitignore: bool,
#[clap(long, overrides_with("respect_gitignore"), hide = true)]
no_respect_gitignore: bool,
/// List of paths, used to omit files and/or directories from analysis.
#[arg(
long,
value_delimiter = ',',
value_name = "FILE_PATTERN",
help_heading = "File selection"
)]
pub exclude: Option<Vec<FilePattern>>,
/// Enforce exclusions, even for paths passed to Ruff directly on the command-line.
/// Use `--no-force-exclude` to disable.
#[arg(
@@ -395,9 +386,9 @@ pub struct FormatCommand {
#[arg(long, help_heading = "Miscellaneous")]
pub stdin_filename: Option<PathBuf>,
/// Enable preview mode; enables unstable formatting.
/// Enable preview mode; checks will include unstable rules and fixes.
/// Use `--no-preview` to disable.
#[arg(long, overrides_with("no_preview"))]
#[arg(long, overrides_with("no_preview"), hide = true)]
preview: bool,
#[clap(long, overrides_with("preview"), hide = true)]
no_preview: bool,
@@ -531,7 +522,6 @@ impl FormatCommand {
self.respect_gitignore,
self.no_respect_gitignore,
),
exclude: self.exclude,
preview: resolve_bool_arg(self.preview, self.no_preview).map(PreviewMode::from),
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
// Unsupported on the formatter CLI, but required on `Overrides`.
@@ -668,8 +658,6 @@ impl ConfigurationTransformer for CliOverrides {
}
if let Some(preview) = &self.preview {
config.preview = Some(*preview);
config.lint.preview = Some(*preview);
config.format.preview = Some(*preview);
}
if let Some(per_file_ignores) = &self.per_file_ignores {
config.lint.per_file_ignores = Some(collect_per_file_ignores(per_file_ignores.clone()));

View File

@@ -10,7 +10,7 @@ use ruff_linter::linter::add_noqa_to_path;
use ruff_linter::source_kind::SourceKind;
use ruff_linter::warn_user_once;
use ruff_python_ast::{PySourceType, SourceType};
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig, ResolvedFile};
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig};
use crate::args::CliOverrides;
@@ -36,7 +36,7 @@ pub(crate) fn add_noqa(
&paths
.iter()
.flatten()
.map(ResolvedFile::path)
.map(ignore::DirEntry::path)
.collect::<Vec<_>>(),
pyproject_config,
);
@@ -45,15 +45,14 @@ pub(crate) fn add_noqa(
let modifications: usize = paths
.par_iter()
.flatten()
.filter_map(|resolved_file| {
.filter_map(|entry| {
let path = entry.path();
let SourceType::Python(source_type @ (PySourceType::Python | PySourceType::Stub)) =
SourceType::from(resolved_file.path())
SourceType::from(path)
else {
return None;
};
let path = resolved_file.path();
let package = resolved_file
.path()
let package = path
.parent()
.and_then(|parent| package_roots.get(parent))
.and_then(|package| *package);

View File

@@ -22,10 +22,7 @@ use ruff_linter::{fs, warn_user_once, IOError};
use ruff_python_ast::imports::ImportMap;
use ruff_source_file::SourceFileBuilder;
use ruff_text_size::{TextRange, TextSize};
use ruff_workspace::resolver::{
match_exclusion, python_files_in_path, PyprojectConfig, PyprojectDiscoveryStrategy,
ResolvedFile,
};
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig, PyprojectDiscoveryStrategy};
use crate::args::CliOverrides;
use crate::cache::{self, Cache};
@@ -45,7 +42,8 @@ pub(crate) fn check(
// Collect all the Python files to check.
let start = Instant::now();
let (paths, resolver) = python_files_in_path(files, pyproject_config, overrides)?;
debug!("Identified files to lint in: {:?}", start.elapsed());
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
if paths.is_empty() {
warn_user_once!("No Python files found under the given path(s)");
@@ -79,7 +77,7 @@ pub(crate) fn check(
&paths
.iter()
.flatten()
.map(ResolvedFile::path)
.map(ignore::DirEntry::path)
.collect::<Vec<_>>(),
pyproject_config,
);
@@ -100,114 +98,95 @@ pub(crate) fn check(
});
let start = Instant::now();
let diagnostics_per_file = paths.par_iter().filter_map(|resolved_file| {
let result = match resolved_file {
Ok(resolved_file) => {
let path = resolved_file.path();
let package = path
.parent()
.and_then(|parent| package_roots.get(parent))
.and_then(|package| *package);
let mut diagnostics: Diagnostics = paths
.par_iter()
.map(|entry| {
match entry {
Ok(entry) => {
let path = entry.path();
let package = path
.parent()
.and_then(|parent| package_roots.get(parent))
.and_then(|package| *package);
let settings = resolver.resolve(path, pyproject_config);
let settings = resolver.resolve(path, pyproject_config);
if !resolved_file.is_root()
&& match_exclusion(
resolved_file.path(),
resolved_file.file_name(),
&settings.linter.exclude,
)
{
return None;
}
let cache_root = package.unwrap_or_else(|| path.parent().unwrap_or(path));
let cache = caches.as_ref().and_then(|caches| {
if let Some(cache) = caches.get(&cache_root) {
Some(cache)
} else {
debug!("No cache found for {}", cache_root.display());
None
}
});
lint_path(
path,
package,
&settings.linter,
cache,
noqa,
fix_mode,
unsafe_fixes,
)
.map_err(|e| {
(Some(path.to_path_buf()), {
let mut error = e.to_string();
for cause in e.chain() {
write!(&mut error, "\n Cause: {cause}").unwrap();
let cache_root = package.unwrap_or_else(|| path.parent().unwrap_or(path));
let cache = caches.as_ref().and_then(|caches| {
if let Some(cache) = caches.get(&cache_root) {
Some(cache)
} else {
debug!("No cache found for {}", cache_root.display());
None
}
error
})
})
}
Err(e) => Err((
if let Error::WithPath { path, .. } = e {
Some(path.clone())
} else {
None
},
e.io_error()
.map_or_else(|| e.to_string(), io::Error::to_string),
)),
};
});
Some(result.unwrap_or_else(|(path, message)| {
if let Some(path) = &path {
let settings = resolver.resolve(path, pyproject_config);
if settings.linter.rules.enabled(Rule::IOError) {
let dummy =
SourceFileBuilder::new(path.to_string_lossy().as_ref(), "").finish();
Diagnostics::new(
vec![Message::from_diagnostic(
Diagnostic::new(IOError { message }, TextRange::default()),
dummy,
TextSize::default(),
)],
ImportMap::default(),
FxHashMap::default(),
lint_path(
path,
package,
&settings.linter,
cache,
noqa,
fix_mode,
unsafe_fixes,
)
.map_err(|e| {
(Some(path.to_owned()), {
let mut error = e.to_string();
for cause in e.chain() {
write!(&mut error, "\n Cause: {cause}").unwrap();
}
error
})
})
}
Err(e) => Err((
if let Error::WithPath { path, .. } = e {
Some(path.clone())
} else {
None
},
e.io_error()
.map_or_else(|| e.to_string(), io::Error::to_string),
)),
}
.unwrap_or_else(|(path, message)| {
if let Some(path) = &path {
let settings = resolver.resolve(path, pyproject_config);
if settings.linter.rules.enabled(Rule::IOError) {
let dummy =
SourceFileBuilder::new(path.to_string_lossy().as_ref(), "").finish();
Diagnostics::new(
vec![Message::from_diagnostic(
Diagnostic::new(IOError { message }, TextRange::default()),
dummy,
TextSize::default(),
)],
ImportMap::default(),
FxHashMap::default(),
)
} else {
warn!(
"{}{}{} {message}",
"Failed to lint ".bold(),
fs::relativize_path(path).bold(),
":".bold()
);
Diagnostics::default()
}
} else {
warn!(
"{}{}{} {message}",
"Failed to lint ".bold(),
fs::relativize_path(path).bold(),
":".bold()
);
warn!("{} {message}", "Encountered error:".bold());
Diagnostics::default()
}
} else {
warn!("{} {message}", "Encountered error:".bold());
Diagnostics::default()
}
}))
});
})
})
.reduce(Diagnostics::default, |mut acc, item| {
acc += item;
acc
});
// Aggregate the diagnostics of all checked files and count the checked files.
// This can't be a regular for loop because we use `par_iter`.
let (mut all_diagnostics, checked_files) = diagnostics_per_file
.fold(
|| (Diagnostics::default(), 0u64),
|(all_diagnostics, checked_files), file_diagnostics| {
(all_diagnostics + file_diagnostics, checked_files + 1)
},
)
.reduce(
|| (Diagnostics::default(), 0u64),
|a, b| (a.0 + b.0, a.1 + b.1),
);
all_diagnostics.messages.sort();
diagnostics.messages.sort();
// Store the caches.
if let Some(caches) = caches {
@@ -217,9 +196,9 @@ pub(crate) fn check(
}
let duration = start.elapsed();
debug!("Checked {:?} files in: {:?}", checked_files, duration);
debug!("Checked {:?} files in: {:?}", paths.len(), duration);
Ok(all_diagnostics)
Ok(diagnostics)
}
/// Wraps [`lint_path`](crate::diagnostics::lint_path) in a [`catch_unwind`](std::panic::catch_unwind) and emits

View File

@@ -4,7 +4,7 @@ use anyhow::Result;
use ruff_linter::packaging;
use ruff_linter::settings::flags;
use ruff_workspace::resolver::{match_exclusion, python_file_at_path, PyprojectConfig};
use ruff_workspace::resolver::{python_file_at_path, PyprojectConfig};
use crate::args::CliOverrides;
use crate::diagnostics::{lint_stdin, Diagnostics};
@@ -22,14 +22,6 @@ pub(crate) fn check_stdin(
if !python_file_at_path(filename, pyproject_config, overrides)? {
return Ok(Diagnostics::default());
}
let lint_settings = &pyproject_config.settings.linter;
if filename
.file_name()
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
{
return Ok(Diagnostics::default());
}
}
let package_root = filename.and_then(Path::parent).and_then(|path| {
packaging::detect_package_root(path, &pyproject_config.settings.linter.namespace_packages)

View File

@@ -20,7 +20,7 @@ use ruff_linter::warn_user_once;
use ruff_python_ast::{PySourceType, SourceType};
use ruff_python_formatter::{format_module_source, FormatModuleError};
use ruff_text_size::{TextLen, TextRange, TextSize};
use ruff_workspace::resolver::{match_exclusion, python_files_in_path};
use ruff_workspace::resolver::python_files_in_path;
use ruff_workspace::FormatterSettings;
use crate::args::{CliOverrides, FormatArguments};
@@ -61,42 +61,26 @@ pub(crate) fn format(
}
let start = Instant::now();
let (mut results, errors): (Vec<_>, Vec<_>) = paths
let (results, errors): (Vec<_>, Vec<_>) = paths
.into_par_iter()
.filter_map(|entry| {
match entry {
Ok(resolved_file) => {
let path = resolved_file.path();
Ok(entry) => {
let path = entry.into_path();
let SourceType::Python(source_type) = SourceType::from(&path) else {
// Ignore any non-Python files.
return None;
};
let resolved_settings = resolver.resolve(path, &pyproject_config);
// Ignore files that are excluded from formatting
if !resolved_file.is_root()
&& match_exclusion(
path,
resolved_file.file_name(),
&resolved_settings.formatter.exclude,
)
{
return None;
}
let resolved_settings = resolver.resolve(&path, &pyproject_config);
Some(
match catch_unwind(|| {
format_path(path, &resolved_settings.formatter, source_type, mode)
format_path(&path, &resolved_settings.formatter, source_type, mode)
}) {
Ok(inner) => inner.map(|result| FormatPathResult {
path: resolved_file.into_path(),
result,
}),
Err(error) => Err(FormatCommandError::Panic(
Some(resolved_file.into_path()),
error,
)),
Ok(inner) => inner.map(|result| FormatPathResult { path, result }),
Err(error) => Err(FormatCommandError::Panic(Some(path), error)),
},
)
}
@@ -120,8 +104,6 @@ pub(crate) fn format(
error!("{error}");
}
results.sort_unstable_by(|a, b| a.path.cmp(&b.path));
let summary = FormatSummary::new(results.as_slice(), mode);
// Report on the formatting changes.
@@ -155,7 +137,7 @@ pub(crate) fn format(
}
/// Format the file at the given [`Path`].
#[tracing::instrument(level="debug", skip_all, fields(path = %path.display()))]
#[tracing::instrument(skip_all, fields(path = %path.display()))]
fn format_path(
path: &Path,
settings: &FormatterSettings,

View File

@@ -6,7 +6,7 @@ use log::error;
use ruff_linter::source_kind::SourceKind;
use ruff_python_ast::{PySourceType, SourceType};
use ruff_workspace::resolver::{match_exclusion, python_file_at_path};
use ruff_workspace::resolver::python_file_at_path;
use ruff_workspace::FormatterSettings;
use crate::args::{CliOverrides, FormatArguments};
@@ -33,14 +33,6 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
if !python_file_at_path(filename, &pyproject_config, overrides)? {
return Ok(ExitStatus::Success);
}
let format_settings = &pyproject_config.settings.formatter;
if filename
.file_name()
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
{
return Ok(ExitStatus::Success);
}
}
let path = cli.stdin_filename.as_deref();

View File

@@ -5,7 +5,7 @@ use anyhow::Result;
use itertools::Itertools;
use ruff_linter::warn_user_once;
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig, ResolvedFile};
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig};
use crate::args::CliOverrides;
@@ -25,13 +25,12 @@ pub(crate) fn show_files(
}
// Print the list of files.
for path in paths
.into_iter()
for entry in paths
.iter()
.flatten()
.map(ResolvedFile::into_path)
.sorted_unstable()
.sorted_by(|a, b| a.path().cmp(b.path()))
{
writeln!(writer, "{}", path.to_string_lossy())?;
writeln!(writer, "{}", entry.path().to_string_lossy())?;
}
Ok(())

View File

@@ -4,7 +4,7 @@ use std::path::PathBuf;
use anyhow::{bail, Result};
use itertools::Itertools;
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig, ResolvedFile};
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig};
use crate::args::CliOverrides;
@@ -19,17 +19,16 @@ pub(crate) fn show_settings(
let (paths, resolver) = python_files_in_path(files, pyproject_config, overrides)?;
// Print the list of files.
let Some(path) = paths
.into_iter()
let Some(entry) = paths
.iter()
.flatten()
.map(ResolvedFile::into_path)
.sorted_unstable()
.sorted_by(|a, b| a.path().cmp(b.path()))
.next()
else {
bail!("No files found under the given path");
};
let settings = resolver.resolve(&path, pyproject_config);
let path = entry.path();
let settings = resolver.resolve(path, pyproject_config);
writeln!(writer, "Resolved settings for: {path:?}")?;
if let Some(settings_path) = pyproject_config.path.as_ref() {

View File

@@ -2,7 +2,7 @@
use std::fs::File;
use std::io;
use std::ops::{Add, AddAssign};
use std::ops::AddAssign;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
@@ -11,6 +11,7 @@ use anyhow::{Context, Result};
use colored::Colorize;
use filetime::FileTime;
use log::{debug, error, warn};
use ruff_linter::settings::types::UnsafeFixes;
use rustc_hash::FxHashMap;
use ruff_diagnostics::Diagnostic;
@@ -19,7 +20,6 @@ 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::{flags, LinterSettings};
use ruff_linter::source_kind::{SourceError, SourceKind};
use ruff_linter::{fs, IOError, SyntaxError};
@@ -61,7 +61,7 @@ impl FileCacheKey {
#[derive(Debug, Default, PartialEq)]
pub(crate) struct Diagnostics {
pub(crate) messages: Vec<Message>,
pub(crate) fixed: FixMap,
pub(crate) fixed: FxHashMap<String, FixTable>,
pub(crate) imports: ImportMap,
pub(crate) notebook_indexes: FxHashMap<String, NotebookIndex>,
}
@@ -74,7 +74,7 @@ impl Diagnostics {
) -> Self {
Self {
messages,
fixed: FixMap::default(),
fixed: FxHashMap::default(),
imports,
notebook_indexes,
}
@@ -142,68 +142,22 @@ impl Diagnostics {
}
}
impl Add for Diagnostics {
type Output = Diagnostics;
fn add(mut self, other: Self) -> Self::Output {
self += other;
self
}
}
impl AddAssign for Diagnostics {
fn add_assign(&mut self, other: Self) {
self.messages.extend(other.messages);
self.imports.extend(other.imports);
self.fixed += other.fixed;
self.notebook_indexes.extend(other.notebook_indexes);
}
}
/// A collection of fixes indexed by file path.
#[derive(Debug, Default, PartialEq)]
pub(crate) struct FixMap(FxHashMap<String, FixTable>);
impl FixMap {
/// Returns `true` if there are no fixes in the map.
pub(crate) fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Returns an iterator over the fixes in the map, along with the file path.
pub(crate) fn iter(&self) -> impl Iterator<Item = (&String, &FixTable)> {
self.0.iter()
}
/// Returns an iterator over the fixes in the map.
pub(crate) fn values(&self) -> impl Iterator<Item = &FixTable> {
self.0.values()
}
}
impl FromIterator<(String, FixTable)> for FixMap {
fn from_iter<T: IntoIterator<Item = (String, FixTable)>>(iter: T) -> Self {
Self(
iter.into_iter()
.filter(|(_, fixes)| !fixes.is_empty())
.collect(),
)
}
}
impl AddAssign for FixMap {
fn add_assign(&mut self, rhs: Self) {
for (filename, fixed) in rhs.0 {
for (filename, fixed) in other.fixed {
if fixed.is_empty() {
continue;
}
let fixed_in_file = self.0.entry(filename).or_default();
let fixed_in_file = self.fixed.entry(filename).or_default();
for (rule, count) in fixed {
if count > 0 {
*fixed_in_file.entry(rule).or_default() += count;
}
}
}
self.notebook_indexes.extend(other.notebook_indexes);
}
}
@@ -364,7 +318,7 @@ pub(crate) fn lint_path(
Ok(Diagnostics {
messages,
fixed: FixMap::from_iter([(fs::relativize_path(path), fixed)]),
fixed: FxHashMap::from_iter([(fs::relativize_path(path), fixed)]),
imports,
notebook_indexes,
})
@@ -482,7 +436,7 @@ pub(crate) fn lint_stdin(
Ok(Diagnostics {
messages,
fixed: FixMap::from_iter([(
fixed: FxHashMap::from_iter([(
fs::relativize_path(path.unwrap_or_else(|| Path::new("-"))),
fixed,
)]),

View File

@@ -7,9 +7,11 @@ use anyhow::Result;
use bitflags::bitflags;
use colored::Colorize;
use itertools::{iterate, Itertools};
use rustc_hash::FxHashMap;
use serde::Serialize;
use ruff_linter::fs::relativize_path;
use ruff_linter::linter::FixTable;
use ruff_linter::logging::LogLevel;
use ruff_linter::message::{
AzureEmitter, Emitter, EmitterContext, GithubEmitter, GitlabEmitter, GroupedEmitter,
@@ -20,7 +22,7 @@ use ruff_linter::registry::{AsRule, Rule};
use ruff_linter::settings::flags::{self};
use ruff_linter::settings::types::{SerializationFormat, UnsafeFixes};
use crate::diagnostics::{Diagnostics, FixMap};
use crate::diagnostics::Diagnostics;
bitflags! {
#[derive(Default, Debug, Copy, Clone)]
@@ -460,7 +462,7 @@ fn show_fix_status(fix_mode: flags::FixMode, fixables: Option<&FixableStatistics
(!fix_mode.is_apply()) && fixables.is_some_and(FixableStatistics::any_applicable_fixes)
}
fn print_fix_summary(writer: &mut dyn Write, fixed: &FixMap) -> Result<()> {
fn print_fix_summary(writer: &mut dyn Write, fixed: &FxHashMap<String, FixTable>) -> Result<()> {
let total = fixed
.values()
.map(|table| table.values().sum::<usize>())

View File

@@ -13,7 +13,7 @@ const BIN_NAME: &str = "ruff";
#[test]
fn default_options() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["format", "--isolated", "--stdin-filename", "test.py"])
.args(["format", "--isolated"])
.arg("-")
.pass_stdin(r#"
def foo(arg1, arg2,):
@@ -50,9 +50,6 @@ fn format_options() -> Result<()> {
fs::write(
&ruff_toml,
r#"
tab-size = 8
line-length = 84
[format]
indent-style = "tab"
quote-style = "single"
@@ -67,7 +64,7 @@ line-ending = "cr-lf"
.arg("-")
.pass_stdin(r#"
def foo(arg1, arg2,):
print("Shouldn't change quotes. It exceeds the line width with the tab size 8")
print("Shouldn't change quotes")
if condition:
@@ -79,9 +76,7 @@ if condition:
exit_code: 0
----- stdout -----
def foo(arg1, arg2):
print(
"Shouldn't change quotes. It exceeds the line width with the tab size 8"
)
print("Shouldn't change quotes")
if condition:
@@ -93,108 +88,6 @@ if condition:
Ok(())
}
#[test]
fn exclude() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
extend-exclude = ["out"]
[format]
exclude = ["test.py", "generated.py"]
"#,
)?;
fs::write(
tempdir.path().join("main.py"),
r#"
from test import say_hy
if __name__ == "__main__":
say_hy("dear Ruff contributor")
"#,
)?;
// Excluded file but passed to the CLI directly, should be formatted
let test_path = tempdir.path().join("test.py");
fs::write(
&test_path,
r#"
def say_hy(name: str):
print(f"Hy {name}")"#,
)?;
fs::write(
tempdir.path().join("generated.py"),
r#"NUMBERS = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19
]
OTHER = "OTHER"
"#,
)?;
let out_dir = tempdir.path().join("out");
fs::create_dir(&out_dir)?;
fs::write(out_dir.join("a.py"), "a = a")?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.args(["format", "--check", "--config"])
.arg(ruff_toml.file_name().unwrap())
// Explicitly pass test.py, should be formatted regardless of it being excluded by format.exclude
.arg(test_path.file_name().unwrap())
// Format all other files in the directory, should respect the `exclude` and `format.exclude` options
.arg("."), @r###"
success: false
exit_code: 1
----- stdout -----
Would reformat: main.py
Would reformat: test.py
2 files would be reformatted
----- stderr -----
warning: `ruff format` is not yet stable, and subject to change in future versions.
"###);
Ok(())
}
#[test]
fn exclude_stdin() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
extend-select = ["B", "Q"]
[format]
exclude = ["generated.py"]
"#,
)?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.args(["format", "--config", &ruff_toml.file_name().unwrap().to_string_lossy(), "--stdin-filename", "generated.py", "-"])
.pass_stdin(r#"
from test import say_hy
if __name__ == '__main__':
say_hy("dear Ruff contributor")
"#), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `ruff format` is not yet stable, and subject to change in future versions.
"###);
Ok(())
}
#[test]
fn format_option_inheritance() -> Result<()> {
let tempdir = TempDir::new()?;

View File

@@ -1252,8 +1252,8 @@ fn diff_does_not_show_display_only_fixes_with_unsafe_fixes_enabled() {
])
.pass_stdin("def add_to_list(item, some_list=[]): ..."),
@r###"
success: true
exit_code: 0
success: false
exit_code: 1
----- stdout -----
----- stderr -----
@@ -1276,8 +1276,8 @@ fn diff_only_unsafe_fixes_available() {
])
.pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
@r###"
success: true
exit_code: 0
success: false
exit_code: 1
----- stdout -----
----- stderr -----

View File

@@ -31,15 +31,14 @@ inline-quotes = "single"
.args(STDIN_BASE_OPTIONS)
.arg("--config")
.arg(&ruff_toml)
.args(["--stdin-filename", "test.py"])
.arg("-")
.pass_stdin(r#"a = "abcba".strip("aba")"#), @r###"
success: false
exit_code: 1
----- stdout -----
test.py:1:5: Q000 [*] Double quotes found but single quotes preferred
test.py:1:5: B005 Using `.strip()` with multi-character strings is misleading
test.py:1:19: Q000 [*] Double quotes found but single quotes preferred
-:1:5: Q000 [*] Double quotes found but single quotes preferred
-:1:5: B005 Using `.strip()` with multi-character strings is misleading
-:1:19: Q000 [*] Double quotes found but single quotes preferred
Found 3 errors.
[*] 2 fixable with the `--fix` option.
@@ -156,117 +155,3 @@ inline-quotes = "single"
"###);
Ok(())
}
#[test]
fn exclude() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
extend-select = ["B", "Q"]
extend-exclude = ["out"]
[lint]
exclude = ["test.py", "generated.py"]
[lint.flake8-quotes]
inline-quotes = "single"
"#,
)?;
fs::write(
tempdir.path().join("main.py"),
r#"
from test import say_hy
if __name__ == "__main__":
say_hy("dear Ruff contributor")
"#,
)?;
// Excluded file but passed to the CLI directly, should be linted
let test_path = tempdir.path().join("test.py");
fs::write(
&test_path,
r#"
def say_hy(name: str):
print(f"Hy {name}")"#,
)?;
fs::write(
tempdir.path().join("generated.py"),
r#"NUMBERS = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19
]
OTHER = "OTHER"
"#,
)?;
let out_dir = tempdir.path().join("out");
fs::create_dir(&out_dir)?;
fs::write(out_dir.join("a.py"), r#"a = "a""#)?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.arg("check")
.args(STDIN_BASE_OPTIONS)
.args(["--config", &ruff_toml.file_name().unwrap().to_string_lossy()])
// Explicitly pass test.py, should be linted regardless of it being excluded by lint.exclude
.arg(test_path.file_name().unwrap())
// Lint all other files in the directory, should respect the `exclude` and `lint.exclude` options
.arg("."), @r###"
success: false
exit_code: 1
----- stdout -----
main.py:4:16: Q000 [*] Double quotes found but single quotes preferred
main.py:5:12: Q000 [*] Double quotes found but single quotes preferred
test.py:3:15: Q000 [*] Double quotes found but single quotes preferred
Found 3 errors.
[*] 3 fixable with the `--fix` option.
----- stderr -----
"###);
Ok(())
}
#[test]
fn exclude_stdin() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");
fs::write(
&ruff_toml,
r#"
extend-select = ["B", "Q"]
[lint]
exclude = ["generated.py"]
[lint.flake8-quotes]
inline-quotes = "single"
"#,
)?;
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.current_dir(tempdir.path())
.arg("check")
.args(STDIN_BASE_OPTIONS)
.args(["--config", &ruff_toml.file_name().unwrap().to_string_lossy()])
.args(["--stdin-filename", "generated.py"])
.arg("-")
.pass_stdin(r#"
from test import say_hy
if __name__ == "__main__":
say_hy("dear Ruff contributor")
"#), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
"###);
Ok(())
}

View File

@@ -11,6 +11,7 @@ use std::{fmt, fs, io, iter};
use anyhow::{bail, format_err, Context, Error};
use clap::{CommandFactory, FromArgMatches};
use ignore::DirEntry;
use imara_diff::intern::InternedInput;
use imara_diff::sink::Counter;
use imara_diff::{diff, Algorithm};
@@ -35,14 +36,14 @@ use ruff_linter::settings::types::{FilePattern, FilePatternSet};
use ruff_python_formatter::{
format_module_source, FormatModuleError, MagicTrailingComma, PyFormatOptions,
};
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig, ResolvedFile, Resolver};
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig, Resolver};
/// Find files that ruff would check so we can format them. Adapted from `ruff_cli`.
#[allow(clippy::type_complexity)]
fn ruff_check_paths(
dirs: &[PathBuf],
) -> anyhow::Result<(
Vec<Result<ResolvedFile, ignore::Error>>,
Vec<Result<DirEntry, ignore::Error>>,
Resolver,
PyprojectConfig,
)> {
@@ -466,9 +467,9 @@ fn format_dev_project(
let iter = { paths.into_par_iter() };
#[cfg(feature = "singlethreaded")]
let iter = { paths.into_iter() };
iter.map(|path| {
iter.map(|dir_entry| {
let result = format_dir_entry(
path,
dir_entry,
stability_check,
write,
&black_options,
@@ -526,20 +527,24 @@ fn format_dev_project(
/// Error handling in between walkdir and `format_dev_file`
fn format_dir_entry(
resolved_file: Result<ResolvedFile, ignore::Error>,
dir_entry: Result<DirEntry, ignore::Error>,
stability_check: bool,
write: bool,
options: &BlackOptions,
resolver: &Resolver,
pyproject_config: &PyprojectConfig,
) -> anyhow::Result<(Result<Statistics, CheckFileError>, PathBuf), Error> {
let resolved_file = resolved_file.context("Iterating the files in the repository failed")?;
let dir_entry = match dir_entry.context("Iterating the files in the repository failed") {
Ok(dir_entry) => dir_entry,
Err(err) => return Err(err),
};
let file = dir_entry.path().to_path_buf();
// For some reason it does not filter in the beginning
if resolved_file.file_name() == "pyproject.toml" {
return Ok((Ok(Statistics::default()), resolved_file.into_path()));
if dir_entry.file_name() == "pyproject.toml" {
return Ok((Ok(Statistics::default()), file));
}
let path = resolved_file.into_path();
let path = dir_entry.path().to_path_buf();
let mut options = options.to_py_format_options(&path);
let settings = resolver.resolve(&path, pyproject_config);

View File

@@ -1,7 +1,6 @@
//! Generate a Markdown-compatible listing of configuration options for `pyproject.toml`.
//!
//! Used for <https://docs.astral.sh/ruff/settings/>.
use itertools::Itertools;
use std::fmt::Write;
use ruff_workspace::options::Options;
@@ -108,24 +107,6 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parent_set:
output.push('\n');
output.push_str(&format!("**Type**: `{}`\n", field.value_type));
output.push('\n');
if !field.aliases.is_empty() {
let title = if field.aliases.len() == 1 {
"Alias"
} else {
"Aliases"
};
output.push_str(&format!(
"**{title}**: {}\n",
field
.aliases
.iter()
.map(|alias| format!("`{alias}`"))
.join(", ")
));
output.push('\n');
}
output.push_str(&format!(
"**Example usage**:\n\n```toml\n[tool.ruff{}]\n{}\n```\n",
if let Some(set_name) = parent_set.name() {

View File

@@ -95,7 +95,7 @@ impl std::fmt::Display for IndentStyle {
///
/// Determines the visual width of a tab character (`\t`) and the number of
/// spaces per indent when using [`IndentStyle::Space`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, CacheKey)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct IndentWidth(NonZeroU8);

View File

@@ -10,10 +10,6 @@ def double_quotes_backslash_uppercase():
R"""Sum\\mary."""
def shouldnt_add_raw_here():
"Ruff \U000026a1"
def make_unique_pod_id(pod_id: str) -> str | None:
r"""
Generate a unique Pod name.

View File

@@ -1,17 +0,0 @@
"""Test that type parameters are considered used."""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Callable
from .foo import Record as Record1
from .bar import Record as Record2
type RecordCallback[R: Record1] = Callable[[R], None]
def process_record[R: Record2](record: R) -> None:
...

View File

@@ -1,5 +0,0 @@
"""Test lazy evaluation of type alias values."""
type RecordCallback[R: Record] = Callable[[R], None]
from collections.abc import Callable

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::Expr;
use ruff_python_ast::{Expr, TypeParam};
use ruff_python_semantic::{ScopeId, Snapshot};
use ruff_text_size::TextRange;
@@ -10,7 +10,7 @@ pub(crate) struct Deferred<'a> {
pub(crate) scopes: Vec<ScopeId>,
pub(crate) string_type_definitions: Vec<(TextRange, &'a str, Snapshot)>,
pub(crate) future_type_definitions: Vec<(&'a Expr, Snapshot)>,
pub(crate) type_param_definitions: Vec<(&'a Expr, Snapshot)>,
pub(crate) type_param_definitions: Vec<(&'a TypeParam, Snapshot)>,
pub(crate) functions: Vec<Snapshot>,
pub(crate) lambdas: Vec<(&'a Expr, Snapshot)>,
pub(crate) for_loops: Vec<Snapshot>,

View File

@@ -582,9 +582,9 @@ where
if let Some(type_params) = type_params {
self.visit_type_params(type_params);
}
self.deferred
.type_param_definitions
.push((value, self.semantic.snapshot()));
// The value in a `type` alias has annotation semantics, in that it's never
// evaluated at runtime.
self.visit_annotation(value);
self.semantic.pop_scope();
self.visit_expr(name);
}
@@ -1389,14 +1389,9 @@ where
}
}
// Step 2: Traversal
if let ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
bound: Some(bound), ..
}) = type_param
{
self.deferred
.type_param_definitions
.push((bound, self.semantic.snapshot()));
}
self.deferred
.type_param_definitions
.push((type_param, self.semantic.snapshot()));
}
}
@@ -1771,9 +1766,12 @@ impl<'a> Checker<'a> {
for (type_param, snapshot) in type_params {
self.semantic.restore(snapshot);
self.semantic.flags |=
SemanticModelFlags::TYPE_PARAM_DEFINITION | SemanticModelFlags::TYPE_DEFINITION;
self.visit_expr(type_param);
if let ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
bound: Some(bound), ..
}) = type_param
{
self.visit_annotation(bound);
}
}
}
self.semantic.restore(snapshot);

View File

@@ -3,7 +3,7 @@
use anyhow::{Context, Result};
use ruff_diagnostics::Edit;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{self as ast, Arguments, ExceptHandler, Stmt};
use ruff_python_codegen::Stylist;
use ruff_python_index::Indexer;

View File

@@ -253,9 +253,3 @@ impl From<NonZeroU8> for TabSize {
Self(tab_size)
}
}
impl From<TabSize> for NonZeroU8 {
fn from(value: TabSize) -> Self {
value.0
}
}

View File

@@ -34,7 +34,7 @@ use crate::checkers::ast::Checker;
///
/// ## Example
/// ```python
/// "text.txt".strip(".txt") # "e"
/// "text.txt".strip(".txt") # "ex"
/// ```
///
/// Use instead:

View File

@@ -5,8 +5,8 @@ use rustc_hash::FxHashMap;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::comparable::ComparableExpr;
use ruff_python_ast::node::AstNode;
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::AstNode;
use ruff_python_ast::{self as ast, Arguments, Constant, Decorator, Expr, ExprContext};
use ruff_python_codegen::Generator;
use ruff_python_trivia::CommentRanges;

View File

@@ -6,7 +6,7 @@ use log::error;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{self as ast, whitespace, Constant, ElifElseClause, Expr, Stmt};
use ruff_python_codegen::Stylist;
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};

View File

@@ -1,8 +1,8 @@
use ruff_diagnostics::Edit;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::{self as ast, Arguments, CmpOp, Comprehension, Expr};
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,6 +1,6 @@
use memchr::memchr_iter;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_text_size::Ranged;
@@ -46,21 +46,18 @@ use crate::docstrings::Docstring;
#[violation]
pub struct EscapeSequenceInDocstring;
impl AlwaysFixableViolation for EscapeSequenceInDocstring {
impl Violation for EscapeSequenceInDocstring {
#[derive_message_formats]
fn message(&self) -> String {
format!(r#"Use `r"""` if any backslashes in a docstring"#)
}
fn fix_title(&self) -> String {
format!(r#"Add `r` prefix"#)
}
}
/// D301
pub(crate) fn backslashes(checker: &mut Checker, docstring: &Docstring) {
// Docstring is already raw.
if docstring.leading_quote().contains(['r', 'R']) {
let contents = docstring.contents;
if contents.starts_with('r') || contents.starts_with("ur") {
return;
}
@@ -70,15 +67,11 @@ pub(crate) fn backslashes(checker: &mut Checker, docstring: &Docstring) {
if memchr_iter(b'\\', bytes).any(|position| {
let escaped_char = bytes.get(position.saturating_add(1));
// Allow continuations (backslashes followed by newlines) and Unicode escapes.
!matches!(escaped_char, Some(b'\r' | b'\n' | b'u' | b'U' | b'N'))
!matches!(escaped_char, Some(b'\r' | b'\n' | b'u' | b'N'))
}) {
let mut diagnostic = Diagnostic::new(EscapeSequenceInDocstring, docstring.range());
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
"r".to_owned() + docstring.contents,
checker.diagnostics.push(Diagnostic::new(
EscapeSequenceInDocstring,
docstring.range(),
)));
checker.diagnostics.push(diagnostic);
));
}
}

View File

@@ -1,23 +1,28 @@
---
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
---
D.py:333:5: D301 [*] Use `r"""` if any backslashes in a docstring
D.py:328:5: D301 Use `r"""` if any backslashes in a docstring
|
326 | @expect('D301: Use r""" if any backslashes in a docstring')
327 | def single_quotes_raw_uppercase_backslash():
328 | R'Sum\mary.'
| ^^^^^^^^^^^^ D301
|
D.py:333:5: D301 Use `r"""` if any backslashes in a docstring
|
331 | @expect('D301: Use r""" if any backslashes in a docstring')
332 | def double_quotes_backslash():
333 | """Sum\\mary."""
| ^^^^^^^^^^^^^^^^ D301
|
= help: Add `r` prefix
Suggested fix
330 330 |
331 331 | @expect('D301: Use r""" if any backslashes in a docstring')
332 332 | def double_quotes_backslash():
333 |- """Sum\\mary."""
333 |+ r"""Sum\\mary."""
334 334 |
335 335 |
336 336 | @expect('D301: Use r""" if any backslashes in a docstring')
D.py:338:5: D301 Use `r"""` if any backslashes in a docstring
|
336 | @expect('D301: Use r""" if any backslashes in a docstring')
337 | def double_quotes_backslash_uppercase():
338 | R"""Sum\\mary."""
| ^^^^^^^^^^^^^^^^^ D301
|

View File

@@ -1,20 +1,18 @@
---
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
---
D301.py:2:5: D301 [*] Use `r"""` if any backslashes in a docstring
D301.py:2:5: D301 Use `r"""` if any backslashes in a docstring
|
1 | def double_quotes_backslash():
2 | """Sum\\mary."""
| ^^^^^^^^^^^^^^^^ D301
|
= help: Add `r` prefix
Suggested fix
1 1 | def double_quotes_backslash():
2 |- """Sum\\mary."""
2 |+ r"""Sum\\mary."""
3 3 |
4 4 |
5 5 | def double_quotes_backslash_raw():
D301.py:10:5: D301 Use `r"""` if any backslashes in a docstring
|
9 | def double_quotes_backslash_uppercase():
10 | R"""Sum\\mary."""
| ^^^^^^^^^^^^^^^^^ D301
|

View File

@@ -50,7 +50,6 @@ mod tests {
#[test_case(Rule::UnusedImport, Path::new("F401_16.py"))]
#[test_case(Rule::UnusedImport, Path::new("F401_17.py"))]
#[test_case(Rule::UnusedImport, Path::new("F401_18.py"))]
#[test_case(Rule::UnusedImport, Path::new("F401_19.py"))]
#[test_case(Rule::ImportShadowedByLoopVar, Path::new("F402.py"))]
#[test_case(Rule::UndefinedLocalWithImportStar, Path::new("F403.py"))]
#[test_case(Rule::LateFutureImport, Path::new("F404.py"))]
@@ -136,7 +135,6 @@ mod tests {
#[test_case(Rule::UndefinedName, Path::new("F821_17.py"))]
#[test_case(Rule::UndefinedName, Path::new("F821_18.py"))]
#[test_case(Rule::UndefinedName, Path::new("F821_19.py"))]
#[test_case(Rule::UndefinedName, Path::new("F821_20.py"))]
#[test_case(Rule::UndefinedExport, Path::new("F822_0.py"))]
#[test_case(Rule::UndefinedExport, Path::new("F822_1.py"))]
#[test_case(Rule::UndefinedExport, Path::new("F822_2.py"))]

View File

@@ -1,4 +0,0 @@
---
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---

View File

@@ -1,14 +0,0 @@
---
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F821_20.py:3:24: F821 Undefined name `Record`
|
1 | """Test lazy evaluation of type alias values."""
2 |
3 | type RecordCallback[R: Record] = Callable[[R], None]
| ^^^^^^ F821
4 |
5 | from collections.abc import Callable
|

View File

@@ -3,8 +3,8 @@ use itertools::Itertools;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::node::AstNode;
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::AstNode;
use ruff_python_ast::{self as ast, Arguments, Expr};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;

View File

@@ -23,7 +23,7 @@ use crate::rules::{
flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming,
pycodestyle, pydocstyle, pyflakes, pylint, pyupgrade,
};
use crate::settings::types::{FilePatternSet, PerFileIgnore, PythonVersion};
use crate::settings::types::{PerFileIgnore, PythonVersion};
use crate::{codes, RuleSelector};
use super::line_width::{LineLength, TabSize};
@@ -38,7 +38,6 @@ pub mod types;
#[derive(Debug, CacheKey)]
pub struct LinterSettings {
pub exclude: FilePatternSet,
pub project_root: PathBuf,
pub rules: RuleTable,
@@ -132,7 +131,6 @@ impl LinterSettings {
pub fn new(project_root: &Path) -> Self {
Self {
exclude: FilePatternSet::default(),
target_version: PythonVersion::default(),
project_root: project_root.to_path_buf(),
rules: DEFAULT_SELECTORS

View File

@@ -16,7 +16,6 @@ doctest = false
[dependencies]
ruff_python_trivia = { path = "../ruff_python_trivia" }
serde_derive_internals = "0.29.0"
proc-macro2 = { workspace = true }
quote = { workspace = true }

View File

@@ -1,11 +1,11 @@
use proc_macro2::TokenTree;
use quote::{quote, quote_spanned};
use serde_derive_internals::Ctxt;
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::{
AngleBracketedGenericArguments, Attribute, Data, DataStruct, DeriveInput, ExprLit, Field,
Fields, Lit, LitStr, Path, PathArguments, PathSegment, Token, Type, TypePath,
Fields, Lit, LitStr, Meta, Path, PathArguments, PathSegment, Token, Type, TypePath,
};
use ruff_python_trivia::textwrap::dedent;
@@ -38,14 +38,25 @@ pub(crate) fn derive_impl(input: DeriveInput) -> syn::Result<proc_macro2::TokenS
.any(|attr| attr.path().is_ident("option_group"))
{
output.push(handle_option_group(field)?);
} else if let Type::Path(ty) = &field.ty {
let serde_field = serde_field_metadata(field)?;
} else if let Some(serde) = field
.attrs
.iter()
.find(|attr| attr.path().is_ident("serde"))
{
// If a field has the `serde(flatten)` attribute, flatten the options into the parent
// by calling `Type::record` instead of `visitor.visit_set`
if serde_field.flatten() {
let ty_name = ty.path.require_ident()?;
output.push(quote_spanned!(ident.span() => (#ty_name::record(visit))));
if let (Type::Path(ty), Meta::List(list)) = (&field.ty, &serde.meta) {
for token in list.tokens.clone() {
if let TokenTree::Ident(ident) = token {
if ident == "flatten" {
let ty_name = ty.path.require_ident()?;
output.push(quote_spanned!(
ident.span() => (#ty_name::record(visit))
));
break;
}
}
}
}
}
}
@@ -182,10 +193,6 @@ fn handle_option(field: &Field, attr: &Attribute) -> syn::Result<proc_macro2::To
} = attr.parse_args::<FieldAttributes>()?;
let kebab_name = LitStr::new(&ident.to_string().replace('_', "-"), ident.span());
let serde_field = serde_field_metadata(field)?;
let attributed_aliases = serde_field.aliases();
let aliases = quote!(BTreeSet::from_iter([#(#attributed_aliases),*]));
Ok(quote_spanned!(
ident.span() => {
visit.record_field(#kebab_name, crate::options_base::OptionField{
@@ -193,7 +200,6 @@ fn handle_option(field: &Field, attr: &Attribute) -> syn::Result<proc_macro2::To
default: &#default,
value_type: &#value_type,
example: &#example,
aliases: #aliases
})
}
))
@@ -242,17 +248,3 @@ fn _parse_key_value(input: ParseStream, name: &str) -> syn::Result<String> {
_ => Err(syn::Error::new(value.span(), "Expected literal string")),
}
}
fn serde_field_metadata(field: &Field) -> syn::Result<serde_derive_internals::attr::Field> {
let context = Ctxt::new();
let field = serde_derive_internals::attr::Field::from_ast(
&context,
0,
field,
None,
&serde_derive_internals::attr::Default::Default,
);
context.check()?;
Ok(field)
}

View File

@@ -1,6 +1,6 @@
use ruff_text_size::{Ranged, TextRange};
use crate::AnyNodeRef;
use crate::node::AnyNodeRef;
use crate::{self as ast, Expr};
/// Unowned pendant to [`ast::Expr`] that stores a reference instead of a owned value.

View File

@@ -8,9 +8,9 @@ use smallvec::SmallVec;
use ruff_text_size::{Ranged, TextRange};
use crate::call_path::CallPath;
use crate::node::AnyNodeRef;
use crate::parenthesize::parenthesized_range;
use crate::statement_visitor::{walk_body, walk_stmt, StatementVisitor};
use crate::AnyNodeRef;
use crate::{
self as ast, Arguments, CmpOp, Constant, ExceptHandler, Expr, MatchCase, Pattern, Stmt,
TypeParam,

View File

@@ -2,7 +2,6 @@ use std::path::Path;
pub use expression::*;
pub use int::*;
pub use node::{AnyNode, AnyNodeRef, AstNode, NodeKind};
pub use nodes::*;
pub mod all;
@@ -15,7 +14,7 @@ pub mod helpers;
pub mod identifier;
pub mod imports;
mod int;
mod node;
pub mod node;
mod nodes;
pub mod parenthesize;
pub mod relocate;

View File

@@ -1,7 +1,7 @@
use ruff_python_trivia::{BackwardsTokenizer, CommentRanges, SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextLen, TextRange};
use crate::AnyNodeRef;
use crate::node::AnyNodeRef;
use crate::ExpressionRef;
/// Returns the [`TextRange`] of a given expression including parentheses, if the expression is

View File

@@ -1,10 +1,10 @@
use crate::node::{AnyNodeRef, AstNode};
use crate::{
Alias, Arguments, BoolOp, CmpOp, Comprehension, Constant, Decorator, ElifElseClause,
ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Parameter, ParameterWithDefault,
Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParams, UnaryOp,
WithItem,
};
use crate::{AnyNodeRef, AstNode};
/// Visitor that traverses all nodes recursively in pre-order.
pub trait PreorderVisitor<'a> {

View File

@@ -2,12 +2,12 @@ use std::fmt::{Debug, Write};
use insta::assert_snapshot;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::visitor::preorder::{
walk_alias, walk_comprehension, walk_except_handler, walk_expr, walk_keyword, walk_match_case,
walk_module, walk_parameter, walk_parameters, walk_pattern, walk_stmt, walk_type_param,
walk_with_item, PreorderVisitor,
};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::{
Alias, BoolOp, CmpOp, Comprehension, Constant, ExceptHandler, Expr, Keyword, MatchCase, Mod,
Operator, Parameter, Parameters, Pattern, Stmt, TypeParam, UnaryOp, WithItem,

View File

@@ -5,12 +5,12 @@ use ruff_python_ast as ast;
use ruff_python_parser::lexer::lex;
use ruff_python_parser::{parse_tokens, Mode};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::visitor::{
walk_alias, walk_comprehension, walk_except_handler, walk_expr, walk_keyword, walk_match_case,
walk_parameter, walk_parameters, walk_pattern, walk_stmt, walk_type_param, walk_with_item,
Visitor,
};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::{
Alias, BoolOp, CmpOp, Comprehension, ExceptHandler, Expr, Keyword, MatchCase, Operator,
Parameter, Parameters, Pattern, Stmt, TypeParam, UnaryOp, WithItem,

View File

@@ -150,7 +150,7 @@ impl<'fmt, 'ast, 'buf> JoinCommaSeparatedBuilder<'fmt, 'ast, 'buf> {
N: Ranged,
Separator: Format<PyFormatContext<'ast>>,
{
self.result = self.result.and_then(|()| {
self.result = self.result.and_then(|_| {
if self.entries.is_one_or_more() {
write!(self.fmt, [token(","), separator])?;
}
@@ -190,7 +190,7 @@ impl<'fmt, 'ast, 'buf> JoinCommaSeparatedBuilder<'fmt, 'ast, 'buf> {
}
pub(crate) fn finish(&mut self) -> FormatResult<()> {
self.result.and_then(|()| {
self.result.and_then(|_| {
if let Some(last_end) = self.entries.position() {
let magic_trailing_comma = has_magic_trailing_comma(
TextRange::new(last_end, self.sequence_end),

View File

@@ -180,7 +180,7 @@ mod tests {
use insta::assert_debug_snapshot;
use ruff_formatter::SourceCode;
use ruff_python_ast::AnyNode;
use ruff_python_ast::node::AnyNode;
use ruff_python_ast::{StmtBreak, StmtContinue};
use ruff_python_trivia::CommentRanges;
use ruff_text_size::{TextRange, TextSize};

View File

@@ -1,8 +1,8 @@
use std::borrow::Cow;
use ruff_formatter::{format_args, write, FormatError, FormatOptions, SourceCode};
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_python_ast::PySourceType;
use ruff_python_ast::{AnyNodeRef, AstNode};
use ruff_python_trivia::{
is_pragma_comment, lines_after, lines_after_ignoring_trivia, lines_before,
};

View File

@@ -96,8 +96,8 @@ pub(crate) use format::{
leading_alternate_branch_comments, leading_comments, leading_node_comments, trailing_comments,
};
use ruff_formatter::{SourceCode, SourceCodeSlice};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::visitor::preorder::{PreorderVisitor, TraversalSignal};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::Mod;
use ruff_python_trivia::{CommentRanges, PythonWhitespace};
use ruff_source_file::Locator;

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
@@ -52,7 +52,7 @@ impl<'a> From<AnyNodeRef<'a>> for NodeRefEqualityKey<'a> {
#[cfg(test)]
mod tests {
use crate::comments::node_key::NodeRefEqualityKey;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::StmtContinue;
use ruff_text_size::TextRange;
use std::collections::hash_map::DefaultHasher;

View File

@@ -1,7 +1,7 @@
use std::cmp::Ordering;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::whitespace::indentation;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::{self as ast, Comprehension, Expr, MatchCase, ModModule, Parameters};
use ruff_python_trivia::{
find_only_token_in_range, indentation_at_offset, BackwardsTokenizer, CommentRanges,

View File

@@ -2,7 +2,7 @@ use std::fmt::Debug;
use std::iter::Peekable;
use ruff_formatter::{SourceCode, SourceCodeSlice};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Mod, Stmt};
// The interface is designed to only export the members relevant for iterating nodes in
// pre-order.

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{write, FormatRuleWithOptions};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Constant, Expr, ExprAttribute, ExprConstant};
use ruff_python_trivia::{find_only_token_in_range, SimpleTokenKind};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprAwait;
use crate::expression::maybe_parenthesize_expression;

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Expr, ExprBinOp};
use crate::comments::SourceComment;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{FormatOwnedWithRule, FormatRefWithRule};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{BoolOp, ExprBoolOp};
use crate::expression::binary_like::BinaryLike;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::FormatRuleWithOptions;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Expr, ExprCall};
use crate::comments::{dangling_comments, SourceComment};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{FormatOwnedWithRule, FormatRefWithRule};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{CmpOp, Expr, ExprCompare};
use crate::comments::SourceComment;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::FormatRuleWithOptions;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Constant, ExprConstant};
use ruff_text_size::{Ranged, TextLen, TextRange};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Expr, ExprDict};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprDictComp;
use ruff_text_size::Ranged;

View File

@@ -2,7 +2,7 @@ use memchr::memchr2;
use crate::comments::SourceComment;
use ruff_formatter::FormatResult;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprFString;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprFormattedValue;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write, FormatRuleWithOptions};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprGeneratorExp;
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{write, FormatRuleWithOptions};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Expr, ExprIfExp};
use crate::comments::leading_comments;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprLambda;
use ruff_text_size::Ranged;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::prelude::format_with;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprList;
use ruff_text_size::Ranged;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write, FormatResult};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprListComp;
use crate::comments::SourceComment;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{write, FormatContext};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprName;
use crate::comments::SourceComment;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprNamedExpr;
use crate::comments::{dangling_comments, SourceComment};

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprSet;
use ruff_text_size::Ranged;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write, Buffer, FormatResult};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprSetComp;
use crate::comments::SourceComment;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{write, FormatError};
use ruff_python_ast::{AnyNodeRef, AstNode};
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_python_ast::{Expr, ExprSlice, ExprUnaryOp, UnaryOp};
use ruff_python_trivia::{SimpleToken, SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprStarred;
use crate::comments::{dangling_comments, SourceComment};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{write, FormatRuleWithOptions};
use ruff_python_ast::{AnyNodeRef, AstNode};
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_python_ast::{Expr, ExprSubscript};
use crate::comments::SourceComment;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write, FormatRuleWithOptions};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprTuple;
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprUnaryOp;
use ruff_python_ast::UnaryOp;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Expr, ExprYield, ExprYieldFrom};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprYieldFrom;
use crate::expression::expr_yield::AnyExpressionYield;

View File

@@ -6,8 +6,8 @@ use ruff_formatter::{
write, FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions,
};
use ruff_python_ast as ast;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::visitor::preorder::{walk_expr, PreorderVisitor};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::{Constant, Expr, ExpressionRef, Operator};
use ruff_python_trivia::CommentRanges;

View File

@@ -1,6 +1,6 @@
use ruff_formatter::prelude::tag::Condition;
use ruff_formatter::{format_args, write, Argument, Arguments};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExpressionRef;
use ruff_python_trivia::CommentRanges;
use ruff_python_trivia::{

View File

@@ -3,7 +3,7 @@ use std::borrow::Cow;
use bitflags::bitflags;
use ruff_formatter::{format_args, write, FormatError};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{self as ast, Constant, ExprConstant, ExprFString, ExpressionRef};
use ruff_python_parser::lexer::{lex_starts_at, LexicalError, LexicalErrorType};
use ruff_python_parser::{Mode, Tok};

View File

@@ -3,7 +3,7 @@ use tracing::Level;
use ruff_formatter::prelude::*;
use ruff_formatter::{format, FormatError, Formatted, PrintError, Printed, SourceCode};
use ruff_python_ast::AstNode;
use ruff_python_ast::node::AstNode;
use ruff_python_ast::Mod;
use ruff_python_index::tokens_and_ranges;
use ruff_python_parser::lexer::LexicalError;

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AstNode;
use ruff_python_ast::node::AstNode;
use ruff_python_ast::MatchCase;
use crate::builders::parenthesize_if_expands;

View File

@@ -1,8 +1,8 @@
use std::usize;
use ruff_formatter::{format_args, write, FormatRuleWithOptions};
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_python_ast::Parameters;
use ruff_python_ast::{AnyNodeRef, AstNode};
use ruff_python_trivia::{SimpleToken, SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange, TextSize};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::Pattern;
use ruff_python_trivia::CommentRanges;
use ruff_python_trivia::{

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AstNode;
use ruff_python_ast::node::AstNode;
use ruff_python_ast::{Pattern, PatternArguments};
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange, TextSize};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::PatternMatchAs;
use crate::comments::{dangling_comments, SourceComment};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::PatternMatchClass;
use crate::comments::{dangling_comments, SourceComment};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::PatternMatchMapping;
use ruff_python_ast::{Expr, Identifier, Pattern};
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::PatternMatchOr;
use crate::comments::leading_comments;

View File

@@ -1,6 +1,6 @@
use crate::comments::SourceComment;
use ruff_formatter::{format_args, Format, FormatResult};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::PatternMatchSequence;
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange};

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{Constant, PatternMatchSingleton};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::PatternMatchStar;
use crate::comments::{dangling_comments, SourceComment};

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::PatternMatchValue;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parentheses};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{write, Argument, Arguments, FormatError};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{
ElifElseClause, ExceptHandlerExceptHandler, MatchCase, StmtClassDef, StmtFor, StmtFunctionDef,
StmtIf, StmtMatch, StmtTry, StmtWhile, StmtWith, Suite,

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write};
use ruff_python_ast::AstNode;
use ruff_python_ast::node::AstNode;
use ruff_python_ast::StmtGlobal;
use crate::comments::{SourceComment, SuppressionKind};

View File

@@ -1,5 +1,5 @@
use ruff_formatter::{format_args, write};
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{ElifElseClause, StmtIf};
use crate::comments::SourceComment;

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