mirror of https://github.com/astral-sh/ruff
[`flake8-logging`] Add `flake8_logging` boilerplate and first rule `LOG009` (#7249)
## Summary Adds `LOG009` from [flake8-logging](https://github.com/adamchainz/flake8-logging). Also adds the boilerplate for a new plugin Checks for usages of undocumented `logging.WARN` constant and suggests replacement with `logging.WARNING`. ## Test Plan `cargo test` with fresh fixture ## Issue links Refers: https://github.com/astral-sh/ruff/issues/7248
This commit is contained in:
parent
64ea00048b
commit
3112202a5b
25
LICENSE
25
LICENSE
|
|
@ -1224,6 +1224,31 @@ are:
|
|||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-logging, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Adam Johnson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- Pyright, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ quality tools, including:
|
|||
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
|
||||
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [flake8-logging](https://pypi.org/project/flake8-logging/)
|
||||
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
||||
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
|
||||
- [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import logging
|
||||
|
||||
logging.WARN # LOG009
|
||||
logging.WARNING # OK
|
||||
|
||||
from logging import WARN, WARNING
|
||||
|
||||
WARN # LOG009
|
||||
WARNING # OK
|
||||
|
|
@ -13,10 +13,10 @@ use crate::registry::Rule;
|
|||
use crate::rules::{
|
||||
flake8_2020, flake8_async, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins,
|
||||
flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_django,
|
||||
flake8_future_annotations, flake8_gettext, flake8_implicit_str_concat, flake8_logging_format,
|
||||
flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self, flake8_simplify,
|
||||
flake8_tidy_imports, flake8_use_pathlib, flynt, numpy, pandas_vet, pep8_naming, pycodestyle,
|
||||
pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff,
|
||||
flake8_future_annotations, flake8_gettext, flake8_implicit_str_concat, flake8_logging,
|
||||
flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self,
|
||||
flake8_simplify, flake8_tidy_imports, flake8_use_pathlib, flynt, numpy, pandas_vet,
|
||||
pep8_naming, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff,
|
||||
};
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
|
|
@ -260,6 +260,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::SixPY3) {
|
||||
flake8_2020::rules::name_or_attribute(checker, expr);
|
||||
}
|
||||
if checker.enabled(Rule::UndocumentedWarn) {
|
||||
flake8_logging::rules::undocumented_warn(checker, expr);
|
||||
}
|
||||
if checker.enabled(Rule::LoadBeforeGlobalDeclaration) {
|
||||
pylint::rules::load_before_global_declaration(checker, id, expr);
|
||||
}
|
||||
|
|
@ -326,6 +329,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::CollectionsNamedTuple) {
|
||||
flake8_pyi::rules::collections_named_tuple(checker, expr);
|
||||
}
|
||||
if checker.enabled(Rule::UndocumentedWarn) {
|
||||
flake8_logging::rules::undocumented_warn(checker, expr);
|
||||
}
|
||||
pandas_vet::rules::attr(checker, attribute);
|
||||
}
|
||||
Expr::Call(
|
||||
|
|
|
|||
|
|
@ -920,6 +920,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
(Refurb, "132") => (RuleGroup::Nursery, rules::refurb::rules::CheckAndRemoveFromSet),
|
||||
(Refurb, "145") => (RuleGroup::Preview, rules::refurb::rules::SliceCopy),
|
||||
|
||||
// flake8-logging
|
||||
(Flake8Logging, "009") => (RuleGroup::Preview, rules::flake8_logging::rules::UndocumentedWarn),
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,6 +199,9 @@ pub enum Linter {
|
|||
/// [refurb](https://pypi.org/project/refurb/)
|
||||
#[prefix = "FURB"]
|
||||
Refurb,
|
||||
/// [flake8-logging](https://pypi.org/project/flake8-logging/)
|
||||
#[prefix = "LOG"]
|
||||
Flake8Logging,
|
||||
/// Ruff-specific rules
|
||||
#[prefix = "RUF"]
|
||||
Ruff,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
//! Rules from [flake8-logging](https://pypi.org/project/flake8-logging/).
|
||||
pub(crate) mod rules;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::assert_messages;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::Settings;
|
||||
use crate::test::test_path;
|
||||
|
||||
#[test_case(Rule::UndocumentedWarn, Path::new("LOG009.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_logging").join(path).as_path(),
|
||||
&Settings::for_rule(rule_code),
|
||||
)?;
|
||||
assert_messages!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
pub(crate) use undocumented_warn::*;
|
||||
|
||||
mod undocumented_warn;
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
use ruff_python_ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::importer::ImportRequest;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of `logging.WARN`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// The `logging.WARN` constant is an undocumented alias for `logging.WARNING`.
|
||||
///
|
||||
/// Although it’s not explicitly deprecated, `logging.WARN` is not mentioned
|
||||
/// in the `logging` documentation. Prefer `logging.WARNING` instead.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// import logging
|
||||
///
|
||||
///
|
||||
/// logging.basicConfig(level=logging.WARN)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// import logging
|
||||
///
|
||||
///
|
||||
/// logging.basicConfig(level=logging.WARNING)
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct UndocumentedWarn;
|
||||
|
||||
impl Violation for UndocumentedWarn {
|
||||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Use of undocumented `logging.WARN` constant")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> Option<String> {
|
||||
Some(format!("Replace `logging.WARN` with `logging.WARNING`"))
|
||||
}
|
||||
}
|
||||
|
||||
/// LOG009
|
||||
pub(crate) fn undocumented_warn(checker: &mut Checker, expr: &Expr) {
|
||||
if checker
|
||||
.semantic()
|
||||
.resolve_call_path(expr)
|
||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["logging", "WARN"]))
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(UndocumentedWarn, expr.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.try_set_fix(|| {
|
||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||
&ImportRequest::import("logging", "WARNING"),
|
||||
expr.range().start(),
|
||||
checker.semantic(),
|
||||
)?;
|
||||
let reference_edit = Edit::range_replacement(binding, expr.range());
|
||||
Ok(Fix::suggested_edits(import_edit, [reference_edit]))
|
||||
});
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_logging/mod.rs
|
||||
---
|
||||
LOG009.py:3:1: LOG009 [*] Use of undocumented `logging.WARN` constant
|
||||
|
|
||||
1 | import logging
|
||||
2 |
|
||||
3 | logging.WARN # LOG009
|
||||
| ^^^^^^^^^^^^ LOG009
|
||||
4 | logging.WARNING # OK
|
||||
|
|
||||
= help: Replace `logging.WARN` with `logging.WARNING`
|
||||
|
||||
ℹ Suggested fix
|
||||
1 1 | import logging
|
||||
2 2 |
|
||||
3 |-logging.WARN # LOG009
|
||||
3 |+logging.WARNING # LOG009
|
||||
4 4 | logging.WARNING # OK
|
||||
5 5 |
|
||||
6 6 | from logging import WARN, WARNING
|
||||
|
||||
LOG009.py:8:1: LOG009 [*] Use of undocumented `logging.WARN` constant
|
||||
|
|
||||
6 | from logging import WARN, WARNING
|
||||
7 |
|
||||
8 | WARN # LOG009
|
||||
| ^^^^ LOG009
|
||||
9 | WARNING # OK
|
||||
|
|
||||
= help: Replace `logging.WARN` with `logging.WARNING`
|
||||
|
||||
ℹ Suggested fix
|
||||
5 5 |
|
||||
6 6 | from logging import WARN, WARNING
|
||||
7 7 |
|
||||
8 |-WARN # LOG009
|
||||
8 |+logging.WARNING # LOG009
|
||||
9 9 | WARNING # OK
|
||||
|
||||
|
||||
|
|
@ -22,6 +22,7 @@ pub mod flake8_future_annotations;
|
|||
pub mod flake8_gettext;
|
||||
pub mod flake8_implicit_str_concat;
|
||||
pub mod flake8_import_conventions;
|
||||
pub mod flake8_logging;
|
||||
pub mod flake8_logging_format;
|
||||
pub mod flake8_no_pep420;
|
||||
pub mod flake8_pie;
|
||||
|
|
|
|||
|
|
@ -852,7 +852,11 @@ mod tests {
|
|||
Rule::QuadraticListSummation,
|
||||
];
|
||||
|
||||
const PREVIEW_RULES: &[Rule] = &[Rule::TooManyPublicMethods, Rule::SliceCopy];
|
||||
const PREVIEW_RULES: &[Rule] = &[
|
||||
Rule::TooManyPublicMethods,
|
||||
Rule::SliceCopy,
|
||||
Rule::UndocumentedWarn,
|
||||
];
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn resolve_rules(
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ natively, including:
|
|||
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
|
||||
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [flake8-logging](https://pypi.org/project/flake8-logging-format/)
|
||||
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
||||
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
|
||||
- [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
|
|
@ -156,6 +157,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
|||
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
|
||||
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [flake8-logging](https://pypi.org/project/flake8-logging/)
|
||||
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
||||
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
|
||||
- [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
|
|
|
|||
|
|
@ -2133,6 +2133,10 @@
|
|||
"ISC001",
|
||||
"ISC002",
|
||||
"ISC003",
|
||||
"LOG",
|
||||
"LOG0",
|
||||
"LOG00",
|
||||
"LOG009",
|
||||
"N",
|
||||
"N8",
|
||||
"N80",
|
||||
|
|
|
|||
Loading…
Reference in New Issue