mirror of https://github.com/astral-sh/ruff
feat: plugin scaffold for tryceratops with TRY300 (#2055)
Renamed to TRY to avoid conflicts, as proposed in https://github.com/guilatrova/tryceratops/pull/55 https://github.com/guilatrova/tryceratops/blob/main/docs/violations/TC300.md See: #2056
This commit is contained in:
parent
0c30768288
commit
afcf5c0ee0
|
|
@ -140,6 +140,7 @@ developer of [Zulip](https://github.com/zulip/zulip):
|
|||
1. [flake8-no-pep420 (INP)](#flake8-no-pep420-inp)
|
||||
1. [flake8-executable (EXE)](#flake8-executable-exe)
|
||||
1. [flake8-type-checking (TYP)](#flake8-type-checking-typ)
|
||||
1. [tryceratops (TRY)](#tryceratops-try)
|
||||
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
|
||||
1. [Editor Integrations](#editor-integrations)
|
||||
1. [FAQ](#faq)
|
||||
|
|
@ -1187,6 +1188,14 @@ For more, see [flake8-type-checking](https://pypi.org/project/flake8-type-checki
|
|||
| ---- | ---- | ------- | --- |
|
||||
| TYP005 | empty-type-checking-block | Found empty type-checking block | |
|
||||
|
||||
### tryceratops (TRY)
|
||||
|
||||
For more, see [tryceratops](https://pypi.org/project/tryceratops/1.1.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| TRY300 | try-consider-else | Consider `else` block | |
|
||||
|
||||
### Ruff-specific rules (RUF)
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
Violation:
|
||||
|
||||
Returning a final value inside a try block may indicate you could use an else block
|
||||
instead to outline the success scenario
|
||||
"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MyException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def bad():
|
||||
try:
|
||||
a = 1
|
||||
b = process()
|
||||
return b
|
||||
except MyException:
|
||||
logger.exception("process failed")
|
||||
|
||||
|
||||
def good():
|
||||
try:
|
||||
a = 1
|
||||
b = process()
|
||||
except MyException:
|
||||
logger.exception("process failed")
|
||||
else:
|
||||
return b
|
||||
|
||||
|
||||
def noreturn():
|
||||
try:
|
||||
a = 1
|
||||
b = process()
|
||||
except MyException:
|
||||
logger.exception("process failed")
|
||||
|
||||
|
||||
def still_good():
|
||||
try:
|
||||
return process()
|
||||
except MyException:
|
||||
logger.exception("process failed")
|
||||
|
|
@ -1747,6 +1747,10 @@
|
|||
"TID25",
|
||||
"TID251",
|
||||
"TID252",
|
||||
"TRY",
|
||||
"TRY3",
|
||||
"TRY30",
|
||||
"TRY300",
|
||||
"TYP",
|
||||
"TYP0",
|
||||
"TYP00",
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ use crate::rules::{
|
|||
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pie, flake8_print,
|
||||
flake8_pytest_style, flake8_return, flake8_simplify, flake8_tidy_imports, flake8_type_checking,
|
||||
flake8_unused_arguments, mccabe, pandas_vet, pep8_naming, pycodestyle, pydocstyle, pyflakes,
|
||||
pygrep_hooks, pylint, pyupgrade, ruff,
|
||||
pygrep_hooks, pylint, pyupgrade, ruff, tryceratops,
|
||||
};
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::{flags, Settings};
|
||||
|
|
@ -1544,6 +1544,9 @@ where
|
|||
self, body, handlers, finalbody,
|
||||
);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::TryConsiderElse) {
|
||||
tryceratops::rules::try_consider_else(self, body, orelse);
|
||||
}
|
||||
}
|
||||
StmtKind::Assign { targets, value, .. } => {
|
||||
if self.settings.rules.enabled(&Rule::DoNotAssignLambda) {
|
||||
|
|
|
|||
|
|
@ -427,6 +427,8 @@ ruff_macros::define_rule_mapping!(
|
|||
EXE005 => rules::flake8_executable::rules::ShebangNewline,
|
||||
// flake8-type-checking
|
||||
TYP005 => rules::flake8_type_checking::rules::EmptyTypeCheckingBlock,
|
||||
// tryceratops
|
||||
TRY300 => rules::tryceratops::rules::TryConsiderElse,
|
||||
// Ruff
|
||||
RUF001 => violations::AmbiguousUnicodeCharacterString,
|
||||
RUF002 => violations::AmbiguousUnicodeCharacterDocstring,
|
||||
|
|
@ -511,6 +513,8 @@ pub enum Linter {
|
|||
Flake8Executable,
|
||||
#[prefix = "TYP"]
|
||||
Flake8TypeChecking,
|
||||
#[prefix = "TRY"]
|
||||
Tryceratops,
|
||||
#[prefix = "RUF"]
|
||||
Ruff,
|
||||
}
|
||||
|
|
@ -585,6 +589,7 @@ impl Linter {
|
|||
Linter::Flake8NoPep420 => Prefixes::Single(RuleSelector::INP),
|
||||
Linter::Flake8Executable => Prefixes::Single(RuleSelector::EXE),
|
||||
Linter::Flake8TypeChecking => Prefixes::Single(RuleSelector::TYP),
|
||||
Linter::Tryceratops => Prefixes::Single(RuleSelector::TRY),
|
||||
Linter::Ruff => Prefixes::Single(RuleSelector::RUF),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,3 +36,4 @@ pub mod pygrep_hooks;
|
|||
pub mod pylint;
|
||||
pub mod pyupgrade;
|
||||
pub mod ruff;
|
||||
pub mod tryceratops;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
//! Rules from [tryceratops](https://pypi.org/project/tryceratops/1.1.0/).
|
||||
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::linter::test_path;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings;
|
||||
|
||||
#[test_case(Rule::TryConsiderElse, Path::new("TRY300.py"); "TRY300")]
|
||||
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("./resources/test/fixtures/tryceratops")
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
)?;
|
||||
insta::assert_yaml_snapshot!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
pub use try_consider_else::{try_consider_else, TryConsiderElse};
|
||||
|
||||
mod try_consider_else;
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct TryConsiderElse;
|
||||
);
|
||||
impl Violation for TryConsiderElse {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Consider `else` block")
|
||||
}
|
||||
}
|
||||
|
||||
/// TRY300
|
||||
pub fn try_consider_else(checker: &mut Checker, body: &[Stmt], orelse: &[Stmt]) {
|
||||
if body.len() > 1 && orelse.is_empty() {
|
||||
if let Some(stmt) = body.last() {
|
||||
if let StmtKind::Return { .. } = &stmt.node {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
TryConsiderElse,
|
||||
Range::from_located(&body[0]),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
source: src/rules/tryceratops/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
TryConsiderElse: ~
|
||||
location:
|
||||
row: 18
|
||||
column: 8
|
||||
end_location:
|
||||
row: 18
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
Loading…
Reference in New Issue