Extend pragma comment cases (#7687)

## Summary

Extends the pragma comment detection in the formatter to support
case-insensitive `noqa` (as supposed by Ruff), plus a variety of other
pragmas (`isort:`, `nosec`, etc.).

Also extracts the detection out into the trivia crate so that we can
reuse it in the linter (see:
https://github.com/astral-sh/ruff/issues/7471).

## Test Plan

`cargo test`
This commit is contained in:
Charlie Marsh 2023-09-28 14:55:19 -04:00 committed by GitHub
parent 46b85ab0a9
commit f62b4c801f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 11 deletions

View file

@ -1,10 +1,12 @@
mod comment_ranges;
mod cursor;
mod pragmas;
pub mod textwrap;
mod tokenizer;
mod whitespace;
pub use comment_ranges::CommentRanges;
pub use cursor::*;
pub use pragmas::*;
pub use tokenizer::*;
pub use whitespace::*;

View file

@ -0,0 +1,30 @@
/// Returns `true` if a comment appears to be a pragma comment.
///
/// ```
/// assert!(ruff_python_trivia::is_pragma_comment("# type: ignore"));
/// assert!(ruff_python_trivia::is_pragma_comment("# noqa: F401"));
/// assert!(ruff_python_trivia::is_pragma_comment("# noqa"));
/// assert!(ruff_python_trivia::is_pragma_comment("# NoQA"));
/// assert!(ruff_python_trivia::is_pragma_comment("# nosec"));
/// assert!(ruff_python_trivia::is_pragma_comment("# nosec B602, B607"));
/// assert!(ruff_python_trivia::is_pragma_comment("# isort: off"));
/// assert!(ruff_python_trivia::is_pragma_comment("# isort: skip"));
/// ```
pub fn is_pragma_comment(comment: &str) -> bool {
let Some(content) = comment.strip_prefix('#') else {
return false;
};
let trimmed = content.trim_start();
// Case-insensitive match against `noqa` (which doesn't require a trailing colon).
matches!(
trimmed.as_bytes(),
[b'n' | b'N', b'o' | b'O', b'q' | b'Q', b'a' | b'A', ..]
) ||
// Case-insensitive match against pragmas that don't require a trailing colon.
trimmed.starts_with("nosec") ||
// Case-sensitive match against a variety of pragmas that _do_ require a trailing colon.
trimmed
.split_once(':')
.is_some_and(|(maybe_pragma, _)| matches!(maybe_pragma, "isort" | "type" | "pyright" | "pylint" | "flake8" | "ruff"))
}