@@ -447,6 +447,7 @@ def __init__(self, linter: PyLinter) -> None:
447447 self .import_graph : defaultdict [str , set [str ]] = defaultdict (set )
448448 self ._imports_stack : list [tuple [ImportNode , str ]] = []
449449 self ._first_non_import_node = None
450+ self ._non_import_nodes : list = []
450451 self ._module_pkg : dict [Any , Any ] = (
451452 {}
452453 ) # mapping of modules to the pkg they belong in
@@ -608,6 +609,7 @@ def leave_module(self, node: nodes.Module) -> None:
608609
609610 self ._imports_stack = []
610611 self ._first_non_import_node = None
612+ self ._non_import_nodes = []
611613
612614 def compute_first_non_import_node (
613615 self ,
@@ -621,12 +623,7 @@ def compute_first_non_import_node(
621623 | nodes .Try
622624 ),
623625 ) -> None :
624- # if the node does not contain an import instruction, and if it is the
625- # first node of the module, keep a track of it (all the import positions
626- # of the module will be compared to the position of this first
627- # instruction)
628- if self ._first_non_import_node :
629- return
626+ # Track non-import nodes at module level to check import positions
630627 if not isinstance (node .parent , nodes .Module ):
631628 return
632629 if isinstance (node , nodes .Try ) and any (
@@ -644,7 +641,11 @@ def compute_first_non_import_node(
644641 ]
645642 if all (valid_targets ):
646643 return
647- self ._first_non_import_node = node
644+
645+ if not self ._first_non_import_node :
646+ self ._first_non_import_node = node
647+
648+ self ._non_import_nodes .append (node )
648649
649650 visit_try = visit_assignattr = visit_assign = visit_ifexp = visit_comprehension = (
650651 visit_expr
@@ -653,12 +654,7 @@ def compute_first_non_import_node(
653654 def visit_functiondef (
654655 self , node : nodes .FunctionDef | nodes .While | nodes .For | nodes .ClassDef
655656 ) -> None :
656- # If it is the first non import instruction of the module, record it.
657- if self ._first_non_import_node :
658- return
659-
660- # Check if the node belongs to an `If` or a `Try` block. If they
661- # contain imports, skip recording this node.
657+ # Record non-import instruction unless inside an If/Try block that contains imports
662658 if not isinstance (node .parent .scope (), nodes .Module ):
663659 return
664660
@@ -670,7 +666,10 @@ def visit_functiondef(
670666 if any (root .nodes_of_class ((nodes .Import , nodes .ImportFrom ))):
671667 return
672668
673- self ._first_non_import_node = node
669+ if not self ._first_non_import_node :
670+ self ._first_non_import_node = node
671+
672+ self ._non_import_nodes .append (node )
674673
675674 visit_classdef = visit_for = visit_while = visit_functiondef
676675
@@ -699,17 +698,37 @@ def _check_position(self, node: ImportNode) -> None:
699698
700699 Send a message if `node` comes before another instruction
701700 """
702- # if a first non-import instruction has already been encountered,
703- # it means the import comes after it and therefore is not well placed
701+ # Check if import comes after a non-import statement
704702 if self ._first_non_import_node :
705- if self .linter .is_message_enabled ("wrong-import-position" , node .fromlineno ):
706- self .add_message (
707- "wrong-import-position" , node = node , args = node .as_string ()
708- )
709- else :
703+ # Check for inline pragma on the import line
704+ if not self .linter .is_message_enabled ("wrong-import-position" , node .fromlineno ):
710705 self .linter .add_ignored_message (
711706 "wrong-import-position" , node .fromlineno , node
712707 )
708+ return
709+
710+ # Check for pragma on the preceding non-import statement
711+ most_recent_non_import = None
712+ for non_import_node in self ._non_import_nodes :
713+ if non_import_node .fromlineno < node .fromlineno :
714+ most_recent_non_import = non_import_node
715+ else :
716+ break
717+
718+ if most_recent_non_import :
719+ check_line = most_recent_non_import .fromlineno
720+ if not self .linter .is_message_enabled ("wrong-import-position" , check_line ):
721+ self .linter .add_ignored_message (
722+ "wrong-import-position" , check_line , most_recent_non_import
723+ )
724+ self .linter .add_ignored_message (
725+ "wrong-import-position" , node .fromlineno , node
726+ )
727+ return
728+
729+ self .add_message (
730+ "wrong-import-position" , node = node , args = node .as_string ()
731+ )
713732
714733 def _record_import (
715734 self ,
0 commit comments