Compare commits

...

6 Commits

Author SHA1 Message Date
Charlie Marsh
b5ab492a70 Bump version to 0.0.187 2022-12-18 20:09:02 -05:00
Charlie Marsh
1fc09ebd5c Fix inverted E501 condition (#1285) 2022-12-18 20:08:30 -05:00
Charlie Marsh
6cf047976c Bump pygrep-hooks tally in README 2022-12-18 18:05:32 -05:00
Reiner Gerecke
87465daacc pygrep-hooks - deprecated use of logging.warn & no blanket type ignore (#1275) 2022-12-18 18:04:21 -05:00
Chris Brendel
a52bed7101 Use --stdin-filename when resolving configuration files (#1281) 2022-12-18 17:51:55 -05:00
Anders Kaseorg
20ac823778 generate-check-code-prefix: Run rustfmt automatically; only write if changed (#1282) 2022-12-18 17:46:23 -05:00
32 changed files with 321 additions and 59 deletions

View File

@@ -39,7 +39,7 @@ jobs:
- run: ./target/release/ruff_dev generate-rules-table
- run: ./target/release/ruff_dev generate-options
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. You may have to rerun 'cargo dev generate-options' and/or 'cargo dev generate-rules-table'."
- run: ./target/release/ruff_dev generate-check-code-prefix && cargo fmt -- src/checks_gen.rs
- run: ./target/release/ruff_dev generate-check-code-prefix
- run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. You may have to rerun 'cargo dev generate-check-code-prefix'."
- run: git diff --exit-code -- README.md src/checks_gen.rs

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.186
rev: v0.0.187
hooks:
- id: ruff

8
Cargo.lock generated
View File

@@ -724,7 +724,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.186-dev.0"
version = "0.0.187-dev.0"
dependencies = [
"anyhow",
"clap 4.0.29",
@@ -1845,7 +1845,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.186"
version = "0.0.187"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1901,7 +1901,7 @@ dependencies = [
[[package]]
name = "ruff_dev"
version = "0.0.186"
version = "0.0.187"
dependencies = [
"anyhow",
"clap 4.0.29",
@@ -1919,7 +1919,7 @@ dependencies = [
[[package]]
name = "ruff_macros"
version = "0.0.186"
version = "0.0.187"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -6,7 +6,7 @@ members = [
[package]
name = "ruff"
version = "0.0.186"
version = "0.0.187"
edition = "2021"
rust-version = "1.65.0"
@@ -43,7 +43,7 @@ quick-junit = { version = "0.3.2" }
rayon = { version = "1.5.3" }
regex = { version = "1.6.0" }
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
ruff_macros = { version = "0.0.186", path = "ruff_macros" }
ruff_macros = { version = "0.0.187", path = "ruff_macros" }
rustc-hash = { version = "1.1.0" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }

View File

@@ -159,7 +159,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
```yaml
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.186
rev: v0.0.187
hooks:
- id: ruff
```
@@ -900,6 +900,8 @@ For more, see [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) on GitH
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PGH001 | NoEval | No builtin `eval()` allowed | |
| PGH002 | DeprecatedLogWarn | `warn` is deprecated in favor of `warning` | |
| PGH003 | BlanketTypeIgnore | Use specific error codes when ignoring type issues | |
### Pylint (PLC, PLE, PLR, PLW)
@@ -1198,7 +1200,7 @@ natively, including:
- [`mccabe`](https://pypi.org/project/mccabe/)
- [`pep8-naming`](https://pypi.org/project/pep8-naming/)
- [`pydocstyle`](https://pypi.org/project/pydocstyle/)
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (1/10)
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/10)
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (16/33)
- [`yesqa`](https://github.com/asottile/yesqa)
@@ -1254,7 +1256,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
Ruff can also replace [`isort`](https://pypi.org/project/isort/),
[`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
[`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/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.

View File

@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8_to_ruff"
version = "0.0.186"
version = "0.0.187"
dependencies = [
"anyhow",
"clap",
@@ -1975,7 +1975,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.186"
version = "0.0.187"
dependencies = [
"anyhow",
"bincode",

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.186-dev.0"
version = "0.0.187-dev.0"
edition = "2021"
[lib]

View File

@@ -55,3 +55,8 @@ sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labor
# OK
# https://loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com
# Not OK
_ = """
Source: https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533
"""

View File

@@ -0,0 +1,8 @@
import logging
import warnings
from warnings import warn
warnings.warn("this is ok")
warn("by itself is also ok")
logging.warning("this is fine")
log.warning("this is ok")

View File

@@ -0,0 +1,15 @@
import logging
from logging import warn
logging.warn("this is not ok")
log.warn("this is also not ok")
warn("not ok")
def foo():
from logging import warn
def warn():
pass
warn("has been redefined, but we will still report it")

View File

@@ -0,0 +1,11 @@
x = 1 # type: ignore
x = 1 # type ignore
x = 1 # type:ignore
x = 1
x = 1 # type ignore # noqa
x = 1 # type: ignore[attr-defined]
x = 1 # type: ignore[attr-defined, name-defined]
x = 1 # type: ignore[type-mismatch] # noqa
x = 1 # type: Union[int, str]
x = 1 # type: ignoreme

View File

@@ -69,3 +69,13 @@ _ = """Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.
""" # noqa
# Valid
# this is a veryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy long comment # noqa: E501
# Valid
_ = """Here's a source: https://github.com/ethereum/web3.py/blob/ffe59daf10edc19ee5f05227b25bac8d090e8aa4/web3/_utils/events.py#L201
May raise:
- DeserializationError if the abi string is invalid or abi or log topics/data do not match
""" # noqa: E501

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_dev"
version = "0.0.186"
version = "0.0.187"
edition = "2021"
[dependencies]

View File

@@ -1,18 +1,18 @@
//! Generate the `CheckCodePrefix` enum.
use std::collections::{BTreeMap, BTreeSet};
use std::fs::OpenOptions;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Output, Stdio};
use anyhow::Result;
use anyhow::{ensure, Result};
use clap::Parser;
use codegen::{Scope, Type, Variant};
use itertools::Itertools;
use ruff::checks::{CheckCode, CODE_REDIRECTS, PREFIX_REDIRECTS};
use strum::IntoEnumIterator;
const FILE: &str = "src/checks_gen.rs";
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
@@ -204,12 +204,25 @@ pub fn main(cli: &Cli) -> Result<()> {
output.push('\n');
output.push('\n');
let rustfmt = Command::new("rustfmt")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
write!(rustfmt.stdin.as_ref().unwrap(), "{output}")?;
let Output { status, stdout, .. } = rustfmt.wait_with_output()?;
ensure!(status.success(), "rustfmt failed with {status}");
// Write the output to `src/checks_gen.rs` (or stdout).
if cli.dry_run {
println!("{output}");
println!("{}", String::from_utf8(stdout)?);
} else {
let mut f = OpenOptions::new().write(true).truncate(true).open(FILE)?;
write!(f, "{output}")?;
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("Failed to find root directory")
.join("src/checks_gen.rs");
if fs::read(&file).map_or(true, |old| old != stdout) {
fs::write(&file, stdout)?;
}
}
Ok(())

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_macros"
version = "0.0.186"
version = "0.0.187"
edition = "2021"
[lib]

View File

@@ -1957,7 +1957,10 @@ where
// pygrep-hooks
if self.settings.enabled.contains(&CheckCode::PGH001) {
pygrep_hooks::checks::no_eval(self, func);
pygrep_hooks::plugins::no_eval(self, func);
}
if self.settings.enabled.contains(&CheckCode::PGH002) {
pygrep_hooks::plugins::deprecated_log_warn(self, func);
}
// pylint

View File

@@ -2,40 +2,58 @@
use crate::checks::{Check, CheckCode};
use crate::pycodestyle::checks::{line_too_long, no_newline_at_end_of_file};
use crate::pygrep_hooks::plugins::blanket_type_ignore;
use crate::pyupgrade::checks::unnecessary_coding_comment;
use crate::settings::{flags, Settings};
pub fn check_lines(contents: &str, settings: &Settings, autofix: flags::Autofix) -> Vec<Check> {
pub fn check_lines(
contents: &str,
commented_lines: &[usize],
settings: &Settings,
autofix: flags::Autofix,
) -> Vec<Check> {
let mut checks: Vec<Check> = vec![];
let enforce_unnecessary_coding_comment = settings.enabled.contains(&CheckCode::UP009);
let enforce_line_too_long = settings.enabled.contains(&CheckCode::E501);
let enforce_no_newline_at_end_of_file = settings.enabled.contains(&CheckCode::W292);
let enforce_blanket_type_ignore = settings.enabled.contains(&CheckCode::PGH003);
for (lineno, line) in contents.lines().enumerate() {
// Enforce unnecessary coding comments (UP009).
if enforce_unnecessary_coding_comment {
if lineno < 2 {
if let Some(check) = unnecessary_coding_comment(
lineno,
line,
matches!(autofix, flags::Autofix::Enabled)
&& settings.fixable.contains(&CheckCode::UP009),
) {
checks.push(check);
let mut commented_lines_iter = commented_lines.iter().peekable();
for (index, line) in contents.lines().enumerate() {
while commented_lines_iter
.next_if(|lineno| &(index + 1) == *lineno)
.is_some()
{
if enforce_unnecessary_coding_comment {
if index < 2 {
if let Some(check) = unnecessary_coding_comment(
index,
line,
matches!(autofix, flags::Autofix::Enabled)
&& settings.fixable.contains(&CheckCode::UP009),
) {
checks.push(check);
}
}
}
if enforce_blanket_type_ignore {
if commented_lines.contains(&(index + 1)) {
if let Some(check) = blanket_type_ignore(index, line) {
checks.push(check);
}
}
}
}
// Enforce line length violations (E501).
if enforce_line_too_long {
if let Some(check) = line_too_long(lineno, line, settings.line_length) {
if let Some(check) = line_too_long(index, line, settings.line_length) {
checks.push(check);
}
}
}
// Enforce newlines at end of files (W292).
if enforce_no_newline_at_end_of_file {
if let Some(check) = no_newline_at_end_of_file(contents) {
checks.push(check);
@@ -58,6 +76,7 @@ mod tests {
let check_with_max_line_length = |line_length: usize| {
check_lines(
line,
&[],
&Settings {
line_length,
..Settings::for_rule(CheckCode::E501)

View File

@@ -316,6 +316,8 @@ pub enum CheckCode {
RUF100,
// pygrep-hooks
PGH001,
PGH002,
PGH003,
// pandas-vet
PDV002,
PDV003,
@@ -887,6 +889,8 @@ pub enum CheckKind {
BooleanPositionalValueInFunctionCall,
// pygrep-hooks
NoEval,
DeprecatedLogWarn,
BlanketTypeIgnore,
// flake8-unused-arguments
UnusedFunctionArgument(String),
UnusedMethodArgument(String),
@@ -925,7 +929,9 @@ impl CheckCode {
pub fn lint_source(&self) -> &'static LintSource {
match self {
CheckCode::RUF100 => &LintSource::NoQA,
CheckCode::E501 | CheckCode::W292 | CheckCode::UP009 => &LintSource::Lines,
CheckCode::E501 | CheckCode::W292 | CheckCode::UP009 | CheckCode::PGH003 => {
&LintSource::Lines
}
CheckCode::ERA001
| CheckCode::Q000
| CheckCode::Q001
@@ -1260,6 +1266,8 @@ impl CheckCode {
CheckCode::FBT003 => CheckKind::BooleanPositionalValueInFunctionCall,
// pygrep-hooks
CheckCode::PGH001 => CheckKind::NoEval,
CheckCode::PGH002 => CheckKind::DeprecatedLogWarn,
CheckCode::PGH003 => CheckKind::BlanketTypeIgnore,
// flake8-unused-arguments
CheckCode::ARG001 => CheckKind::UnusedFunctionArgument("...".to_string()),
CheckCode::ARG002 => CheckKind::UnusedMethodArgument("...".to_string()),
@@ -1504,6 +1512,8 @@ impl CheckCode {
CheckCode::PDV015 => CheckCategory::PandasVet,
CheckCode::PDV901 => CheckCategory::PandasVet,
CheckCode::PGH001 => CheckCategory::PygrepHooks,
CheckCode::PGH002 => CheckCategory::PygrepHooks,
CheckCode::PGH003 => CheckCategory::PygrepHooks,
CheckCode::PLC0414 => CheckCategory::Pylint,
CheckCode::PLC2201 => CheckCategory::Pylint,
CheckCode::PLC3002 => CheckCategory::Pylint,
@@ -1847,6 +1857,8 @@ impl CheckKind {
CheckKind::BooleanPositionalValueInFunctionCall => &CheckCode::FBT003,
// pygrep-hooks
CheckKind::NoEval => &CheckCode::PGH001,
CheckKind::DeprecatedLogWarn => &CheckCode::PGH002,
CheckKind::BlanketTypeIgnore => &CheckCode::PGH003,
// flake8-unused-arguments
CheckKind::UnusedFunctionArgument(..) => &CheckCode::ARG001,
CheckKind::UnusedMethodArgument(..) => &CheckCode::ARG002,
@@ -2684,6 +2696,12 @@ impl CheckKind {
}
// pygrep-hooks
CheckKind::NoEval => "No builtin `eval()` allowed".to_string(),
CheckKind::DeprecatedLogWarn => {
"`warn` is deprecated in favor of `warning`".to_string()
}
CheckKind::BlanketTypeIgnore => {
"Use specific error codes when ignoring type issues".to_string()
}
// flake8-unused-arguments
CheckKind::UnusedFunctionArgument(name) => {
format!("Unused function argument: `{name}`")

View File

@@ -326,6 +326,8 @@ pub enum CheckCodePrefix {
PGH0,
PGH00,
PGH001,
PGH002,
PGH003,
PLC,
PLC0,
PLC04,
@@ -1425,10 +1427,12 @@ impl CheckCodePrefix {
CheckCodePrefix::PDV9 => vec![CheckCode::PDV901],
CheckCodePrefix::PDV90 => vec![CheckCode::PDV901],
CheckCodePrefix::PDV901 => vec![CheckCode::PDV901],
CheckCodePrefix::PGH => vec![CheckCode::PGH001],
CheckCodePrefix::PGH0 => vec![CheckCode::PGH001],
CheckCodePrefix::PGH00 => vec![CheckCode::PGH001],
CheckCodePrefix::PGH => vec![CheckCode::PGH001, CheckCode::PGH002, CheckCode::PGH003],
CheckCodePrefix::PGH0 => vec![CheckCode::PGH001, CheckCode::PGH002, CheckCode::PGH003],
CheckCodePrefix::PGH00 => vec![CheckCode::PGH001, CheckCode::PGH002, CheckCode::PGH003],
CheckCodePrefix::PGH001 => vec![CheckCode::PGH001],
CheckCodePrefix::PGH002 => vec![CheckCode::PGH002],
CheckCodePrefix::PGH003 => vec![CheckCode::PGH003],
CheckCodePrefix::PLC => {
vec![CheckCode::PLC0414, CheckCode::PLC2201, CheckCode::PLC3002]
}
@@ -2259,6 +2263,8 @@ impl CheckCodePrefix {
CheckCodePrefix::PGH0 => SuffixLength::One,
CheckCodePrefix::PGH00 => SuffixLength::Two,
CheckCodePrefix::PGH001 => SuffixLength::Three,
CheckCodePrefix::PGH002 => SuffixLength::Three,
CheckCodePrefix::PGH003 => SuffixLength::Three,
CheckCodePrefix::PLC => SuffixLength::Zero,
CheckCodePrefix::PLC0 => SuffixLength::One,
CheckCodePrefix::PLC04 => SuffixLength::Two,

View File

@@ -120,7 +120,7 @@ pub struct Cli {
pub autoformat: bool,
/// The name of the file when passing it through stdin.
#[arg(long)]
pub stdin_filename: Option<String>,
pub stdin_filename: Option<PathBuf>,
/// Explain a rule.
#[arg(long)]
pub explain: Option<CheckCode>,
@@ -203,7 +203,7 @@ pub struct Arguments {
pub show_files: bool,
pub show_settings: bool,
pub silent: bool,
pub stdin_filename: Option<String>,
pub stdin_filename: Option<PathBuf>,
pub verbose: bool,
pub watch: bool,
}

View File

@@ -126,7 +126,12 @@ pub(crate) fn check_path(
.iter()
.any(|check_code| matches!(check_code.lint_source(), LintSource::Lines))
{
checks.extend(check_lines(contents, settings, autofix));
checks.extend(check_lines(
contents,
&directives.commented_lines,
settings,
autofix,
));
}
// Enforce `noqa` directives.

View File

@@ -35,18 +35,27 @@ use path_absolutize::path_dedot;
/// Resolve the relevant settings strategy and defaults for the current
/// invocation.
fn resolve(config: Option<PathBuf>, overrides: &Overrides) -> Result<PyprojectDiscovery> {
fn resolve(
config: Option<&Path>,
overrides: &Overrides,
stdin_filename: Option<&Path>,
) -> Result<PyprojectDiscovery> {
if let Some(pyproject) = config {
// First priority: the user specified a `pyproject.toml` file. Use that
// `pyproject.toml` for _all_ configuration, and resolve paths relative to the
// current working directory. (This matches ESLint's behavior.)
let settings = resolve_settings(&pyproject, &Relativity::Cwd, Some(overrides))?;
let settings = resolve_settings(pyproject, &Relativity::Cwd, Some(overrides))?;
Ok(PyprojectDiscovery::Fixed(settings))
} else if let Some(pyproject) = pyproject::find_pyproject_toml(path_dedot::CWD.as_path())? {
// Second priority: find a `pyproject.toml` file in the current working path,
// and resolve all paths relative to that directory. (With
// `Strategy::Hierarchical`, we'll end up finding the "closest" `pyproject.toml`
// file for every Python file later on, so these act as the "default" settings.)
} else if let Some(pyproject) = pyproject::find_pyproject_toml(
stdin_filename
.as_ref()
.unwrap_or(&path_dedot::CWD.as_path()),
)? {
// Second priority: find a `pyproject.toml` file in either an ancestor of
// `stdin_filename` (if set) or the current working path all paths relative to
// that directory. (With `Strategy::Hierarchical`, we'll end up finding
// the "closest" `pyproject.toml` file for every Python file later on,
// so these act as the "default" settings.)
let settings = resolve_settings(&pyproject, &Relativity::Parent, Some(overrides))?;
Ok(PyprojectDiscovery::Hierarchical(settings))
} else if let Some(pyproject) = pyproject::find_user_pyproject_toml() {
@@ -85,7 +94,11 @@ fn inner_main() -> Result<ExitCode> {
// Construct the "default" settings. These are used when no `pyproject.toml`
// files are present, or files are injected from outside of the hierarchy.
let pyproject_strategy = resolve(cli.config, &overrides)?;
let pyproject_strategy = resolve(
cli.config.as_deref(),
&overrides,
cli.stdin_filename.as_deref(),
)?;
// Extract options that are included in `Settings`, but only apply at the top
// level.
@@ -207,9 +220,8 @@ fn inner_main() -> Result<ExitCode> {
// Generate lint violations.
let diagnostics = if is_stdin {
let filename = cli.stdin_filename.unwrap_or_else(|| "-".to_string());
let path = Path::new(&filename);
commands::run_stdin(&pyproject_strategy, path, autofix)?
let path = cli.stdin_filename.unwrap_or_else(|| PathBuf::from("-"));
commands::run_stdin(&pyproject_strategy, &path, autofix)?
} else {
commands::run(
&cli.files,

View File

@@ -26,7 +26,7 @@ pub fn line_too_long(lineno: usize, line: &str, max_line_length: usize) -> Optio
// Do not enforce the line length for commented lines that end with a URL
// or contain only a single word.
if first == "#" || chunks.last().map_or(true, |c| URL_REGEX.is_match(c)) {
if first == "#" && chunks.last().map_or(true, |c| URL_REGEX.is_match(c)) {
return None;
}

View File

@@ -46,4 +46,15 @@ expression: checks
row: 43
column: 105
fix: ~
- kind:
LineTooLong:
- 129
- 88
location:
row: 61
column: 88
end_location:
row: 61
column: 129
fix: ~

View File

@@ -1,4 +1,4 @@
pub mod checks;
pub mod plugins;
#[cfg(test)]
mod tests {
@@ -14,6 +14,9 @@ mod tests {
#[test_case(CheckCode::PGH001, Path::new("PGH001_0.py"); "PGH001_0")]
#[test_case(CheckCode::PGH001, Path::new("PGH001_1.py"); "PGH001_1")]
#[test_case(CheckCode::PGH002, Path::new("PGH002_0.py"); "PGH002_0")]
#[test_case(CheckCode::PGH002, Path::new("PGH002_1.py"); "PGH002_1")]
#[test_case(CheckCode::PGH003, Path::new("PGH003_0.py"); "PGH003_0")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(

View File

@@ -0,0 +1,22 @@
use once_cell::sync::Lazy;
use regex::Regex;
use rustpython_ast::Location;
use crate::ast::types::Range;
use crate::checks::{Check, CheckKind};
static BLANKET_TYPE_IGNORE_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"# type:? *ignore($|\s)").unwrap());
/// PGH003 - use of blanket type ignore comments
pub fn blanket_type_ignore(lineno: usize, line: &str) -> Option<Check> {
BLANKET_TYPE_IGNORE_REGEX.find(line).map(|m| {
Check::new(
CheckKind::BlanketTypeIgnore,
Range {
location: Location::new(lineno + 1, m.start()),
end_location: Location::new(lineno + 1, m.end()),
},
)
})
}

View File

@@ -0,0 +1,19 @@
use rustpython_ast::Expr;
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
/// PGH002 - deprecated use of logging.warn
pub fn deprecated_log_warn(checker: &mut Checker, func: &Expr) {
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
if call_path == ["log", "warn"]
|| match_call_path(&call_path, "logging", "warn", &checker.from_imports)
{
checker.add_check(Check::new(
CheckKind::DeprecatedLogWarn,
Range::from_located(func),
));
}
}

View File

@@ -0,0 +1,7 @@
pub use blanket_type_ignore::blanket_type_ignore;
pub use deprecated_log_warn::deprecated_log_warn;
pub use no_eval::no_eval;
mod blanket_type_ignore;
mod deprecated_log_warn;
mod no_eval;

View File

@@ -4,6 +4,7 @@ use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
/// PGH001 - no eval
pub fn no_eval(checker: &mut Checker, func: &Expr) {
let ExprKind::Name { id, .. } = &func.node else {
return;

View File

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

View File

@@ -0,0 +1,37 @@
---
source: src/pygrep_hooks/mod.rs
expression: checks
---
- kind: DeprecatedLogWarn
location:
row: 4
column: 0
end_location:
row: 4
column: 12
fix: ~
- kind: DeprecatedLogWarn
location:
row: 5
column: 0
end_location:
row: 5
column: 8
fix: ~
- kind: DeprecatedLogWarn
location:
row: 6
column: 0
end_location:
row: 6
column: 4
fix: ~
- kind: DeprecatedLogWarn
location:
row: 15
column: 4
end_location:
row: 15
column: 8
fix: ~

View File

@@ -0,0 +1,29 @@
---
source: src/pygrep_hooks/mod.rs
expression: checks
---
- kind: BlanketTypeIgnore
location:
row: 1
column: 7
end_location:
row: 1
column: 21
fix: ~
- kind: BlanketTypeIgnore
location:
row: 2
column: 7
end_location:
row: 2
column: 20
fix: ~
- kind: BlanketTypeIgnore
location:
row: 3
column: 7
end_location:
row: 3
column: 20
fix: ~