@@ -354,6 +354,8 @@ def visit_Call(self, node):
354354 ):
355355 self .errors .append (B010 (node .lineno , node .col_offset ))
356356
357+ self .check_for_b026 (node )
358+
357359 self .generic_visit (node )
358360
359361 def visit_Assign (self , node ):
@@ -641,6 +643,22 @@ def is_abstract_decorator(expr):
641643
642644 self .errors .append (B024 (node .lineno , node .col_offset , vars = (node .name ,)))
643645
646+ def check_for_b026 (self , call : ast .Call ):
647+ if not call .keywords :
648+ return
649+
650+ starreds = [arg for arg in call .args if isinstance (arg , ast .Starred )]
651+ if not starreds :
652+ return
653+
654+ first_keyword = call .keywords [0 ].value
655+ for starred in starreds :
656+ if (starred .lineno , starred .col_offset ) > (
657+ first_keyword .lineno ,
658+ first_keyword .col_offset ,
659+ ):
660+ self .errors .append (B026 (starred .lineno , starred .col_offset ))
661+
644662 def _get_assigned_names (self , loop_node ):
645663 loop_targets = (ast .For , ast .AsyncFor , ast .comprehension )
646664 for node in children_in_scope (loop_node ):
@@ -1203,6 +1221,14 @@ def visit_Lambda(self, node):
12031221 " will be considered and all other except catches can be safely removed."
12041222 )
12051223)
1224+ B026 = Error (
1225+ message = (
1226+ "B026 Star-arg unpacking after a keyword argument is strongly discouraged, "
1227+ "because it only works when the keyword parameter is declared after all "
1228+ "parameters supplied by the unpacked sequence, and this change of ordering can "
1229+ "surprise and mislead readers."
1230+ )
1231+ )
12061232
12071233# Warnings disabled by default.
12081234B901 = Error (
0 commit comments