mirror of https://github.com/astral-sh/ruff
Merge bc0ad6ec5a into b0bc990cbf
This commit is contained in:
commit
57287a8797
|
|
@ -1189,6 +1189,16 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||||
(Flake8Logging, "014") => rules::flake8_logging::rules::ExcInfoOutsideExceptHandler,
|
(Flake8Logging, "014") => rules::flake8_logging::rules::ExcInfoOutsideExceptHandler,
|
||||||
(Flake8Logging, "015") => rules::flake8_logging::rules::RootLoggerCall,
|
(Flake8Logging, "015") => rules::flake8_logging::rules::RootLoggerCall,
|
||||||
|
|
||||||
|
// flake8-mock-spec
|
||||||
|
(Flake8MockSpec, "010") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::Mock),
|
||||||
|
(Flake8MockSpec, "011") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::MagicMock),
|
||||||
|
(Flake8MockSpec, "012") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::NonCallableMock),
|
||||||
|
(Flake8MockSpec, "013") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::AsyncMock),
|
||||||
|
(Flake8MockSpec, "014") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::ThreadingMock),
|
||||||
|
(Flake8MockSpec, "020") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::Patch),
|
||||||
|
(Flake8MockSpec, "021") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::PatchObject),
|
||||||
|
(Flake8MockSpec, "022") => (RuleGroup::Preview, rules::flake8_mock_spec::rules::PatchMultiple),
|
||||||
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,9 @@ pub enum Linter {
|
||||||
/// [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
/// [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
||||||
#[prefix = "G"]
|
#[prefix = "G"]
|
||||||
Flake8LoggingFormat,
|
Flake8LoggingFormat,
|
||||||
|
/// [flake8-mock-spec](https://pypi.org/project/flake8-mock-spec/)
|
||||||
|
#[prefix = "TMS"]
|
||||||
|
Flake8MockSpec,
|
||||||
/// [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420/)
|
/// [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420/)
|
||||||
#[prefix = "INP"]
|
#[prefix = "INP"]
|
||||||
Flake8NoPep420,
|
Flake8NoPep420,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct AsyncMock;
|
||||||
|
|
||||||
|
impl Violation for AsyncMock {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.AsyncMock` without `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "AsyncMock"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_argument("spec", 0).is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(AsyncMock, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct MagicMock;
|
||||||
|
|
||||||
|
impl Violation for MagicMock {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.MagicMock` without `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "MagicMock"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_argument("spec", 0).is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(MagicMock, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct Mock;
|
||||||
|
|
||||||
|
impl Violation for Mock {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.Mock` without `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "Mock"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_argument("spec", 0).is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(Mock, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct NonCallableMock;
|
||||||
|
|
||||||
|
impl Violation for NonCallableMock {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.NonCallableMock` without `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "NonCallableMock"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_argument("spec", 0).is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(NonCallableMock, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct Patch;
|
||||||
|
|
||||||
|
impl Violation for Patch {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.patch` without one any `autospec`, `new`, `new_callable`, `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "patch"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_keyword("autospec").is_none()
|
||||||
|
&& call.arguments.find_argument("new", 1).is_none()
|
||||||
|
&& call.arguments.find_keyword("new_callable").is_none()
|
||||||
|
&& call.arguments.find_keyword("spec").is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(Patch, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct PatchMultiple;
|
||||||
|
|
||||||
|
impl Violation for PatchMultiple {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.patch.multiple` without one any `autospec`, `new`, `new_callable`, `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "patch", "multiple"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_keyword("autospec").is_none()
|
||||||
|
&& call.arguments.find_keyword("new_callable").is_none()
|
||||||
|
&& call.arguments.find_argument("spec", 1).is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(PatchMultiple, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct PatchObject;
|
||||||
|
|
||||||
|
impl Violation for PatchObject {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.patch.object` without one any `autospec`, `new`, `new_callable`, `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "patch", "object"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_keyword("autospec").is_none()
|
||||||
|
&& call.arguments.find_argument("new", 2).is_none()
|
||||||
|
&& call.arguments.find_keyword("new_callable").is_none()
|
||||||
|
&& call.arguments.find_keyword("spec").is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(PatchObject, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::Violation;
|
||||||
|
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct ThreadingMock;
|
||||||
|
|
||||||
|
impl Violation for ThreadingMock {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"`unittest.mock.ThreadingMock` without `spec` or `spec_set` argument".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mock(checker: &Checker, call: &ast::ExprCall) {
|
||||||
|
if !checker.semantic().seen_module(Modules::UNITTEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(&call.func)
|
||||||
|
.is_some_and(|qualified_name| {
|
||||||
|
matches!(qualified_name.segments(), ["unittest", "mock", "ThreadingMock"])
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if call.arguments.find_argument("spec", 0).is_none()
|
||||||
|
&& call.arguments.find_keyword("spec_set").is_none()
|
||||||
|
{
|
||||||
|
let mut diagnostic = checker.report_diagnostic(ThreadingMock, call.func.range());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1486,6 +1486,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
"airflow" => self.seen.insert(Modules::AIRFLOW),
|
"airflow" => self.seen.insert(Modules::AIRFLOW),
|
||||||
"hashlib" => self.seen.insert(Modules::HASHLIB),
|
"hashlib" => self.seen.insert(Modules::HASHLIB),
|
||||||
"crypt" => self.seen.insert(Modules::CRYPT),
|
"crypt" => self.seen.insert(Modules::CRYPT),
|
||||||
|
"unittest" => self.seen.insert(Modules::UNITTEST),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2254,6 +2255,7 @@ bitflags! {
|
||||||
const AIRFLOW = 1 << 27;
|
const AIRFLOW = 1 << 27;
|
||||||
const HASHLIB = 1 << 28;
|
const HASHLIB = 1 << 28;
|
||||||
const CRYPT = 1 << 29;
|
const CRYPT = 1 << 29;
|
||||||
|
const UNITTEST = 1 << 30;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue