This commit is contained in:
tluolamo 2025-12-16 16:37:08 -05:00 committed by GitHub
commit 5dab8e8064
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 228 additions and 1 deletions

View File

@ -259,6 +259,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -261,6 +261,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -263,6 +263,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -263,6 +263,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -260,6 +260,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -260,6 +260,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -259,6 +259,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -259,6 +259,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -259,6 +259,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -372,6 +372,7 @@ linter.pylint.max_statements = 50
linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pylint.max_nested_blocks = 5
linter.pylint.max_module_lines = 1000
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false

View File

@ -78,6 +78,10 @@ pub(crate) fn check_physical_lines(
if enforce_copyright_notice {
missing_copyright_notice(locator, settings, context);
}
if context.is_rule_enabled(Rule::TooManyLines) {
pylint::rules::too_many_lines(locator, settings, context);
}
}
#[cfg(test)]

View File

@ -221,6 +221,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "C0206") => rules::pylint::rules::DictIndexMissingItems,
(Pylint, "C0207") => rules::pylint::rules::MissingMaxsplitArg,
(Pylint, "C0208") => rules::pylint::rules::IterationOverSet,
(Pylint, "C0302") => rules::pylint::rules::TooManyLines,
(Pylint, "C0414") => rules::pylint::rules::UselessImportAlias,
(Pylint, "C0415") => rules::pylint::rules::ImportOutsideTopLevel,
(Pylint, "C1802") => rules::pylint::rules::LenTest,

View File

@ -259,6 +259,7 @@ impl Rule {
| Rule::MissingCopyrightNotice
| Rule::MissingNewlineAtEndOfFile
| Rule::MixedSpacesAndTabs
| Rule::TooManyLines
| Rule::TrailingWhitespace => LintSource::PhysicalLines,
Rule::AmbiguousUnicodeCharacterComment
| Rule::BlanketTypeIgnore

View File

@ -0,0 +1,33 @@
//! Settings for the `flake8-lineleak` plugin.
use std::fmt::{Display, Formatter};
use ruff_macros::CacheKey;
use crate::display_settings;
#[derive(Debug, Clone, CacheKey)]
pub struct Settings {
pub max_line_count: usize,
}
impl Default for Settings {
fn default() -> Self {
Self {
max_line_count: 100,
}
}
}
impl Display for Settings {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
display_settings! {
formatter = f,
namespace = "linter.flake8_lineleak",
fields = [
self.max_line_count,
]
}
Ok(())
}
}

View File

@ -470,4 +470,90 @@ mod tests {
assert_diagnostics!(diagnostics);
Ok(())
}
#[test]
fn too_many_lines_below_limit() {
use crate::test::test_snippet;
let diagnostics = test_snippet(
r"
# Line 1
# Line 2
# Line 3
import os
"
.trim(),
&LinterSettings {
preview: PreviewMode::Enabled,
pylint: pylint::settings::Settings {
max_module_lines: 1000,
..pylint::settings::Settings::default()
},
..LinterSettings::for_rules(vec![Rule::TooManyLines])
},
);
assert_diagnostics!(diagnostics);
}
#[test]
fn too_many_lines_exceeds_limit() {
use crate::test::test_snippet;
let diagnostics = test_snippet(
r"
# Line 1
# Line 2
# Line 3
# Line 4
# Line 5
# Line 6
# Line 7
# Line 8
# Line 9
# Line 10
# Line 11
import os
"
.trim(),
&LinterSettings {
preview: PreviewMode::Enabled,
pylint: pylint::settings::Settings {
max_module_lines: 10,
..pylint::settings::Settings::default()
},
..LinterSettings::for_rules(vec![Rule::TooManyLines])
},
);
assert!(!diagnostics.is_empty());
}
#[test]
fn too_many_lines_at_limit() {
use crate::test::test_snippet;
let diagnostics = test_snippet(
r"
# Line 1
# Line 2
# Line 3
# Line 4
# Line 5
# Line 6
# Line 7
# Line 8
# Line 9
# Line 10
"
.trim(),
&LinterSettings {
preview: PreviewMode::Enabled,
pylint: pylint::settings::Settings {
max_module_lines: 10,
..pylint::settings::Settings::default()
},
..LinterSettings::for_rules(vec![Rule::TooManyLines])
},
);
assert_diagnostics!(diagnostics);
}
}

