@@ -8,6 +8,7 @@ use ruff_diagnostics::Diagnostic;
8
8
use ruff_diagnostics:: Edit ;
9
9
use ruff_diagnostics:: Fix ;
10
10
use ruff_macros:: { derive_message_formats, violation} ;
11
+ use ruff_python_ast:: PySourceType ;
11
12
use ruff_python_codegen:: Stylist ;
12
13
use ruff_python_parser:: lexer:: LexResult ;
13
14
use ruff_python_parser:: lexer:: LexicalError ;
@@ -51,9 +52,14 @@ const BLANK_LINES_NESTED_LEVEL: u32 = 1;
51
52
/// pass
52
53
/// ```
53
54
///
55
+ /// ## Typing stub files (`.pyi`)
56
+ /// The typing style guide recommends to not use blank lines between methods except to group
57
+ /// them. That's why this rule is not enabled in typing stub files.
58
+ ///
54
59
/// ## References
55
60
/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines)
56
61
/// - [Flake 8 rule](https://www.flake8rules.com/rules/E301.html)
62
+ /// - [Typing Style Guide](https://typing.readthedocs.io/en/latest/source/stubs.html#blank-lines)
57
63
#[ violation]
58
64
pub struct BlankLineBetweenMethods ;
59
65
@@ -96,9 +102,14 @@ impl AlwaysFixableViolation for BlankLineBetweenMethods {
96
102
/// pass
97
103
/// ```
98
104
///
105
+ /// ## Typing stub files (`.pyi`)
106
+ /// The typing style guide recommends to not use blank lines between classes and functions except to group
107
+ /// them. That's why this rule is not enabled in typing stub files.
108
+ ///
99
109
/// ## References
100
110
/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines)
101
111
/// - [Flake 8 rule](https://www.flake8rules.com/rules/E302.html)
112
+ /// - [Typing Style Guide](https://typing.readthedocs.io/en/latest/source/stubs.html#blank-lines)
102
113
#[ violation]
103
114
pub struct BlankLinesTopLevel {
104
115
actual_blank_lines : u32 ,
@@ -150,13 +161,17 @@ impl AlwaysFixableViolation for BlankLinesTopLevel {
150
161
/// pass
151
162
/// ```
152
163
///
164
+ /// ## Typing stub files (`.pyi`)
165
+ /// The rule allows at most one blank line in typing stub files in accordance to the typing style guide recommendation.
166
+ ///
153
167
/// Note: The rule respects the following `isort` settings when determining the maximum number of blank lines allowed between two statements:
154
168
/// * [`lint.isort.lines-after-imports`]: For top-level statements directly following an import statement.
155
169
/// * [`lint.isort.lines-between-types`]: For `import` statements directly following a `from ... import ...` statement or vice versa.
156
170
///
157
171
/// ## References
158
172
/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines)
159
173
/// - [Flake 8 rule](https://www.flake8rules.com/rules/E303.html)
174
+ /// - [Typing Style Guide](https://typing.readthedocs.io/en/latest/source/stubs.html#blank-lines)
160
175
#[ violation]
161
176
pub struct TooManyBlankLines {
162
177
actual_blank_lines : u32 ,
@@ -246,9 +261,14 @@ impl AlwaysFixableViolation for BlankLineAfterDecorator {
246
261
/// user = User()
247
262
/// ```
248
263
///
264
+ /// ## Typing stub files (`.pyi`)
265
+ /// The typing style guide recommends to not use blank lines between statements except to group
266
+ /// them. That's why this rule is not enabled in typing stub files.
267
+ ///
249
268
/// ## References
250
269
/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines)
251
270
/// - [Flake 8 rule](https://www.flake8rules.com/rules/E305.html)
271
+ /// - [Typing Style Guide](https://typing.readthedocs.io/en/latest/source/stubs.html#blank-lines)
252
272
#[ violation]
253
273
pub struct BlankLinesAfterFunctionOrClass {
254
274
actual_blank_lines : u32 ,
@@ -295,9 +315,14 @@ impl AlwaysFixableViolation for BlankLinesAfterFunctionOrClass {
295
315
/// pass
296
316
/// ```
297
317
///
318
+ /// ## Typing stub files (`.pyi`)
319
+ /// The typing style guide recommends to not use blank lines between classes and functions except to group
320
+ /// them. That's why this rule is not enabled in typing stub files.
321
+ ///
298
322
/// ## References
299
323
/// - [PEP 8](https://peps.python.org/pep-0008/#blank-lines)
300
324
/// - [Flake 8 rule](https://www.flake8rules.com/rules/E306.html)
325
+ /// - [Typing Style Guide](https://typing.readthedocs.io/en/latest/source/stubs.html#blank-lines)
301
326
#[ violation]
302
327
pub struct BlankLinesBeforeNestedDefinition ;
303
328
@@ -628,20 +653,23 @@ pub(crate) struct BlankLinesChecker<'a> {
628
653
indent_width : IndentWidth ,
629
654
lines_after_imports : isize ,
630
655
lines_between_types : usize ,
656
+ source_type : PySourceType ,
631
657
}
632
658
633
659
impl < ' a > BlankLinesChecker < ' a > {
634
660
pub ( crate ) fn new (
635
661
locator : & ' a Locator < ' a > ,
636
662
stylist : & ' a Stylist < ' a > ,
637
663
settings : & crate :: settings:: LinterSettings ,
664
+ source_type : PySourceType ,
638
665
) -> BlankLinesChecker < ' a > {
639
666
BlankLinesChecker {
640
667
stylist,
641
668
locator,
642
669
indent_width : settings. tab_size ,
643
670
lines_after_imports : settings. isort . lines_after_imports ,
644
671
lines_between_types : settings. isort . lines_between_types ,
672
+ source_type,
645
673
}
646
674
}
647
675
@@ -739,6 +767,8 @@ impl<'a> BlankLinesChecker<'a> {
739
767
&& !matches ! ( state. follows, Follows :: Docstring | Follows :: Decorator )
740
768
// Do not trigger when the def follows an if/while/etc...
741
769
&& prev_indent_length. is_some_and ( |prev_indent_length| prev_indent_length >= line. indent_length )
770
+ // Blank lines in stub files are only used for grouping. Don't enforce blank lines.
771
+ && !self . source_type . is_stub ( )
742
772
{
743
773
// E301
744
774
let mut diagnostic = Diagnostic :: new ( BlankLineBetweenMethods , line. first_token_range ) ;
@@ -750,20 +780,31 @@ impl<'a> BlankLinesChecker<'a> {
750
780
diagnostics. push ( diagnostic) ;
751
781
}
752
782
783
+ // Blank lines in stub files are used to group definitions. Don't enforce blank lines.
784
+ let max_lines_level = if self . source_type . is_stub ( ) {
785
+ 1
786
+ } else {
787
+ if line. indent_length == 0 {
788
+ BLANK_LINES_TOP_LEVEL
789
+ } else {
790
+ BLANK_LINES_NESTED_LEVEL
791
+ }
792
+ } ;
793
+
753
794
let expected_blank_lines_before_definition = if line. indent_length == 0 {
754
795
// Mimic the isort rules for the number of blank lines before classes and functions
755
796
if state. follows . is_any_import ( ) {
756
797
// Fallback to the default if the value is too large for an u32 or if it is negative.
757
798
// A negative value means that isort should determine the blank lines automatically.
758
- // `isort` defaults to 2 if before a class or function definition and 1 otherwise.
759
- // Defaulting to 2 here is correct because the variable is only used when testing the
799
+ // `isort` defaults to 2 if before a class or function definition (except in stubs where it is one) and 1 otherwise.
800
+ // Defaulting to 2 (or 1 in stubs) here is correct because the variable is only used when testing the
760
801
// blank lines before a class or function definition.
761
- u32:: try_from ( self . lines_after_imports ) . unwrap_or ( BLANK_LINES_TOP_LEVEL )
802
+ u32:: try_from ( self . lines_after_imports ) . unwrap_or ( max_lines_level )
762
803
} else {
763
- BLANK_LINES_TOP_LEVEL
804
+ max_lines_level
764
805
}
765
806
} else {
766
- BLANK_LINES_NESTED_LEVEL
807
+ max_lines_level
767
808
} ;
768
809
769
810
if line. preceding_blank_lines < expected_blank_lines_before_definition
@@ -775,6 +816,8 @@ impl<'a> BlankLinesChecker<'a> {
775
816
&& line. indent_length == 0
776
817
// Only apply to functions or classes.
777
818
&& line. kind . is_class_function_or_decorator ( )
819
+ // Blank lines in stub files are used to group definitions. Don't enforce blank lines.
820
+ && !self . source_type . is_stub ( )
778
821
{
779
822
// E302
780
823
let mut diagnostic = Diagnostic :: new (
@@ -804,12 +847,6 @@ impl<'a> BlankLinesChecker<'a> {
804
847
diagnostics. push ( diagnostic) ;
805
848
}
806
849
807
- let max_lines_level = if line. indent_length == 0 {
808
- BLANK_LINES_TOP_LEVEL
809
- } else {
810
- BLANK_LINES_NESTED_LEVEL
811
- } ;
812
-
813
850
// If between `import` and `from .. import ..` or the other way round,
814
851
// allow up to `lines_between_types` newlines for isort compatibility.
815
852
// We let `isort` remove extra blank lines when the imports belong
@@ -893,6 +930,8 @@ impl<'a> BlankLinesChecker<'a> {
893
930
&& line. indent_length == 0
894
931
&& !line. is_comment_only
895
932
&& !line. kind . is_class_function_or_decorator ( )
933
+ // Blank lines in stub files are used for grouping, don't enforce blank lines.
934
+ && !self . source_type . is_stub ( )
896
935
{
897
936
// E305
898
937
let mut diagnostic = Diagnostic :: new (
@@ -933,6 +972,8 @@ impl<'a> BlankLinesChecker<'a> {
933
972
&& prev_indent_length. is_some_and ( |prev_indent_length| prev_indent_length >= line. indent_length )
934
973
// Allow groups of one-liners.
935
974
&& !( matches ! ( state. follows, Follows :: Def ) && line. last_token != TokenKind :: Colon )
975
+ // Blank lines in stub files are only used for grouping. Don't enforce blank lines.
976
+ && !self . source_type . is_stub ( )
936
977
{
937
978
// E306
938
979
let mut diagnostic =
0 commit comments