diff --git a/crates/ruff_cache/tests/cache_key.rs b/crates/ruff_cache/tests/cache_key.rs index 898d430d4e..f786978806 100644 --- a/crates/ruff_cache/tests/cache_key.rs +++ b/crates/ruff_cache/tests/cache_key.rs @@ -3,27 +3,11 @@ use std::hash::{Hash, Hasher}; use ruff_cache::{CacheKey, CacheKeyHasher}; use ruff_macros::CacheKey; -#[derive(CacheKey, Hash)] -struct UnitStruct; - -#[derive(CacheKey, Hash)] -struct NamedFieldsStruct { - a: String, - b: String, -} - -#[derive(CacheKey, Hash)] -struct UnnamedFieldsStruct(String, String); - -#[derive(CacheKey, Hash)] -enum Enum { - Unit, - UnnamedFields(String, String), - NamedFields { a: String, b: String }, -} - #[test] fn unit_struct_cache_key() { + #[derive(CacheKey, Hash)] + struct UnitStruct; + let mut key = CacheKeyHasher::new(); UnitStruct.cache_key(&mut key); @@ -36,6 +20,43 @@ fn unit_struct_cache_key() { #[test] fn named_field_struct() { + #[derive(CacheKey, Hash)] + struct NamedFieldsStruct { + a: String, + b: String, + } + + let mut key = CacheKeyHasher::new(); + + let named_fields = NamedFieldsStruct { + a: "Hello".into(), + b: "World".into(), + }; + + named_fields.cache_key(&mut key); + + let mut hash = CacheKeyHasher::new(); + named_fields.hash(&mut hash); + + assert_eq!(hash.finish(), key.finish()); +} + +#[test] +fn struct_ignored_fields() { + #[derive(CacheKey)] + struct NamedFieldsStruct { + a: String, + #[cache_key(ignore)] + #[allow(unused)] + b: String, + } + + impl Hash for NamedFieldsStruct { + fn hash(&self, state: &mut H) { + self.a.hash(state); + } + } + let mut key = CacheKeyHasher::new(); let named_fields = NamedFieldsStruct { @@ -53,6 +74,9 @@ fn named_field_struct() { #[test] fn unnamed_field_struct() { + #[derive(CacheKey, Hash)] + struct UnnamedFieldsStruct(String, String); + let mut key = CacheKeyHasher::new(); let unnamed_fields = UnnamedFieldsStruct("Hello".into(), "World".into()); @@ -65,6 +89,13 @@ fn unnamed_field_struct() { assert_eq!(hash.finish(), key.finish()); } +#[derive(CacheKey, Hash)] +enum Enum { + Unit, + UnnamedFields(String, String), + NamedFields { a: String, b: String }, +} + #[test] fn enum_unit_variant() { let mut key = CacheKeyHasher::new(); diff --git a/crates/ruff_cli/src/cache.rs b/crates/ruff_cli/src/cache.rs index 189c11dbb3..89634c0fb1 100644 --- a/crates/ruff_cli/src/cache.rs +++ b/crates/ruff_cli/src/cache.rs @@ -59,21 +59,18 @@ pub(crate) struct Cache { impl Cache { /// Open or create a new cache. /// - /// `cache_dir` is considered the root directory of the cache, which can be - /// local to the project, global or otherwise set by the user. - /// /// `package_root` is the path to root of the package that is contained /// within this cache and must be canonicalized (to avoid considering `./` /// and `../project` being different). /// /// Finally `settings` is used to ensure we don't open a cache for different - /// settings. - pub(crate) fn open(cache_dir: &Path, package_root: PathBuf, settings: &Settings) -> Cache { + /// settings. It also defines the directory where to store the cache. + pub(crate) fn open(package_root: PathBuf, settings: &Settings) -> Cache { debug_assert!(package_root.is_absolute(), "package root not canonicalized"); let mut buf = itoa::Buffer::new(); let key = Path::new(buf.format(cache_key(&package_root, settings))); - let path = PathBuf::from_iter([cache_dir, Path::new("content"), key]); + let path = PathBuf::from_iter([&settings.cache_dir, Path::new("content"), key]); let file = match File::open(&path) { Ok(file) => file, @@ -350,7 +347,7 @@ mod tests { use itertools::Itertools; use ruff_cache::CACHE_DIR_NAME; - use ruff_linter::settings::{flags, AllSettings, Settings}; + use ruff_linter::settings::{flags, Settings}; use crate::cache::RelativePathBuf; use crate::cache::{self, Cache, FileCache}; @@ -371,10 +368,13 @@ mod tests { let _ = fs::remove_dir_all(&cache_dir); cache::init(&cache_dir).unwrap(); - let settings = Settings::default(); + let settings = Settings { + cache_dir, + ..Settings::default() + }; let package_root = fs::canonicalize(package_root).unwrap(); - let cache = Cache::open(&cache_dir, package_root.clone(), &settings); + let cache = Cache::open(package_root.clone(), &settings); assert_eq!(cache.new_files.lock().unwrap().len(), 0); let mut paths = Vec::new(); @@ -426,7 +426,7 @@ mod tests { cache.store().unwrap(); - let cache = Cache::open(&cache_dir, package_root.clone(), &settings); + let cache = Cache::open(package_root.clone(), &settings); assert_ne!(cache.package.files.len(), 0); parse_errors.sort(); @@ -651,9 +651,8 @@ mod tests { } struct TestCache { - cache_dir: PathBuf, package_root: PathBuf, - settings: AllSettings, + settings: Settings, } impl TestCache { @@ -672,10 +671,12 @@ mod tests { cache::init(&cache_dir).unwrap(); fs::create_dir(package_root.clone()).unwrap(); - let settings = AllSettings::default(); + let settings = Settings { + cache_dir, + ..Settings::default() + }; Self { - cache_dir, package_root, settings, } @@ -695,11 +696,7 @@ mod tests { } fn open(&self) -> Cache { - Cache::open( - &self.cache_dir, - self.package_root.clone(), - &self.settings.lib, - ) + Cache::open(self.package_root.clone(), &self.settings) } fn lint_file_with_cache( @@ -710,7 +707,7 @@ mod tests { lint_path( &self.package_root.join(path), Some(&self.package_root), - &self.settings.lib, + &self.settings, Some(cache), flags::Noqa::Enabled, flags::FixMode::Generate, @@ -720,7 +717,7 @@ mod tests { impl Drop for TestCache { fn drop(&mut self) { - let _ = fs::remove_dir_all(&self.cache_dir); + let _ = fs::remove_dir_all(&self.settings.cache_dir); } } } diff --git a/crates/ruff_cli/src/commands/check.rs b/crates/ruff_cli/src/commands/check.rs index 32599ca8c3..cf9d5649c6 100644 --- a/crates/ruff_cli/src/commands/check.rs +++ b/crates/ruff_cli/src/commands/check.rs @@ -58,13 +58,13 @@ pub(crate) fn check( match pyproject_config.strategy { PyprojectDiscoveryStrategy::Fixed => { - init_cache(&pyproject_config.settings.cli.cache_dir); + init_cache(&pyproject_config.settings.cache_dir); } PyprojectDiscoveryStrategy::Hierarchical => { for settings in std::iter::once(&pyproject_config.settings).chain(resolver.settings()) { - init_cache(&settings.cli.cache_dir); + init_cache(&settings.cache_dir); } } } @@ -88,12 +88,8 @@ pub(crate) fn check( .unique() .par_bridge() .map(|cache_root| { - let settings = resolver.resolve_all(cache_root, pyproject_config); - let cache = Cache::open( - &settings.cli.cache_dir, - cache_root.to_path_buf(), - &settings.lib, - ); + let settings = resolver.resolve(cache_root, pyproject_config); + let cache = Cache::open(cache_root.to_path_buf(), settings); (cache_root, cache) }) .collect::>() @@ -242,7 +238,7 @@ mod test { use ruff_linter::message::{Emitter, EmitterContext, TextEmitter}; use ruff_linter::registry::Rule; - use ruff_linter::settings::{flags, AllSettings, CliSettings, Settings}; + use ruff_linter::settings::{flags, Settings}; use ruff_workspace::resolver::{PyprojectConfig, PyprojectDiscoveryStrategy}; use crate::args::Overrides; @@ -271,11 +267,8 @@ mod test { // Configure let snapshot = format!("{}_{}", rule_code.noqa_code(), path); - let settings = AllSettings { - cli: CliSettings::default(), - // invalid pyproject.toml is not active by default - lib: Settings::for_rules(vec![rule_code, Rule::InvalidPyprojectToml]), - }; + // invalid pyproject.toml is not active by default + let settings = Settings::for_rules(vec![rule_code, Rule::InvalidPyprojectToml]); let pyproject_config = PyprojectConfig::new(PyprojectDiscoveryStrategy::Fixed, settings, None); diff --git a/crates/ruff_cli/src/commands/check_stdin.rs b/crates/ruff_cli/src/commands/check_stdin.rs index cd7f6fa111..6b41e8a9fc 100644 --- a/crates/ruff_cli/src/commands/check_stdin.rs +++ b/crates/ruff_cli/src/commands/check_stdin.rs @@ -24,14 +24,14 @@ pub(crate) fn check_stdin( } } let package_root = filename.and_then(Path::parent).and_then(|path| { - packaging::detect_package_root(path, &pyproject_config.settings.lib.namespace_packages) + packaging::detect_package_root(path, &pyproject_config.settings.namespace_packages) }); let stdin = read_from_stdin()?; let mut diagnostics = lint_stdin( filename, package_root, stdin, - &pyproject_config.settings.lib, + &pyproject_config.settings, noqa, autofix, )?; diff --git a/crates/ruff_cli/src/commands/format_stdin.rs b/crates/ruff_cli/src/commands/format_stdin.rs index d0de2f9e4b..336df64247 100644 --- a/crates/ruff_cli/src/commands/format_stdin.rs +++ b/crates/ruff_cli/src/commands/format_stdin.rs @@ -39,11 +39,11 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &Overrides) -> Resu // Format the file. let path = cli.stdin_filename.as_deref(); - let preview = match pyproject_config.settings.lib.preview { + let preview = match pyproject_config.settings.preview { PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled, PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled, }; - let line_length = pyproject_config.settings.lib.line_length; + let line_length = pyproject_config.settings.line_length; let options = path .map(PyFormatOptions::from_extension) diff --git a/crates/ruff_cli/src/lib.rs b/crates/ruff_cli/src/lib.rs index 3f342c684c..1f7e60b409 100644 --- a/crates/ruff_cli/src/lib.rs +++ b/crates/ruff_cli/src/lib.rs @@ -11,7 +11,7 @@ use notify::{recommended_watcher, RecursiveMode, Watcher}; use ruff_linter::logging::{set_up_logging, LogLevel}; use ruff_linter::settings::types::SerializationFormat; -use ruff_linter::settings::{flags, CliSettings}; +use ruff_linter::settings::{flags, Settings}; use ruff_linter::{fs, warn_user, warn_user_once}; use crate::args::{Args, CheckCommand, Command, FormatCommand}; @@ -224,14 +224,14 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { // Extract options that are included in `Settings`, but only apply at the top // level. - let CliSettings { + let Settings { fix, fix_only, output_format, show_fixes, show_source, .. - } = pyproject_config.settings.cli; + } = pyproject_config.settings; // Autofix rules are as follows: // - By default, generate all fixes, but don't apply them to the filesystem. diff --git a/crates/ruff_cli/src/resolve.rs b/crates/ruff_cli/src/resolve.rs index 9dff25361e..5781677313 100644 --- a/crates/ruff_cli/src/resolve.rs +++ b/crates/ruff_cli/src/resolve.rs @@ -7,8 +7,7 @@ use path_absolutize::path_dedot; use ruff_workspace::configuration::Configuration; use ruff_workspace::pyproject; use ruff_workspace::resolver::{ - resolve_settings_with_processor, ConfigProcessor, PyprojectConfig, PyprojectDiscoveryStrategy, - Relativity, + resolve_root_settings, ConfigProcessor, PyprojectConfig, PyprojectDiscoveryStrategy, Relativity, }; use crate::args::Overrides; @@ -25,7 +24,7 @@ pub fn resolve( if isolated { let mut config = Configuration::default(); overrides.process_config(&mut config); - let settings = config.into_all_settings(&path_dedot::CWD)?; + let settings = config.into_settings(&path_dedot::CWD)?; debug!("Isolated mode, not reading any pyproject.toml"); return Ok(PyprojectConfig::new( PyprojectDiscoveryStrategy::Fixed, @@ -42,7 +41,7 @@ pub fn resolve( .map(|config| shellexpand::full(&config).map(|config| PathBuf::from(config.as_ref()))) .transpose()? { - let settings = resolve_settings_with_processor(&pyproject, Relativity::Cwd, overrides)?; + let settings = resolve_root_settings(&pyproject, Relativity::Cwd, overrides)?; debug!( "Using user specified pyproject.toml at {}", pyproject.display() @@ -65,7 +64,7 @@ pub fn resolve( .unwrap_or(&path_dedot::CWD.as_path()), )? { debug!("Using pyproject.toml (parent) at {}", pyproject.display()); - let settings = resolve_settings_with_processor(&pyproject, Relativity::Parent, overrides)?; + let settings = resolve_root_settings(&pyproject, Relativity::Parent, overrides)?; return Ok(PyprojectConfig::new( PyprojectDiscoveryStrategy::Hierarchical, settings, @@ -79,7 +78,7 @@ pub fn resolve( // these act as the "default" settings.) if let Some(pyproject) = pyproject::find_user_settings_toml() { debug!("Using pyproject.toml (cwd) at {}", pyproject.display()); - let settings = resolve_settings_with_processor(&pyproject, Relativity::Cwd, overrides)?; + let settings = resolve_root_settings(&pyproject, Relativity::Cwd, overrides)?; return Ok(PyprojectConfig::new( PyprojectDiscoveryStrategy::Hierarchical, settings, @@ -94,7 +93,7 @@ pub fn resolve( debug!("Using Ruff default settings"); let mut config = Configuration::default(); overrides.process_config(&mut config); - let settings = config.into_all_settings(&path_dedot::CWD)?; + let settings = config.into_settings(&path_dedot::CWD)?; Ok(PyprojectConfig::new( PyprojectDiscoveryStrategy::Hierarchical, settings, diff --git a/crates/ruff_dev/src/format_dev.rs b/crates/ruff_dev/src/format_dev.rs index fc7c67e6b7..1943adfe9f 100644 --- a/crates/ruff_dev/src/format_dev.rs +++ b/crates/ruff_dev/src/format_dev.rs @@ -60,7 +60,7 @@ fn ruff_check_paths( cli.stdin_filename.as_deref(), )?; // We don't want to format pyproject.toml - pyproject_config.settings.lib.include = FilePatternSet::try_from_vec(vec![ + pyproject_config.settings.include = FilePatternSet::try_from_vec(vec![ FilePattern::Builtin("*.py"), FilePattern::Builtin("*.pyi"), ]) diff --git a/crates/ruff_linter/src/settings/defaults.rs b/crates/ruff_linter/src/settings/defaults.rs index 1ed635e290..5840d52239 100644 --- a/crates/ruff_linter/src/settings/defaults.rs +++ b/crates/ruff_linter/src/settings/defaults.rs @@ -1,6 +1,7 @@ use once_cell::sync::Lazy; use path_absolutize::path_dedot; use regex::Regex; +use ruff_cache::cache_dir; use rustc_hash::FxHashSet; use std::collections::HashSet; @@ -17,7 +18,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; +use crate::settings::types::{FilePatternSet, SerializationFormat}; pub const PREFIXES: &[RuleSelector] = &[ RuleSelector::Prefix { @@ -72,7 +73,15 @@ pub static INCLUDE: Lazy> = Lazy::new(|| { impl Default for Settings { fn default() -> Self { + let project_root = path_dedot::CWD.clone(); Self { + cache_dir: cache_dir(&project_root), + fix: false, + fix_only: false, + output_format: SerializationFormat::default(), + show_fixes: false, + show_source: false, + rules: PREFIXES .iter() .flat_map(|selector| selector.rules(PreviewMode::default())) @@ -92,7 +101,7 @@ impl Default for Settings { namespace_packages: vec![], preview: PreviewMode::default(), per_file_ignores: vec![], - project_root: path_dedot::CWD.clone(), + project_root, respect_gitignore: true, src: vec![path_dedot::CWD.clone()], tab_size: TabSize::default(), diff --git a/crates/ruff_linter/src/settings/mod.rs b/crates/ruff_linter/src/settings/mod.rs index 1b3a7d3574..822e7b53aa 100644 --- a/crates/ruff_linter/src/settings/mod.rs +++ b/crates/ruff_linter/src/settings/mod.rs @@ -31,27 +31,22 @@ pub mod flags; pub mod rule_table; pub mod types; -#[derive(Debug, Default)] -pub struct AllSettings { - pub cli: CliSettings, - pub lib: Settings, -} - -#[derive(Debug, Default, Clone)] -#[allow(clippy::struct_excessive_bools)] -/// Settings that are not used by this library and only here so that `ruff_cli` can use them. -pub struct CliSettings { - pub cache_dir: PathBuf, - pub fix: bool, - pub fix_only: bool, - pub output_format: SerializationFormat, - pub show_fixes: bool, - pub show_source: bool, -} - #[derive(Debug, CacheKey)] #[allow(clippy::struct_excessive_bools)] pub struct Settings { + #[cache_key(ignore)] + pub cache_dir: PathBuf, + #[cache_key(ignore)] + pub fix: bool, + #[cache_key(ignore)] + pub fix_only: bool, + #[cache_key(ignore)] + pub output_format: SerializationFormat, + #[cache_key(ignore)] + pub show_fixes: bool, + #[cache_key(ignore)] + pub show_source: bool, + pub rules: RuleTable, pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, RuleSet)>, diff --git a/crates/ruff_macros/src/cache_key.rs b/crates/ruff_macros/src/cache_key.rs index fa1acecedd..4093b96a3f 100644 --- a/crates/ruff_macros/src/cache_key.rs +++ b/crates/ruff_macros/src/cache_key.rs @@ -1,7 +1,8 @@ -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; +use syn::parse::{Parse, ParseStream}; use syn::spanned::Spanned; -use syn::{Data, DeriveInput, Error, Fields}; +use syn::{Data, DeriveInput, Error, Field, Fields, Token}; pub(crate) fn derive_cache_key(item: &DeriveInput) -> syn::Result { let fields = match &item.data { @@ -65,7 +66,15 @@ pub(crate) fn derive_cache_key(item: &DeriveInput) -> syn::Result { } Data::Struct(item_struct) => { - let fields = item_struct.fields.iter().enumerate().map(|(i, field)| { + let mut fields = Vec::with_capacity(item_struct.fields.len()); + + for (i, field) in item_struct.fields.iter().enumerate() { + if let Some(cache_field_attribute) = cache_key_field_attribute(field)? { + if cache_field_attribute.ignore { + continue; + } + } + let field_attr = match &field.ident { Some(ident) => quote!(self.#ident), None => { @@ -74,8 +83,8 @@ pub(crate) fn derive_cache_key(item: &DeriveInput) -> syn::Result { } }; - quote!(#field_attr.cache_key(key);) - }); + fields.push(quote!(#field_attr.cache_key(key);)); + } quote! {#(#fields)*} } @@ -101,3 +110,44 @@ pub(crate) fn derive_cache_key(item: &DeriveInput) -> syn::Result { } )) } + +fn cache_key_field_attribute(field: &Field) -> syn::Result> { + if let Some(attribute) = field + .attrs + .iter() + .find(|attribute| attribute.path().is_ident("cache_key")) + { + attribute.parse_args::().map(Some) + } else { + Ok(None) + } +} + +#[derive(Debug, Default)] +struct CacheKeyFieldAttributes { + ignore: bool, +} + +impl Parse for CacheKeyFieldAttributes { + fn parse(input: ParseStream) -> syn::Result { + let mut attributes = CacheKeyFieldAttributes::default(); + + let args = input.parse_terminated(Ident::parse, Token![,])?; + + for arg in args { + match arg.to_string().as_str() { + "ignore" => { + attributes.ignore = true; + } + name => { + return Err(Error::new( + arg.span(), + format!("Unknown `cache_field` argument {name}"), + )) + } + } + } + + Ok(attributes) + } +} diff --git a/crates/ruff_macros/src/lib.rs b/crates/ruff_macros/src/lib.rs index addba01392..7efedaabad 100644 --- a/crates/ruff_macros/src/lib.rs +++ b/crates/ruff_macros/src/lib.rs @@ -33,7 +33,11 @@ pub fn derive_combine_options(input: TokenStream) -> TokenStream { .into() } -#[proc_macro_derive(CacheKey)] +/// Generates a [`CacheKey`] implementation for the attributed type. +/// +/// Struct fields can be attributed with the `cache_key` field-attribute that supports: +/// * `ignore`: Ignore the attributed field in the cache key +#[proc_macro_derive(CacheKey, attributes(cache_key))] pub fn cache_key(input: TokenStream) -> TokenStream { let item = parse_macro_input!(input as DeriveInput); diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 9c0716c073..e6f68e90b8 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -27,9 +27,7 @@ use ruff_linter::settings::types::{ FilePattern, FilePatternSet, PerFileIgnore, PreviewMode, PythonVersion, SerializationFormat, Version, }; -use ruff_linter::settings::{ - defaults, resolve_per_file_ignores, AllSettings, CliSettings, Settings, -}; +use ruff_linter::settings::{defaults, resolve_per_file_ignores, Settings}; use ruff_linter::{ fs, warn_user, warn_user_once, warn_user_once_by_id, RuleSelector, RUFF_PKG_VERSION, }; @@ -110,23 +108,6 @@ pub struct Configuration { } impl Configuration { - pub fn into_all_settings(self, project_root: &Path) -> Result { - Ok(AllSettings { - cli: CliSettings { - cache_dir: self - .cache_dir - .clone() - .unwrap_or_else(|| cache_dir(project_root)), - fix: self.fix.unwrap_or(false), - fix_only: self.fix_only.unwrap_or(false), - output_format: self.output_format.unwrap_or_default(), - show_fixes: self.show_fixes.unwrap_or(false), - show_source: self.show_source.unwrap_or(false), - }, - lib: self.into_settings(project_root)?, - }) - } - pub fn into_settings(self, project_root: &Path) -> Result { if let Some(required_version) = &self.required_version { if &**required_version != RUFF_PKG_VERSION { @@ -139,6 +120,16 @@ impl Configuration { } Ok(Settings { + cache_dir: self + .cache_dir + .clone() + .unwrap_or_else(|| cache_dir(project_root)), + fix: self.fix.unwrap_or(false), + fix_only: self.fix_only.unwrap_or(false), + output_format: self.output_format.unwrap_or_default(), + show_fixes: self.show_fixes.unwrap_or(false), + show_source: self.show_source.unwrap_or(false), + rules: self.as_rule_table(), allowed_confusables: self .allowed_confusables diff --git a/crates/ruff_workspace/src/resolver.rs b/crates/ruff_workspace/src/resolver.rs index 3927218324..8be7a9ac39 100644 --- a/crates/ruff_workspace/src/resolver.rs +++ b/crates/ruff_workspace/src/resolver.rs @@ -14,7 +14,7 @@ use path_absolutize::path_dedot; use rustc_hash::{FxHashMap, FxHashSet}; use ruff_linter::packaging::is_package; -use ruff_linter::settings::{AllSettings, Settings}; +use ruff_linter::settings::Settings; use ruff_linter::{fs, warn_user_once}; use crate::configuration::Configuration; @@ -27,7 +27,7 @@ pub struct PyprojectConfig { /// each Python file. pub strategy: PyprojectDiscoveryStrategy, /// All settings from the `pyproject.toml` file. - pub settings: AllSettings, + pub settings: Settings, /// Absolute path to the `pyproject.toml` file. This would be `None` when /// either using the default settings or the `--isolated` flag is set. pub path: Option, @@ -36,7 +36,7 @@ pub struct PyprojectConfig { impl PyprojectConfig { pub fn new( strategy: PyprojectDiscoveryStrategy, - settings: AllSettings, + settings: Settings, path: Option, ) -> Self { Self { @@ -93,21 +93,21 @@ impl Relativity { #[derive(Default)] pub struct Resolver { - settings: BTreeMap, + settings: BTreeMap, } impl Resolver { /// Add a resolved [`Settings`] under a given [`PathBuf`] scope. - fn add(&mut self, path: PathBuf, settings: AllSettings) { + fn add(&mut self, path: PathBuf, settings: Settings) { self.settings.insert(path, settings); } - /// Return the appropriate [`AllSettings`] for a given [`Path`]. - pub fn resolve_all<'a>( + /// Return the appropriate [`Settings`] for a given [`Path`]. + pub fn resolve<'a>( &'a self, path: &Path, pyproject_config: &'a PyprojectConfig, - ) -> &'a AllSettings { + ) -> &'a Settings { match pyproject_config.strategy { PyprojectDiscoveryStrategy::Fixed => &pyproject_config.settings, PyprojectDiscoveryStrategy::Hierarchical => self @@ -119,14 +119,6 @@ impl Resolver { } } - pub fn resolve<'a>( - &'a self, - path: &Path, - pyproject_config: &'a PyprojectConfig, - ) -> &'a Settings { - &self.resolve_all(path, pyproject_config).lib - } - /// Return a mapping from Python package to its package root. pub fn package_roots<'a>( &'a self, @@ -163,7 +155,7 @@ impl Resolver { } /// Return an iterator over the resolved [`Settings`] in this [`Resolver`]. - pub fn settings(&self) -> impl Iterator { + pub fn settings(&self) -> impl Iterator { self.settings.values() } } @@ -260,20 +252,20 @@ fn resolve_scoped_settings( pyproject: &Path, relativity: Relativity, processor: &dyn ConfigProcessor, -) -> Result<(PathBuf, AllSettings)> { +) -> Result<(PathBuf, Settings)> { let configuration = resolve_configuration(pyproject, relativity, processor)?; let project_root = relativity.resolve(pyproject); - let settings = configuration.into_all_settings(&project_root)?; + let settings = configuration.into_settings(&project_root)?; Ok((project_root, settings)) } /// Extract the [`Settings`] from a given `pyproject.toml` and process the /// configuration with the given [`ConfigProcessor`]. -pub fn resolve_settings_with_processor( +pub fn resolve_root_settings( pyproject: &Path, relativity: Relativity, processor: &dyn ConfigProcessor, -) -> Result { +) -> Result { let (_project_root, settings) = resolve_scoped_settings(pyproject, relativity, processor)?; Ok(settings) } @@ -305,7 +297,7 @@ pub fn python_files_in_path( } // Check if the paths themselves are excluded. - if pyproject_config.settings.lib.force_exclude { + if pyproject_config.settings.force_exclude { paths.retain(|path| !is_file_excluded(path, &resolver, pyproject_config)); if paths.is_empty() { return Ok((vec![], resolver)); @@ -321,7 +313,7 @@ pub fn python_files_in_path( for path in &paths[1..] { builder.add(path); } - builder.standard_filters(pyproject_config.settings.lib.respect_gitignore); + builder.standard_filters(pyproject_config.settings.respect_gitignore); builder.hidden(false); let walker = builder.build_parallel(); @@ -430,7 +422,7 @@ pub fn python_file_at_path( pyproject_config: &PyprojectConfig, processor: &dyn ConfigProcessor, ) -> Result { - if !pyproject_config.settings.lib.force_exclude { + if !pyproject_config.settings.force_exclude { return Ok(true); } @@ -510,12 +502,12 @@ mod tests { use tempfile::TempDir; use ruff_linter::settings::types::FilePattern; - use ruff_linter::settings::AllSettings; + use ruff_linter::settings::Settings; use crate::configuration::Configuration; use crate::pyproject::find_settings_toml; use crate::resolver::{ - is_file_excluded, match_exclusion, python_files_in_path, resolve_settings_with_processor, + is_file_excluded, match_exclusion, python_files_in_path, resolve_root_settings, ConfigProcessor, PyprojectConfig, PyprojectDiscoveryStrategy, Relativity, Resolver, }; use crate::tests::test_resource_path; @@ -532,7 +524,7 @@ mod tests { let resolver = Resolver::default(); let pyproject_config = PyprojectConfig::new( PyprojectDiscoveryStrategy::Hierarchical, - resolve_settings_with_processor( + resolve_root_settings( &find_settings_toml(&package_root)?.unwrap(), Relativity::Parent, &NoOpProcessor, @@ -578,11 +570,7 @@ mod tests { let (paths, _) = python_files_in_path( &[root.to_path_buf()], - &PyprojectConfig::new( - PyprojectDiscoveryStrategy::Fixed, - AllSettings::default(), - None, - ), + &PyprojectConfig::new(PyprojectDiscoveryStrategy::Fixed, Settings::default(), None), &NoOpProcessor, )?; let paths = paths