66
66
ModuleDescriptionDict ,
67
67
Options ,
68
68
)
69
- from pylint .utils import ASTWalker , FileState , LinterStats , utils
69
+ from pylint .utils import ASTWalker , FileState , LinterStats , merge_stats , utils
70
70
71
71
MANAGER = astroid .MANAGER
72
72
@@ -317,6 +317,7 @@ def __init__(
317
317
318
318
# Attributes related to stats
319
319
self .stats = LinterStats ()
320
+ self .all_stats : list [LinterStats ] = []
320
321
321
322
# Attributes related to (command-line) options and their parsing
322
323
self .options : Options = options + _make_linter_options (self )
@@ -665,12 +666,12 @@ def check(self, files_or_modules: Sequence[str]) -> None:
665
666
"Missing filename required for --from-stdin"
666
667
)
667
668
668
- extra_packages_paths = list (
669
- {
669
+ extra_packages_paths_set = set ()
670
+ for file_or_module in files_or_modules :
671
+ extra_packages_paths_set .add (
670
672
discover_package_path (file_or_module , self .config .source_roots )
671
- for file_or_module in files_or_modules
672
- }
673
- )
673
+ )
674
+ extra_packages_paths = list (extra_packages_paths_set )
674
675
675
676
# TODO: Move the parallel invocation into step 3 of the checking process
676
677
if not self .config .from_stdin and self .config .jobs > 1 :
@@ -693,13 +694,12 @@ def check(self, files_or_modules: Sequence[str]) -> None:
693
694
fileitems = self ._iterate_file_descrs (files_or_modules )
694
695
data = None
695
696
696
- # The contextmanager also opens all checkers and sets up the PyLinter class
697
697
with augmented_sys_path (extra_packages_paths ):
698
+ # 2) Get the AST for each FileItem
699
+ ast_per_fileitem = self ._get_asts (fileitems , data )
700
+ # 3) Lint each ast
701
+ # The contextmanager also opens all checkers and sets up the PyLinter class
698
702
with self ._astroid_module_checker () as check_astroid_module :
699
- # 2) Get the AST for each FileItem
700
- ast_per_fileitem = self ._get_asts (fileitems , data )
701
-
702
- # 3) Lint each ast
703
703
self ._lint_files (ast_per_fileitem , check_astroid_module )
704
704
705
705
def _get_asts (
@@ -710,6 +710,7 @@ def _get_asts(
710
710
711
711
for fileitem in fileitems :
712
712
self .set_current_module (fileitem .name , fileitem .filepath )
713
+ self ._set_astroid_options ()
713
714
714
715
try :
715
716
ast_per_fileitem [fileitem ] = self .get_ast (
@@ -735,13 +736,14 @@ def check_single_file_item(self, file: FileItem) -> None:
735
736
736
737
initialize() should be called before calling this method
737
738
"""
739
+ self .set_current_module (file .name , file .filepath )
738
740
with self ._astroid_module_checker () as check_astroid_module :
739
741
self ._check_file (self .get_ast , check_astroid_module , file )
740
742
741
743
def _lint_files (
742
744
self ,
743
745
ast_mapping : dict [FileItem , nodes .Module | None ],
744
- check_astroid_module : Callable [[nodes .Module ], bool | None ],
746
+ check_astroid_module : Callable [[nodes .Module ], bool | None ] | None ,
745
747
) -> None :
746
748
"""Lint all AST modules from a mapping.."""
747
749
for fileitem , module in ast_mapping .items ():
@@ -760,12 +762,17 @@ def _lint_files(
760
762
)
761
763
else :
762
764
self .add_message ("fatal" , args = msg , confidence = HIGH )
765
+ # current self.stats is needed in merge - it contains stats from last module
766
+ finished_run_stats = merge_stats ([* self .all_stats , self .stats ])
767
+ # after _lint_files linter.stats is aggregate stats from all modules, like after check_parallel
768
+ self .all_stats = []
769
+ self .stats = finished_run_stats
763
770
764
771
def _lint_file (
765
772
self ,
766
773
file : FileItem ,
767
774
module : nodes .Module ,
768
- check_astroid_module : Callable [[nodes .Module ], bool | None ],
775
+ check_astroid_module : Callable [[nodes .Module ], bool | None ] | None ,
769
776
) -> None :
770
777
"""Lint a file using the passed utility function check_astroid_module).
771
778
@@ -784,7 +791,13 @@ def _lint_file(
784
791
self .current_file = module .file
785
792
786
793
try :
787
- check_astroid_module (module )
794
+ # call _astroid_module_checker after set_current_module, when
795
+ # self.config is the right config for current module
796
+ if check_astroid_module is None :
797
+ with self ._astroid_module_checker () as local_check_astroid_module :
798
+ local_check_astroid_module (module )
799
+ else :
800
+ check_astroid_module (module )
788
801
except Exception as e :
789
802
raise astroid .AstroidError from e
790
803
@@ -898,33 +911,44 @@ def _expand_files(
898
911
def set_current_module (self , modname : str , filepath : str | None = None ) -> None :
899
912
"""Set the name of the currently analyzed module and
900
913
init statistics for it.
914
+
915
+ Save current stats before init to make sure no counters for
916
+ error, statement, etc are missed.
901
917
"""
902
918
if not modname and filepath is None :
903
919
return
904
920
self .reporter .on_set_current_module (modname or "" , filepath )
905
921
self .current_name = modname
906
922
self .current_file = filepath or modname
923
+ self .all_stats .append (self .stats )
924
+ self .stats = LinterStats ()
907
925
self .stats .init_single_module (modname or "" )
908
926
909
927
# If there is an actual filepath we might need to update the config attribute
910
928
if filepath :
911
- namespace = self ._get_namespace_for_file (
929
+ config_path , namespace = self ._get_namespace_for_file (
912
930
Path (filepath ), self ._directory_namespaces
913
931
)
914
932
if namespace :
915
- self .config = namespace or self ._base_config
933
+ self .config = namespace
934
+ if self .config .verbose :
935
+ print (
936
+ f"Using config file from { config_path } for { filepath } " ,
937
+ file = sys .stderr ,
938
+ )
916
939
917
940
def _get_namespace_for_file (
918
941
self , filepath : Path , namespaces : DirectoryNamespaceDict
919
- ) -> argparse .Namespace | None :
942
+ ) -> tuple [Path | None , argparse .Namespace | None ]:
943
+ filepath = filepath .resolve ()
920
944
for directory in namespaces :
921
945
if _is_relative_to (filepath , directory ):
922
- namespace = self ._get_namespace_for_file (
946
+ _ , namespace = self ._get_namespace_for_file (
923
947
filepath , namespaces [directory ][1 ]
924
948
)
925
949
if namespace is None :
926
- return namespaces [directory ][0 ]
927
- return None
950
+ return directory , namespaces [directory ][0 ]
951
+ return None , None
928
952
929
953
@contextlib .contextmanager
930
954
def _astroid_module_checker (
@@ -953,7 +977,7 @@ def _astroid_module_checker(
953
977
rawcheckers = rawcheckers ,
954
978
)
955
979
956
- # notify global end
980
+ # notify end of module if jobs>1, global end otherwise
957
981
self .stats .statement = walker .nbstatements
958
982
for checker in reversed (_checkers ):
959
983
checker .close ()
@@ -1068,22 +1092,26 @@ def _check_astroid_module(
1068
1092
walker .walk (node )
1069
1093
return True
1070
1094
1071
- def open (self ) -> None :
1072
- """Initialize counters ."""
1095
+ def _set_astroid_options (self ) -> None :
1096
+ """Pass some config values to astroid.MANAGER object ."""
1073
1097
MANAGER .always_load_extensions = self .config .unsafe_load_any_extension
1074
1098
MANAGER .max_inferable_values = self .config .limit_inference_results
1075
1099
MANAGER .extension_package_whitelist .update (self .config .extension_pkg_allow_list )
1076
1100
if self .config .extension_pkg_whitelist :
1077
1101
MANAGER .extension_package_whitelist .update (
1078
1102
self .config .extension_pkg_whitelist
1079
1103
)
1080
- self .stats .reset_message_count ()
1104
+
1105
+ def open (self ) -> None :
1106
+ """Initialize self as main checker for one or more modules."""
1107
+ self ._set_astroid_options ()
1081
1108
1082
1109
def generate_reports (self , verbose : bool = False ) -> int | None :
1083
1110
"""Close the whole package /module, it's time to make reports !
1084
1111
1085
1112
if persistent run, pickle results for later comparison
1086
1113
"""
1114
+ self .config = self ._base_config
1087
1115
# Display whatever messages are left on the reporter.
1088
1116
self .reporter .display_messages (report_nodes .Section ())
1089
1117
if not self .file_state ._is_base_filestate :
0 commit comments