-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support negated patterns in [extend-]per-file-ignores #10852
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -296,13 +296,22 @@ impl CacheKey for FilePatternSet { | |
pub struct PerFileIgnore { | ||
pub(crate) basename: String, | ||
pub(crate) absolute: PathBuf, | ||
pub(crate) negated: bool, | ||
pub(crate) rules: RuleSet, | ||
} | ||
|
||
impl PerFileIgnore { | ||
pub fn new(pattern: String, prefixes: &[RuleSelector], project_root: Option<&Path>) -> Self { | ||
pub fn new( | ||
mut pattern: String, | ||
prefixes: &[RuleSelector], | ||
project_root: Option<&Path>, | ||
) -> Self { | ||
// Rules in preview are included here even if preview mode is disabled; it's safe to ignore disabled rules | ||
let rules: RuleSet = prefixes.iter().flat_map(RuleSelector::all_rules).collect(); | ||
let negated = pattern.starts_with('!'); | ||
if negated { | ||
pattern.drain(..1); | ||
} | ||
Comment on lines
+312
to
+314
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might look a little odd, but it's zero-allocation, unlike the version using Perf probably doesn't matter much here in config-parsing; if you'd prefer the version that takes a non-mut String and uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm cool with this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. \cc @BurntSushi may have interesting things to say here :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is fine personally. I agree that saving an alloc probably doesn't matter here (I assume these ultimately get converted to a glob matcher, and that is an enormous amount of work compared to saving an alloc) so I'd write whatever is clear. And this seems clear to me. :) |
||
let path = Path::new(&pattern); | ||
let absolute = match project_root { | ||
Some(project_root) => fs::normalize_path_to(path, project_root), | ||
|
@@ -312,6 +321,7 @@ impl PerFileIgnore { | |
Self { | ||
basename: pattern, | ||
absolute, | ||
negated, | ||
rules, | ||
} | ||
} | ||
|
@@ -593,7 +603,7 @@ pub type IdentifierPattern = glob::Pattern; | |
#[derive(Debug, Clone, CacheKey, Default)] | ||
pub struct PerFileIgnores { | ||
// Ordered as (absolute path matcher, basename matcher, rules) | ||
ignores: Vec<(GlobMatcher, GlobMatcher, RuleSet)>, | ||
ignores: Vec<(GlobMatcher, GlobMatcher, bool, RuleSet)>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be a named struct ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. |
||
} | ||
|
||
impl PerFileIgnores { | ||
|
@@ -609,7 +619,12 @@ impl PerFileIgnores { | |
// Construct basename matcher. | ||
let basename = Glob::new(&per_file_ignore.basename)?.compile_matcher(); | ||
|
||
Ok((absolute, basename, per_file_ignore.rules)) | ||
Ok(( | ||
absolute, | ||
basename, | ||
per_file_ignore.negated, | ||
per_file_ignore.rules, | ||
)) | ||
}) | ||
.collect(); | ||
Ok(Self { ignores: ignores? }) | ||
|
@@ -622,10 +637,10 @@ impl Display for PerFileIgnores { | |
write!(f, "{{}}")?; | ||
} else { | ||
writeln!(f, "{{")?; | ||
for (absolute, basename, rules) in &self.ignores { | ||
for (absolute, basename, negated, rules) in &self.ignores { | ||
writeln!( | ||
f, | ||
"\t{{ absolute = {absolute:#?}, basename = {basename:#?}, rules = {rules} }}," | ||
"\t{{ absolute = {absolute:#?}, basename = {basename:#?}, negated = {negated:#?}, rules = {rules} }}," | ||
)?; | ||
} | ||
write!(f, "}}")?; | ||
|
@@ -635,7 +650,7 @@ impl Display for PerFileIgnores { | |
} | ||
|
||
impl Deref for PerFileIgnores { | ||
type Target = Vec<(GlobMatcher, GlobMatcher, RuleSet)>; | ||
type Target = Vec<(GlobMatcher, GlobMatcher, bool, RuleSet)>; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.ignores | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -905,7 +905,8 @@ pub struct LintCommonOptions { | |
|
||
// Tables are required to go last. | ||
/// A list of mappings from file pattern to rule codes or prefixes to | ||
/// exclude, when considering any matching files. | ||
/// exclude, when considering any matching files. An initial '!' negates | ||
/// the file pattern. | ||
#[option( | ||
default = "{}", | ||
value_type = "dict[str, list[RuleSelector]]", | ||
|
@@ -914,6 +915,8 @@ pub struct LintCommonOptions { | |
# Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`. | ||
"__init__.py" = ["E402"] | ||
"path/to/file.py" = ["E402"] | ||
# Ignore `D` rules everywhere except for the `src/` directory. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this comment correct? Looks like it ignored F401 not D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yeah, it should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, thanks, will fix! |
||
"!src/**.py" = ["F401"] | ||
"# | ||
)] | ||
pub per_file_ignores: Option<FxHashMap<String, Vec<RuleSelector>>>, | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth adding some more tests where there are both regular patterns and negated patterns. And in particular, cases where a negated pattern might try to "override" a previous pattern. e.g.,
Or something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's a great point, I'll put up an update with a test for this case, and probably also more clearly document how this works.
(I don't expect to change the implementation as part of this; I think the way it needs to work is how it does now: we go through each pattern, and if the pattern matches (whether that's a positive match or a negated non-match), we add the listed rules as ignored; we never un-ignore rules based on failure to match a pattern. I think that would get too complex to understand pretty quickly, and also un-ignoring doesn't really make sense for an option named
per-file-ignores
.)