@@ -360,6 +360,7 @@ def visit_Call(self, node):
360
360
self .check_for_b026 (node )
361
361
362
362
self .check_for_b905 (node )
363
+ self .check_for_b028 (node )
363
364
self .generic_visit (node )
364
365
365
366
def visit_Module (self , node ):
@@ -1146,6 +1147,16 @@ def myunparse(node: ast.AST) -> str: # pragma: no cover
1146
1147
# if no pre-mark or variable detected, reset state
1147
1148
current_mark = variable = None
1148
1149
1150
+ def check_for_b028 (self , node ):
1151
+ if (
1152
+ isinstance (node .func , ast .Attribute )
1153
+ and node .func .attr == "warn"
1154
+ and isinstance (node .func .value , ast .Name )
1155
+ and node .func .value .id == "warnings"
1156
+ and not any (kw .arg == "stacklevel" for kw in node .keywords )
1157
+ ):
1158
+ self .errors .append (B028 (node .lineno , node .col_offset ))
1159
+
1149
1160
1150
1161
def compose_call_path (node ):
1151
1162
if isinstance (node , ast .Attribute ):
@@ -1510,6 +1521,15 @@ def visit_Lambda(self, node):
1510
1521
" decorator. Consider adding @abstractmethod."
1511
1522
)
1512
1523
)
1524
+ B028 = Error (
1525
+ message = (
1526
+ "B028 No explicit stacklevel keyword argument found. The warn method from the"
1527
+ " warnings module uses a stacklevel of 1 by default. This will only show a"
1528
+ " stack trace for the line on which the warn method is called."
1529
+ " It is therefore recommended to use a stacklevel of 2 or"
1530
+ " greater to provide more information to the user."
1531
+ )
1532
+ )
1513
1533
1514
1534
# Warnings disabled by default.
1515
1535
B901 = Error (
0 commit comments