Add no-eval rule from pygrep-hooks (#994)

This commit is contained in:
Jonathan Plasse 2022-12-02 18:59:06 +01:00 committed by GitHub
parent 1a24d78f67
commit 117fcb6936
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 267 additions and 47 deletions

23
LICENSE
View file

@ -471,6 +471,29 @@ are:
SOFTWARE. SOFTWARE.
""" """
- pygrep-hooks, licensed as follows:
"""
Copyright (c) 2018 Anthony Sottile
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.
"""
- pyupgrade, licensed as follows: - pyupgrade, licensed as follows:
""" """
Copyright (c) 2017 Anthony Sottile Copyright (c) 2017 Anthony Sottile

View file

@ -77,18 +77,20 @@ of [Conda](https://docs.conda.io/en/latest/):
1. [pep8-naming (N)](#pep8-naming) 1. [pep8-naming (N)](#pep8-naming)
1. [eradicate (ERA)](#eradicate) 1. [eradicate (ERA)](#eradicate)
1. [flake8-bandit (S)](#flake8-bandit) 1. [flake8-bandit (S)](#flake8-bandit)
1. [flake8-comprehensions (C)](#flake8-comprehensions) 1. [flake8-comprehensions (C4)](#flake8-comprehensions)
1. [flake8-boolean-trap (FBT)](#flake8-boolean-trap) 1. [flake8-boolean-trap (FBT)](#flake8-boolean-trap)
1. [flake8-bugbear (B)](#flake8-bugbear) 1. [flake8-bugbear (B)](#flake8-bugbear)
1. [flake8-builtins (A)](#flake8-builtins) 1. [flake8-builtins (A)](#flake8-builtins)
1. [flake8-debugger (T)](#flake8-debugger) 1. [flake8-debugger (T10)](#flake8-debugger)
1. [flake8-tidy-imports (I25)](#flake8-tidy-imports) 1. [flake8-tidy-imports (I25)](#flake8-tidy-imports)
1. [flake8-print (T)](#flake8-print) 1. [flake8-print (T20)](#flake8-print)
1. [flake8-quotes (Q)](#flake8-quotes) 1. [flake8-quotes (Q)](#flake8-quotes)
1. [flake8-annotations (ANN)](#flake8-annotations) 1. [flake8-annotations (ANN)](#flake8-annotations)
1. [flake8-2020 (YTT)](#flake8-2020) 1. [flake8-2020 (YTT)](#flake8-2020)
1. [flake8-blind-except (BLE)](#flake8-blind-except) 1. [flake8-blind-except (BLE)](#flake8-blind-except)
1. [mccabe (C90)](#mccabe) 1. [mccabe (C90)](#mccabe)
1. [pygrep-hooks (PGH)](#pygrep-hooks)
1. [Pylint (PL)](#pylint)
1. [Ruff-specific rules (RUF)](#ruff-specific-rules) 1. [Ruff-specific rules (RUF)](#ruff-specific-rules)
1. [Meta rules (M)](#meta-rules) 1. [Meta rules (M)](#meta-rules)
1. [Editor Integrations](#editor-integrations) 1. [Editor Integrations](#editor-integrations)
@ -726,6 +728,14 @@ For more, see [mccabe](https://pypi.org/project/mccabe/0.7.0/) on PyPI.
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| C901 | FunctionIsTooComplex | `...` is too complex (10) | | | C901 | FunctionIsTooComplex | `...` is too complex (10) | |
### pygrep-hooks
For more, see [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) on GitHub.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PGH001 | NoEval | No builtin `eval()` allowed | |
### Pylint ### Pylint
For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI. For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
@ -902,6 +912,7 @@ natively, including:
- [`yesqa`](https://github.com/asottile/yesqa) - [`yesqa`](https://github.com/asottile/yesqa)
- [`eradicate`](https://pypi.org/project/eradicate/) - [`eradicate`](https://pypi.org/project/eradicate/)
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (16/33) - [`pyupgrade`](https://pypi.org/project/pyupgrade/) (16/33)
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (1/10)
- [`autoflake`](https://pypi.org/project/autoflake/) (1/7) - [`autoflake`](https://pypi.org/project/autoflake/) (1/7)
Beyond the rule set, Ruff suffers from the following limitations vis-à-vis Flake8: Beyond the rule set, Ruff suffers from the following limitations vis-à-vis Flake8:
@ -946,8 +957,10 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
- [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/) (1/3) - [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/) (1/3)
- [`mccabe`](https://pypi.org/project/mccabe/) - [`mccabe`](https://pypi.org/project/mccabe/)
Ruff can also replace [`isort`](https://pypi.org/project/isort/), [`yesqa`](https://github.com/asottile/yesqa), Ruff can also replace [`isort`](https://pypi.org/project/isort/),
and a subset of the rules implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (16/33). [`yesqa`](https://github.com/asottile/yesqa), [`eradicate`](https://pypi.org/project/eradicate/),
[`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (1/10), and a subset of the rules
implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (16/33).
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue. If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue.
@ -1261,7 +1274,7 @@ Exclusions are based on globs, and can be either:
(to exclude any Python files in `directory`). Note that these paths are relative to the (to exclude any Python files in `directory`). Note that these paths are relative to the
project root (e.g., the directory containing your `pyproject.toml`). project root (e.g., the directory containing your `pyproject.toml`).
Note that you'll typically want to use [`extend_exclude`](#extend_exclude) to modify the excluded Note that you'll typically want to use [`extend_exclude`](#extend-exclude) to modify the excluded
paths. paths.
**Default value**: `[".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]` **Default value**: `[".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]`

View file

@ -0,0 +1,9 @@
from ast import literal_eval
eval("3 + 4")
literal_eval({1: 2})
def fn() -> None:
eval("3 + 4")

View file

@ -0,0 +1,11 @@
def eval(content: str) -> None:
pass
eval("3 + 4")
literal_eval({1: 2})
def fn() -> None:
eval("3 + 4")

View file

@ -28,11 +28,12 @@ pub fn main(cli: &Cli) -> Result<()> {
output.push('\n'); output.push('\n');
output.push('\n'); output.push('\n');
if let Some(url) = check_category.url() { if let Some((url, platform)) = check_category.url() {
output.push_str(&format!( output.push_str(&format!(
"For more, see [{}]({}) on PyPI.", "For more, see [{}]({}) on {}.",
check_category.title(), check_category.title(),
url url,
platform
)); ));
output.push('\n'); output.push('\n');
output.push('\n'); output.push('\n');

View file

@ -37,7 +37,7 @@ use crate::{
docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except,
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_debugger, flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_debugger,
flake8_print, flake8_tidy_imports, mccabe, pep8_naming, pycodestyle, pydocstyle, pyflakes, flake8_print, flake8_tidy_imports, mccabe, pep8_naming, pycodestyle, pydocstyle, pyflakes,
pylint, pyupgrade, rules, pygrep_hooks, pylint, pyupgrade, rules,
}; };
const GLOBAL_SCOPE_INDEX: usize = 0; const GLOBAL_SCOPE_INDEX: usize = 0;
@ -1700,6 +1700,11 @@ where
} }
} }
// pygrep-hooks
if self.settings.enabled.contains(&CheckCode::PGH001) {
pygrep_hooks::checks::no_eval(self, func);
}
// Ruff // Ruff
if self.settings.enabled.contains(&CheckCode::RUF101) { if self.settings.enabled.contains(&CheckCode::RUF101) {
rules::plugins::convert_exit_to_sys_exit(self, func); rules::plugins::convert_exit_to_sys_exit(self, func);

View file

@ -278,6 +278,8 @@ pub enum CheckCode {
RUF101, RUF101,
// Meta // Meta
M001, M001,
// pygrep-hooks
PGH001,
} }
#[derive(EnumIter, Debug, PartialEq, Eq)] #[derive(EnumIter, Debug, PartialEq, Eq)]
@ -302,11 +304,26 @@ pub enum CheckCategory {
Flake82020, Flake82020,
Flake8BlindExcept, Flake8BlindExcept,
McCabe, McCabe,
PygrepHooks,
Pylint, Pylint,
Ruff, Ruff,
Meta, Meta,
} }
pub enum Platform {
PyPI,
GitHub,
}
impl fmt::Display for Platform {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Platform::PyPI => fmt.write_str("PyPI"),
Platform::GitHub => fmt.write_str("GitHub"),
}
}
}
impl CheckCategory { impl CheckCategory {
pub fn title(&self) -> &'static str { pub fn title(&self) -> &'static str {
match self { match self {
@ -331,51 +348,97 @@ impl CheckCategory {
CheckCategory::Pydocstyle => "pydocstyle", CheckCategory::Pydocstyle => "pydocstyle",
CheckCategory::Pyflakes => "Pyflakes", CheckCategory::Pyflakes => "Pyflakes",
CheckCategory::Pylint => "Pylint", CheckCategory::Pylint => "Pylint",
CheckCategory::PygrepHooks => "pygrep-hooks",
CheckCategory::Pyupgrade => "pyupgrade", CheckCategory::Pyupgrade => "pyupgrade",
CheckCategory::Ruff => "Ruff-specific rules", CheckCategory::Ruff => "Ruff-specific rules",
} }
} }
pub fn url(&self) -> Option<&'static str> { pub fn url(&self) -> Option<(&'static str, &'static Platform)> {
match self { match self {
CheckCategory::Eradicate => Some("https://pypi.org/project/eradicate/2.1.0/"), CheckCategory::Eradicate => {
CheckCategory::Flake82020 => Some("https://pypi.org/project/flake8-2020/1.7.0/"), Some(("https://pypi.org/project/eradicate/2.1.0/", &Platform::PyPI))
CheckCategory::Flake8Annotations => {
Some("https://pypi.org/project/flake8-annotations/2.9.1/")
} }
CheckCategory::Flake8Bandit => Some("https://pypi.org/project/flake8-bandit/4.1.1/"), CheckCategory::Flake82020 => Some((
CheckCategory::Flake8BlindExcept => { "https://pypi.org/project/flake8-2020/1.7.0/",
Some("https://pypi.org/project/flake8-blind-except/0.2.1/") &Platform::PyPI,
)),
CheckCategory::Flake8Annotations => Some((
"https://pypi.org/project/flake8-annotations/2.9.1/",
&Platform::PyPI,
)),
CheckCategory::Flake8Bandit => Some((
"https://pypi.org/project/flake8-bandit/4.1.1/",
&Platform::PyPI,
)),
CheckCategory::Flake8BlindExcept => Some((
"https://pypi.org/project/flake8-blind-except/0.2.1/",
&Platform::PyPI,
)),
CheckCategory::Flake8BooleanTrap => Some((
"https://pypi.org/project/flake8-boolean-trap/0.1.0/",
&Platform::PyPI,
)),
CheckCategory::Flake8Bugbear => Some((
"https://pypi.org/project/flake8-bugbear/22.10.27/",
&Platform::PyPI,
)),
CheckCategory::Flake8Builtins => Some((
"https://pypi.org/project/flake8-builtins/2.0.1/",
&Platform::PyPI,
)),
CheckCategory::Flake8Comprehensions => Some((
"https://pypi.org/project/flake8-comprehensions/3.10.1/",
&Platform::PyPI,
)),
CheckCategory::Flake8Debugger => Some((
"https://pypi.org/project/flake8-debugger/4.1.2/",
&Platform::PyPI,
)),
CheckCategory::Flake8Print => Some((
"https://pypi.org/project/flake8-print/5.0.0/",
&Platform::PyPI,
)),
CheckCategory::Flake8Quotes => Some((
"https://pypi.org/project/flake8-quotes/3.3.1/",
&Platform::PyPI,
)),
CheckCategory::Flake8TidyImports => Some((
"https://pypi.org/project/flake8-tidy-imports/4.8.0/",
&Platform::PyPI,
)),
CheckCategory::Isort => {
Some(("https://pypi.org/project/isort/5.10.1/", &Platform::PyPI))
} }
CheckCategory::Flake8BooleanTrap => { CheckCategory::McCabe => {
Some("https://pypi.org/project/flake8-boolean-trap/0.1.0/") Some(("https://pypi.org/project/mccabe/0.7.0/", &Platform::PyPI))
} }
CheckCategory::Flake8Bugbear => {
Some("https://pypi.org/project/flake8-bugbear/22.10.27/")
}
CheckCategory::Flake8Builtins => {
Some("https://pypi.org/project/flake8-builtins/2.0.1/")
}
CheckCategory::Flake8Comprehensions => {
Some("https://pypi.org/project/flake8-comprehensions/3.10.1/")
}
CheckCategory::Flake8Debugger => {
Some("https://pypi.org/project/flake8-debugger/4.1.2/")
}
CheckCategory::Flake8Print => Some("https://pypi.org/project/flake8-print/5.0.0/"),
CheckCategory::Flake8Quotes => Some("https://pypi.org/project/flake8-quotes/3.3.1/"),
CheckCategory::Flake8TidyImports => {
Some("https://pypi.org/project/flake8-tidy-imports/4.8.0/")
}
CheckCategory::Isort => Some("https://pypi.org/project/isort/5.10.1/"),
CheckCategory::McCabe => Some("https://pypi.org/project/mccabe/0.7.0/"),
CheckCategory::Meta => None, CheckCategory::Meta => None,
CheckCategory::PEP8Naming => Some("https://pypi.org/project/pep8-naming/0.13.2/"), CheckCategory::PEP8Naming => Some((
CheckCategory::Pycodestyle => Some("https://pypi.org/project/pycodestyle/2.9.1/"), "https://pypi.org/project/pep8-naming/0.13.2/",
CheckCategory::Pydocstyle => Some("https://pypi.org/project/pydocstyle/6.1.1/"), &Platform::PyPI,
CheckCategory::Pyflakes => Some("https://pypi.org/project/pyflakes/2.5.0/"), )),
CheckCategory::Pylint => Some("https://pypi.org/project/pylint/2.15.7/"), CheckCategory::Pycodestyle => Some((
CheckCategory::Pyupgrade => Some("https://pypi.org/project/pyupgrade/3.2.0/"), "https://pypi.org/project/pycodestyle/2.9.1/",
&Platform::PyPI,
)),
CheckCategory::Pydocstyle => Some((
"https://pypi.org/project/pydocstyle/6.1.1/",
&Platform::PyPI,
)),
CheckCategory::Pyflakes => {
Some(("https://pypi.org/project/pyflakes/2.5.0/", &Platform::PyPI))
}
CheckCategory::Pylint => {
Some(("https://pypi.org/project/pylint/2.15.7/", &Platform::PyPI))
}
CheckCategory::PygrepHooks => Some((
"https://github.com/pre-commit/pygrep-hooks",
&Platform::GitHub,
)),
CheckCategory::Pyupgrade => {
Some(("https://pypi.org/project/pyupgrade/3.2.0/", &Platform::PyPI))
}
CheckCategory::Ruff => None, CheckCategory::Ruff => None,
} }
} }
@ -657,6 +720,8 @@ pub enum CheckKind {
BooleanPositionalArgInFunctionDefinition, BooleanPositionalArgInFunctionDefinition,
BooleanDefaultValueInFunctionDefinition, BooleanDefaultValueInFunctionDefinition,
BooleanPositionalValueInFunctionCall, BooleanPositionalValueInFunctionCall,
// pygrep-hooks
NoEval,
// Ruff // Ruff
AmbiguousUnicodeCharacterString(char, char), AmbiguousUnicodeCharacterString(char, char),
AmbiguousUnicodeCharacterDocstring(char, char), AmbiguousUnicodeCharacterDocstring(char, char),
@ -975,6 +1040,8 @@ impl CheckCode {
CheckCode::FBT001 => CheckKind::BooleanPositionalArgInFunctionDefinition, CheckCode::FBT001 => CheckKind::BooleanPositionalArgInFunctionDefinition,
CheckCode::FBT002 => CheckKind::BooleanDefaultValueInFunctionDefinition, CheckCode::FBT002 => CheckKind::BooleanDefaultValueInFunctionDefinition,
CheckCode::FBT003 => CheckKind::BooleanPositionalValueInFunctionCall, CheckCode::FBT003 => CheckKind::BooleanPositionalValueInFunctionCall,
// pygrep-hooks
CheckCode::PGH001 => CheckKind::NoEval,
// Ruff // Ruff
CheckCode::RUF001 => CheckKind::AmbiguousUnicodeCharacterString('𝐁', 'B'), CheckCode::RUF001 => CheckKind::AmbiguousUnicodeCharacterString('𝐁', 'B'),
CheckCode::RUF002 => CheckKind::AmbiguousUnicodeCharacterDocstring('𝐁', 'B'), CheckCode::RUF002 => CheckKind::AmbiguousUnicodeCharacterDocstring('𝐁', 'B'),
@ -1169,6 +1236,7 @@ impl CheckCode {
CheckCode::N816 => CheckCategory::PEP8Naming, CheckCode::N816 => CheckCategory::PEP8Naming,
CheckCode::N817 => CheckCategory::PEP8Naming, CheckCode::N817 => CheckCategory::PEP8Naming,
CheckCode::N818 => CheckCategory::PEP8Naming, CheckCode::N818 => CheckCategory::PEP8Naming,
CheckCode::PGH001 => CheckCategory::PygrepHooks,
CheckCode::PLE1142 => CheckCategory::Pylint, CheckCode::PLE1142 => CheckCategory::Pylint,
CheckCode::Q000 => CheckCategory::Flake8Quotes, CheckCode::Q000 => CheckCategory::Flake8Quotes,
CheckCode::Q001 => CheckCategory::Flake8Quotes, CheckCode::Q001 => CheckCategory::Flake8Quotes,
@ -1456,12 +1524,14 @@ impl CheckKind {
CheckKind::HardcodedPasswordString(..) => &CheckCode::S105, CheckKind::HardcodedPasswordString(..) => &CheckCode::S105,
CheckKind::HardcodedPasswordFuncArg(..) => &CheckCode::S106, CheckKind::HardcodedPasswordFuncArg(..) => &CheckCode::S106,
CheckKind::HardcodedPasswordDefault(..) => &CheckCode::S107, CheckKind::HardcodedPasswordDefault(..) => &CheckCode::S107,
// McCabe // mccabe
CheckKind::FunctionIsTooComplex(..) => &CheckCode::C901, CheckKind::FunctionIsTooComplex(..) => &CheckCode::C901,
// flake8-boolean-trap // flake8-boolean-trap
CheckKind::BooleanPositionalArgInFunctionDefinition => &CheckCode::FBT001, CheckKind::BooleanPositionalArgInFunctionDefinition => &CheckCode::FBT001,
CheckKind::BooleanDefaultValueInFunctionDefinition => &CheckCode::FBT002, CheckKind::BooleanDefaultValueInFunctionDefinition => &CheckCode::FBT002,
CheckKind::BooleanPositionalValueInFunctionCall => &CheckCode::FBT003, CheckKind::BooleanPositionalValueInFunctionCall => &CheckCode::FBT003,
// pygrep-hooks
CheckKind::NoEval => &CheckCode::PGH001,
// Ruff // Ruff
CheckKind::AmbiguousUnicodeCharacterString(..) => &CheckCode::RUF001, CheckKind::AmbiguousUnicodeCharacterString(..) => &CheckCode::RUF001,
CheckKind::AmbiguousUnicodeCharacterDocstring(..) => &CheckCode::RUF002, CheckKind::AmbiguousUnicodeCharacterDocstring(..) => &CheckCode::RUF002,
@ -2183,7 +2253,7 @@ impl CheckKind {
} }
// flake8-blind-except // flake8-blind-except
CheckKind::BlindExcept => "Blind except Exception: statement".to_string(), CheckKind::BlindExcept => "Blind except Exception: statement".to_string(),
// McCabe // mccabe
CheckKind::FunctionIsTooComplex(name, complexity) => { CheckKind::FunctionIsTooComplex(name, complexity) => {
format!("`{name}` is too complex ({complexity})") format!("`{name}` is too complex ({complexity})")
} }
@ -2197,6 +2267,8 @@ impl CheckKind {
CheckKind::BooleanPositionalValueInFunctionCall => { CheckKind::BooleanPositionalValueInFunctionCall => {
"Boolean positional value in function call".to_string() "Boolean positional value in function call".to_string()
} }
// pygrep-hooks
CheckKind::NoEval => "No builtin `eval()` allowed".to_string(),
// Ruff // Ruff
CheckKind::AmbiguousUnicodeCharacterString(confusable, representant) => { CheckKind::AmbiguousUnicodeCharacterString(confusable, representant) => {
format!( format!(

View file

@ -278,6 +278,10 @@ pub enum CheckCodePrefix {
N816, N816,
N817, N817,
N818, N818,
PGH,
PGH0,
PGH00,
PGH001,
PLE, PLE,
PLE1, PLE1,
PLE11, PLE11,
@ -1148,6 +1152,10 @@ impl CheckCodePrefix {
CheckCodePrefix::N816 => vec![CheckCode::N816], CheckCodePrefix::N816 => vec![CheckCode::N816],
CheckCodePrefix::N817 => vec![CheckCode::N817], CheckCodePrefix::N817 => vec![CheckCode::N817],
CheckCodePrefix::N818 => vec![CheckCode::N818], CheckCodePrefix::N818 => vec![CheckCode::N818],
CheckCodePrefix::PGH => vec![CheckCode::PGH001],
CheckCodePrefix::PGH0 => vec![CheckCode::PGH001],
CheckCodePrefix::PGH00 => vec![CheckCode::PGH001],
CheckCodePrefix::PGH001 => vec![CheckCode::PGH001],
CheckCodePrefix::PLE => vec![CheckCode::PLE1142], CheckCodePrefix::PLE => vec![CheckCode::PLE1142],
CheckCodePrefix::PLE1 => vec![CheckCode::PLE1142], CheckCodePrefix::PLE1 => vec![CheckCode::PLE1142],
CheckCodePrefix::PLE11 => vec![CheckCode::PLE1142], CheckCodePrefix::PLE11 => vec![CheckCode::PLE1142],
@ -1615,6 +1623,10 @@ impl CheckCodePrefix {
CheckCodePrefix::N816 => SuffixLength::Three, CheckCodePrefix::N816 => SuffixLength::Three,
CheckCodePrefix::N817 => SuffixLength::Three, CheckCodePrefix::N817 => SuffixLength::Three,
CheckCodePrefix::N818 => SuffixLength::Three, CheckCodePrefix::N818 => SuffixLength::Three,
CheckCodePrefix::PGH => SuffixLength::Zero,
CheckCodePrefix::PGH0 => SuffixLength::One,
CheckCodePrefix::PGH00 => SuffixLength::Two,
CheckCodePrefix::PGH001 => SuffixLength::Three,
CheckCodePrefix::PLE => SuffixLength::Zero, CheckCodePrefix::PLE => SuffixLength::Zero,
CheckCodePrefix::PLE1 => SuffixLength::One, CheckCodePrefix::PLE1 => SuffixLength::One,
CheckCodePrefix::PLE11 => SuffixLength::Two, CheckCodePrefix::PLE11 => SuffixLength::Two,
@ -1713,6 +1725,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
CheckCodePrefix::I, CheckCodePrefix::I,
CheckCodePrefix::M, CheckCodePrefix::M,
CheckCodePrefix::N, CheckCodePrefix::N,
CheckCodePrefix::PGH,
CheckCodePrefix::PLE, CheckCodePrefix::PLE,
CheckCodePrefix::Q, CheckCodePrefix::Q,
CheckCodePrefix::RUF, CheckCodePrefix::RUF,

View file

@ -65,6 +65,7 @@ pub mod printer;
mod pycodestyle; mod pycodestyle;
mod pydocstyle; mod pydocstyle;
mod pyflakes; mod pyflakes;
mod pygrep_hooks;
mod pylint; mod pylint;
mod python; mod python;
mod pyupgrade; mod pyupgrade;

View file

@ -0,0 +1,15 @@
use rustpython_ast::{Expr, ExprKind};
use crate::ast::types::Range;
use crate::check_ast::Checker;
use crate::checks::{Check, CheckKind};
pub fn no_eval(checker: &mut Checker, func: &Expr) {
if let ExprKind::Name { id, .. } = &func.node {
if id == "eval" {
if checker.is_builtin("eval") {
checker.add_check(Check::new(CheckKind::NoEval, Range::from_located(func)));
}
}
}
}

30
src/pygrep_hooks/mod.rs Normal file
View file

@ -0,0 +1,30 @@
pub mod checks;
#[cfg(test)]
mod tests {
use std::convert::AsRef;
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::checks::CheckCode;
use crate::linter::test_path;
use crate::settings;
#[test_case(CheckCode::PGH001, Path::new("PGH001_0.py"); "PGH001_0")]
#[test_case(CheckCode::PGH001, Path::new("PGH001_1.py"); "PGH001_1")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(
Path::new("./resources/test/fixtures/pygrep-hooks")
.join(path)
.as_path(),
&settings::Settings::for_rule(check_code),
true,
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}
}

View file

@ -0,0 +1,21 @@
---
source: src/pygrep_hooks/mod.rs
expression: checks
---
- kind: NoEval
location:
row: 3
column: 0
end_location:
row: 3
column: 4
fix: ~
- kind: NoEval
location:
row: 9
column: 4
end_location:
row: 9
column: 8
fix: ~

View file

@ -0,0 +1,6 @@
---
source: src/pygrep_hooks/mod.rs
expression: checks
---
[]