[`flake8-self`] Add Plugin and Rule `SLF001` (#2470)

This commit is contained in:
Maksudul Haque 2023-02-02 18:58:14 +06:00 committed by GitHub
parent b032f50775
commit 9e59c99133
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 181 additions and 4 deletions

View File

@ -1030,3 +1030,8 @@ are:
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
""" """
- flake8-self, licensed as follows:
"""
Freely Distributable
"""

View File

@ -158,6 +158,7 @@ This README is also available as [documentation](https://beta.ruff.rs/docs/).
1. [Pylint (PL)](#pylint-pl) 1. [Pylint (PL)](#pylint-pl)
1. [tryceratops (TRY)](#tryceratops-try) 1. [tryceratops (TRY)](#tryceratops-try)
1. [flake8-raise (RSE)](#flake8-raise-rse) 1. [flake8-raise (RSE)](#flake8-raise-rse)
1. [flake8-self (SLF)](#flake8-self-slf)
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. --> 1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
1. [Editor Integrations](#editor-integrations) 1. [Editor Integrations](#editor-integrations)
1. [FAQ](#faq) 1. [FAQ](#faq)
@ -1368,6 +1369,14 @@ For more, see [flake8-raise](https://pypi.org/project/flake8-raise/) on PyPI.
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| RSE102 | unnecessary-paren-on-raise-exception | Unnecessary parentheses on raised exception | | | RSE102 | unnecessary-paren-on-raise-exception | Unnecessary parentheses on raised exception | |
### flake8-self (SLF)
For more, see [flake8-self](https://pypi.org/project/flake8-self/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| SLF001 | private-member-access | Private member accessed: `{access}` | |
### Ruff-specific rules (RUF) ### Ruff-specific rules (RUF)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
@ -1661,6 +1670,7 @@ natively, including:
- [flake8-quotes](https://pypi.org/project/flake8-quotes/) - [flake8-quotes](https://pypi.org/project/flake8-quotes/)
- [flake8-raise](https://pypi.org/project/flake8-raise/) - [flake8-raise](https://pypi.org/project/flake8-raise/)
- [flake8-return](https://pypi.org/project/flake8-return/) - [flake8-return](https://pypi.org/project/flake8-return/)
- [flake8-self](https://pypi.org/project/flake8-self/)
- [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998)) - [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998))
- [flake8-super](https://pypi.org/project/flake8-super/) - [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) - [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
@ -1750,6 +1760,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
- [flake8-quotes](https://pypi.org/project/flake8-quotes/) - [flake8-quotes](https://pypi.org/project/flake8-quotes/)
- [flake8-raise](https://pypi.org/project/flake8-raise/) - [flake8-raise](https://pypi.org/project/flake8-raise/)
- [flake8-return](https://pypi.org/project/flake8-return/) - [flake8-return](https://pypi.org/project/flake8-return/)
- [flake8-self](https://pypi.org/project/flake8-self/)
- [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998)) - [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998))
- [flake8-super](https://pypi.org/project/flake8-super/) - [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) - [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)

View File

@ -0,0 +1,31 @@
class Foo:
def __init__(self):
self.public_thing = "foo"
self._private_thing = "bar"
self.__really_private_thing = "baz"
def __str__(self):
return "foo"
def public_func(self):
pass
def _private_func(self):
pass
def __really_private_func(self, arg):
pass
foo = Foo()
print(foo.public_thing)
print(foo.public_func())
print(foo.__dict__)
print(foo.__str__())
print(foo._private_thing) # SLF001
print(foo.__really_private_thing) # SLF001
print(foo._private_func()) # SLF001
print(foo.__really_private_func(1)) # SLF001

View File

@ -1828,6 +1828,10 @@
"SIM4", "SIM4",
"SIM40", "SIM40",
"SIM401", "SIM401",
"SLF",
"SLF0",
"SLF00",
"SLF001",
"T", "T",
"T1", "T1",
"T10", "T10",

View File

@ -36,10 +36,10 @@ use crate::rules::{
flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap,
flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger,
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_logging_format, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_logging_format,
flake8_pie, flake8_print, flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_pie, flake8_print, flake8_pytest_style, flake8_raise, flake8_return, flake8_self,
flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, flake8_use_pathlib, mccabe, flake8_simplify, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
pandas_vet, pep8_naming, pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, flake8_use_pathlib, mccabe, pandas_vet, pep8_naming, pycodestyle, pydocstyle, pyflakes,
ruff, tryceratops, pygrep_hooks, pylint, pyupgrade, ruff, tryceratops,
}; };
use crate::settings::types::PythonVersion; use crate::settings::types::PythonVersion;
use crate::settings::{flags, Settings}; use crate::settings::{flags, Settings};
@ -2148,6 +2148,9 @@ where
if self.settings.rules.enabled(&Rule::BannedApi) { if self.settings.rules.enabled(&Rule::BannedApi) {
flake8_tidy_imports::banned_api::banned_attribute_access(self, expr); flake8_tidy_imports::banned_api::banned_attribute_access(self, expr);
} }
if self.settings.rules.enabled(&Rule::PrivateMemberAccess) {
flake8_self::rules::private_member_access(self, expr);
}
pandas_vet::rules::check_attr(self, attr, value, expr); pandas_vet::rules::check_attr(self, attr, value, expr);
} }
ExprKind::Call { ExprKind::Call {

View File

@ -484,6 +484,8 @@ ruff_macros::define_rule_mapping!(
G202 => rules::flake8_logging_format::violations::LoggingRedundantExcInfo, G202 => rules::flake8_logging_format::violations::LoggingRedundantExcInfo,
// flake8-raise // flake8-raise
RSE102 => rules::flake8_raise::rules::UnnecessaryParenOnRaiseException, RSE102 => rules::flake8_raise::rules::UnnecessaryParenOnRaiseException,
// flake8-self
SLF001 => rules::flake8_self::rules::PrivateMemberAccess,
// ruff // ruff
RUF001 => violations::AmbiguousUnicodeCharacterString, RUF001 => violations::AmbiguousUnicodeCharacterString,
RUF002 => violations::AmbiguousUnicodeCharacterDocstring, RUF002 => violations::AmbiguousUnicodeCharacterDocstring,
@ -616,6 +618,9 @@ pub enum Linter {
/// [flake8-raise](https://pypi.org/project/flake8-raise/) /// [flake8-raise](https://pypi.org/project/flake8-raise/)
#[prefix = "RSE"] #[prefix = "RSE"]
Flake8Raise, Flake8Raise,
/// [flake8-self](https://pypi.org/project/flake8-self/)
#[prefix = "SLF"]
Flake8Self,
/// Ruff-specific rules /// Ruff-specific rules
#[prefix = "RUF"] #[prefix = "RUF"]
Ruff, Ruff,

View File

@ -0,0 +1,26 @@
//! Rules from [flake8-self](https://pypi.org/project/flake8-self/).
pub(crate) mod rules;
#[cfg(test)]
mod tests {
use std::convert::AsRef;
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::registry::Rule;
use crate::test::test_path;
use crate::{assert_yaml_snapshot, settings};
#[test_case(Rule::PrivateMemberAccess, Path::new("SLF001.py"); "SLF001")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("flake8_self").join(path).as_path(),
&settings::Settings::for_rule(rule_code),
)?;
assert_yaml_snapshot!(snapshot, diagnostics);
Ok(())
}
}

View File

@ -0,0 +1,3 @@
pub use private_member_access::{private_member_access, PrivateMemberAccess};
mod private_member_access;

View File

@ -0,0 +1,43 @@
use ruff_macros::derive_message_formats;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::registry::Diagnostic;
use crate::violation::Violation;
use rustpython_ast::{Expr, ExprKind};
define_violation!(
pub struct PrivateMemberAccess {
pub access: String,
}
);
impl Violation for PrivateMemberAccess {
#[derive_message_formats]
fn message(&self) -> String {
let PrivateMemberAccess { access } = self;
format!("Private member accessed: `{access}`")
}
}
const VALID_IDS: [&str; 3] = ["self", "cls", "mcs"];
/// SLF001
pub fn private_member_access(checker: &mut Checker, expr: &Expr) {
if let ExprKind::Attribute { value, attr, .. } = &expr.node {
if !attr.ends_with("__") && (attr.starts_with('_') || attr.starts_with("__")) {
let ExprKind::Name { id, .. } = &value.node else {
return;
};
if !VALID_IDS.contains(&id.as_str()) {
checker.diagnostics.push(Diagnostic::new(
PrivateMemberAccess {
access: format!("{}.{}", id, attr),
},
Range::from_located(expr),
));
}
}
}
}

View File

@ -0,0 +1,45 @@
---
source: src/rules/flake8_self/mod.rs
expression: diagnostics
---
- kind:
PrivateMemberAccess: ~
location:
row: 28
column: 6
end_location:
row: 28
column: 24
fix: ~
parent: ~
- kind:
PrivateMemberAccess: ~
location:
row: 29
column: 6
end_location:
row: 29
column: 32
fix: ~
parent: ~
- kind:
PrivateMemberAccess: ~
location:
row: 30
column: 6
end_location:
row: 30
column: 23
fix: ~
parent: ~
- kind:
PrivateMemberAccess: ~
location:
row: 31
column: 6
end_location:
row: 31
column: 31
fix: ~
parent: ~

View File

@ -23,6 +23,7 @@ pub mod flake8_pytest_style;
pub mod flake8_quotes; pub mod flake8_quotes;
pub mod flake8_raise; pub mod flake8_raise;
pub mod flake8_return; pub mod flake8_return;
pub mod flake8_self;
pub mod flake8_simplify; pub mod flake8_simplify;
pub mod flake8_tidy_imports; pub mod flake8_tidy_imports;
pub mod flake8_type_checking; pub mod flake8_type_checking;