View File

@ -83,6 +83,7 @@ pub(crate) use sys_exit_alias::*;
pub(crate) use too_many_arguments::*;
pub(crate) use too_many_boolean_expressions::*;
pub(crate) use too_many_branches::*;
pub(crate) use too_many_lines::*;
pub(crate) use too_many_locals::*;
pub(crate) use too_many_nested_blocks::*;
pub(crate) use too_many_positional_arguments::*;
@ -194,6 +195,7 @@ mod sys_exit_alias;
mod too_many_arguments;
mod too_many_boolean_expressions;
mod too_many_branches;
mod too_many_lines;
mod too_many_locals;
mod too_many_nested_blocks;
mod too_many_positional_arguments;

View File

@ -0,0 +1,58 @@
use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_text_size::TextRange;
use crate::Locator;
use crate::Violation;
use crate::checkers::ast::LintContext;
use crate::settings::LinterSettings;
/// ## What it does
/// Checks for modules with too many lines.
///
/// By default, this rule allows up to 1000 lines, as configured by the
/// [`lint.pylint.max-module-lines`] option.
///
/// ## Why is this bad?
/// Modules with many lines are generally harder to read and understand.
/// Extracting functionality into separate modules can improve code organization
/// and maintainability.
///
/// ## Example
/// A module with 1500 lines when `max-module-lines` is set to 1000 will trigger
/// this rule.
///
/// ## Options
/// - `lint.pylint.max-module-lines`
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.14.9")]
pub(crate) struct TooManyLines {
actual_lines: usize,
max_lines: usize,
}
impl Violation for TooManyLines {
#[derive_message_formats]
fn message(&self) -> String {
let TooManyLines {
actual_lines,
max_lines,
} = self;
format!("Too many lines in module ({actual_lines}/{max_lines})")
}
}
/// C0302
pub(crate) fn too_many_lines(locator: &Locator, settings: &LinterSettings, context: &LintContext) {
let actual_lines = locator.contents().lines().count();
let max_lines = settings.pylint.max_module_lines;
if actual_lines > max_lines {
context.report_diagnostic(
TooManyLines {
actual_lines,
max_lines,
},
TextRange::default(),
);
}
}

View File

@ -61,6 +61,7 @@ pub struct Settings {
pub max_public_methods: usize,
pub max_locals: usize,
pub max_nested_blocks: usize,
pub max_module_lines: usize,
}
impl Default for Settings {
@ -77,6 +78,7 @@ impl Default for Settings {
max_public_methods: 20,
max_locals: 15,
max_nested_blocks: 5,
max_module_lines: 1000,
}
}
}
@ -97,7 +99,8 @@ impl fmt::Display for Settings {
self.max_statements,
self.max_public_methods,
self.max_locals,
self.max_nested_blocks
self.max_nested_blocks,
self.max_module_lines
]
}
Ok(())

View File

@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---

View File

@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---

View File

@ -3343,6 +3343,14 @@ pub struct PylintOptions {
example = r"max-nested-blocks = 10"
)]
pub max_nested_blocks: Option<usize>,
/// Maximum number of lines allowed in a module (see `PLC0302`).
#[option(
default = r"1000",
value_type = "int",
example = r"max-module-lines = 1500"
)]
pub max_module_lines: Option<usize>,
}
impl PylintOptions {
@ -3367,6 +3375,7 @@ impl PylintOptions {
.unwrap_or(defaults.max_public_methods),
max_locals: self.max_locals.unwrap_or(defaults.max_locals),
max_nested_blocks: self.max_nested_blocks.unwrap_or(defaults.max_nested_blocks),
max_module_lines: self.max_module_lines.unwrap_or(defaults.max_module_lines),
}
}
}

12
ruff.schema.json generated
View File

@ -2794,6 +2794,15 @@
"format": "uint",
"minimum": 0
},
"max-module-lines": {
"description": "Maximum number of lines allowed in a module (see `PLC0302`).",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"max-nested-blocks": {
"description": "Maximum number of nested blocks allowed within a function or method body\n(see `PLR1702`).",
"type": [
@ -3590,6 +3599,9 @@
"PLC0206",
"PLC0207",
"PLC0208",
"PLC03",
"PLC030",
"PLC0302",
"PLC04",
"PLC041",
"PLC0414",