6969 ModuleDescriptionDict ,
7070 Options ,
7171)
72- from pylint .utils import ASTWalker , FileState , LinterStats , utils
72+ from pylint .utils import ASTWalker , FileState , LinterStats , merge_stats , utils
7373
7474MANAGER = astroid .MANAGER
7575
@@ -320,6 +320,7 @@ def __init__(
320320
321321 # Attributes related to stats
322322 self .stats = LinterStats ()
323+ self .all_stats : list [LinterStats ] = []
323324
324325 # Attributes related to (command-line) options and their parsing
325326 self .options : Options = options + _make_linter_options (self )
@@ -951,12 +952,17 @@ def _expand_files(
951952 def set_current_module (self , modname : str , filepath : str | None = None ) -> None :
952953 """Set the name of the currently analyzed module and
953954 init statistics for it.
955+
956+ Save current stats before init to make sure no counters for
957+ error, statement, etc are missed.
954958 """
955959 if not modname and filepath is None :
956960 return
957961 self .reporter .on_set_current_module (modname or "" , filepath )
958962 self .current_name = modname
959963 self .current_file = filepath or modname
964+ self .all_stats .append (self .stats )
965+ self .stats = LinterStats ()
960966 self .stats .init_single_module (modname or "" )
961967
962968 # If there is an actual filepath we might need to update the config attribute
@@ -1013,7 +1019,7 @@ def _astroid_module_checker(
10131019 rawcheckers = rawcheckers ,
10141020 )
10151021
1016- # notify global end
1022+ # notify end of module if jobs>1 or use-local-configs=y, global end otherwise
10171023 self .stats .statement = walker .nbstatements
10181024 for checker in reversed (_checkers ):
10191025 checker .close ()
@@ -1147,14 +1153,18 @@ def generate_reports(self, verbose: bool = False) -> int | None:
11471153
11481154 if persistent run, pickle results for later comparison
11491155 """
1156+ self .config = self ._base_config
11501157 # Display whatever messages are left on the reporter.
11511158 self .reporter .display_messages (report_nodes .Section ())
1159+ # current self.stats is needed in merge - it contains stats from last module
1160+ # separate variable to avoid modifying any stats during reporting
1161+ self .finished_run_stats = merge_stats ([self .stats , * self .all_stats ])
11521162 if not self .file_state ._is_base_filestate :
11531163 # load previous results if any
11541164 previous_stats = load_results (self .file_state .base_name )
1155- self .reporter .on_close (self .stats , previous_stats )
1165+ self .reporter .on_close (self .finished_run_stats , previous_stats )
11561166 if self .config .reports :
1157- sect = self .make_reports (self .stats , previous_stats )
1167+ sect = self .make_reports (self .finished_run_stats , previous_stats )
11581168 else :
11591169 sect = report_nodes .Section ()
11601170
@@ -1163,9 +1173,9 @@ def generate_reports(self, verbose: bool = False) -> int | None:
11631173 score_value = self ._report_evaluation (verbose )
11641174 # save results if persistent run
11651175 if self .config .persistent :
1166- save_results (self .stats , self .file_state .base_name )
1176+ save_results (self .finished_run_stats , self .file_state .base_name )
11671177 else :
1168- self .reporter .on_close (self .stats , LinterStats ())
1178+ self .reporter .on_close (self .finished_run_stats , LinterStats ())
11691179 score_value = None
11701180 return score_value
11711181
@@ -1175,35 +1185,35 @@ def _report_evaluation(self, verbose: bool = False) -> int | None:
11751185 # syntax error preventing pylint from further processing)
11761186 note = None
11771187 previous_stats = load_results (self .file_state .base_name )
1178- if self .stats .statement == 0 :
1188+ if self .finished_run_stats .statement == 0 :
11791189 return note
11801190
11811191 # get a global note for the code
11821192 evaluation = self .config .evaluation
11831193 try :
11841194 stats_dict = {
1185- "fatal" : self .stats .fatal ,
1186- "error" : self .stats .error ,
1187- "warning" : self .stats .warning ,
1188- "refactor" : self .stats .refactor ,
1189- "convention" : self .stats .convention ,
1190- "statement" : self .stats .statement ,
1191- "info" : self .stats .info ,
1195+ "fatal" : self .finished_run_stats .fatal ,
1196+ "error" : self .finished_run_stats .error ,
1197+ "warning" : self .finished_run_stats .warning ,
1198+ "refactor" : self .finished_run_stats .refactor ,
1199+ "convention" : self .finished_run_stats .convention ,
1200+ "statement" : self .finished_run_stats .statement ,
1201+ "info" : self .finished_run_stats .info ,
11921202 }
11931203 note = eval (evaluation , {}, stats_dict ) # pylint: disable=eval-used
11941204 except Exception as ex : # pylint: disable=broad-except
11951205 msg = f"An exception occurred while rating: { ex } "
11961206 else :
1197- self .stats .global_note = note
1207+ self .finished_run_stats .global_note = note
11981208 msg = f"Your code has been rated at { note :.2f} /10"
11991209 if previous_stats :
12001210 pnote = previous_stats .global_note
12011211 if pnote is not None :
12021212 msg += f" (previous run: { pnote :.2f} /10, { note - pnote :+.2f} )"
12031213
12041214 if verbose :
1205- checked_files_count = self .stats .node_count ["module" ]
1206- unchecked_files_count = self .stats .undocumented ["module" ]
1215+ checked_files_count = self .finished_run_stats .node_count ["module" ]
1216+ unchecked_files_count = self .finished_run_stats .undocumented ["module" ]
12071217 msg += f"\n Checked { checked_files_count } files, skipped { unchecked_files_count } files"
12081218
12091219 if self .config .score :
0 commit comments