From c09730bd6497daf1c0373783b68b642b11140db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Noord?= <13665637+DanielNoord@users.noreply.github.com> Date: Mon, 9 May 2022 12:45:05 +0200 Subject: [PATCH] Pass ``msg_store`` and ``node`` to ``FileState`` (#6558) --- pylint/lint/parallel.py | 1 + pylint/lint/pylinter.py | 23 ++++++++++++++--------- pylint/utils/file_state.py | 31 +++++++++++++++++++++++++++++-- tests/lint/unittest_lint.py | 2 +- tests/test_deprecation.py | 13 +++++++++++++ 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/pylint/lint/parallel.py b/pylint/lint/parallel.py index 435bbb35e1..f60c05ab0a 100644 --- a/pylint/lint/parallel.py +++ b/pylint/lint/parallel.py @@ -159,6 +159,7 @@ def check_parallel( mapreduce_data, ) in pool.imap_unordered(_worker_check_single_file, files): linter.file_state.base_name = base_name + linter.file_state._is_base_filestate = False linter.set_current_module(module, file_path) for msg in messages: linter.reporter.handle_message(msg) diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py index 661c4e7a79..53345a6b17 100644 --- a/pylint/lint/pylinter.py +++ b/pylint/lint/pylinter.py @@ -279,8 +279,13 @@ def __init__( self._dynamic_plugins: set[str] = set() """Set of loaded plugin names.""" + # Attributes related to registering messages and their handling + self.msgs_store = MessageDefinitionStore() + self.msg_status = 0 + self._by_id_managed_msgs: list[ManagedMessage] = [] + # Attributes related to visiting files - self.file_state = FileState() + self.file_state = FileState("", self.msgs_store, is_base_filestate=True) self.current_name: str | None = None self.current_file: str | None = None self._ignore_file = False @@ -300,11 +305,6 @@ def __init__( """List of message symbols on which pylint should fail, set by --fail-on.""" self._error_mode = False - # Attributes related to registering messages and their handling - self.msgs_store = MessageDefinitionStore() - self.msg_status = 0 - self._by_id_managed_msgs: list[ManagedMessage] = [] - reporters.ReportsHandlerMixIn.__init__(self) checkers.BaseChecker.__init__(self, self) # provided reports @@ -694,7 +694,7 @@ def _check_file( self._ignore_file = False - self.file_state = FileState(file.modpath) + self.file_state = FileState(file.modpath, self.msgs_store, ast_node) # fix the current file (if the source file was not available or # if it's actually a c extension) self.current_file = ast_node.file @@ -969,7 +969,11 @@ def generate_reports(self) -> int | None: # Display whatever messages are left on the reporter. self.reporter.display_messages(report_nodes.Section()) - if self.file_state.base_name is not None: + # TODO: 3.0: Remove second half of if-statement + if ( + not self.file_state._is_base_filestate + and self.file_state.base_name is not None + ): # load previous results if any previous_stats = load_results(self.file_state.base_name) self.reporter.on_close(self.stats, previous_stats) @@ -994,7 +998,8 @@ def _report_evaluation(self) -> int | None: # check with at least check 1 statements (usually 0 when there is a # syntax error preventing pylint from further processing) note = None - assert self.file_state.base_name + # TODO: 3.0: Remove assertion + assert self.file_state.base_name is not None previous_stats = load_results(self.file_state.base_name) if self.stats.statement == 0: return note diff --git a/pylint/utils/file_state.py b/pylint/utils/file_state.py index 02b94b3797..255bc789c9 100644 --- a/pylint/utils/file_state.py +++ b/pylint/utils/file_state.py @@ -6,6 +6,7 @@ import collections import sys +import warnings from collections import defaultdict from collections.abc import Iterator from typing import TYPE_CHECKING, Dict @@ -33,7 +34,26 @@ class FileState: """Hold internal state specific to the currently analyzed file.""" - def __init__(self, modname: str | None = None) -> None: + def __init__( + self, + modname: str | None = None, + msg_store: MessageDefinitionStore | None = None, + node: nodes.Module | None = None, + *, + is_base_filestate: bool = False, + ) -> None: + if modname is None: + warnings.warn( + "FileState needs a string as modname argument. " + "This argument will be required in pylint 3.0", + DeprecationWarning, + ) + if msg_store is None: + warnings.warn( + "FileState needs a 'MessageDefinitionStore' as msg_store argument. " + "This argument will be required in pylint 3.0", + DeprecationWarning, + ) self.base_name = modname self._module_msgs_state: MessageStateDict = {} self._raw_module_msgs_state: MessageStateDict = {} @@ -41,7 +61,14 @@ def __init__(self, modname: str | None = None) -> None: tuple[str, int], set[int] ] = collections.defaultdict(set) self._suppression_mapping: dict[tuple[str, int], int] = {} - self._effective_max_line_number: int | None = None + self._module = node + if node: + self._effective_max_line_number = node.tolineno + else: + self._effective_max_line_number = None + self._msgs_store = msg_store + self._is_base_filestate = is_base_filestate + """If this FileState is the base state made during initialization of PyLinter.""" def collect_block_lines( self, msgs_store: MessageDefinitionStore, module_node: nodes.Module diff --git a/tests/lint/unittest_lint.py b/tests/lint/unittest_lint.py index 37c912c7bb..19f3f8b2d9 100644 --- a/tests/lint/unittest_lint.py +++ b/tests/lint/unittest_lint.py @@ -191,7 +191,7 @@ def reporter(): def initialized_linter(linter: PyLinter) -> PyLinter: linter.open() linter.set_current_module("toto", "mydir/toto") - linter.file_state = FileState("toto") + linter.file_state = FileState("toto", linter.msgs_store) return linter diff --git a/tests/test_deprecation.py b/tests/test_deprecation.py index 2fd0a56c3e..33e5a9c2fc 100644 --- a/tests/test_deprecation.py +++ b/tests/test_deprecation.py @@ -22,8 +22,10 @@ ITokenChecker, ) from pylint.lint import PyLinter +from pylint.message import MessageDefinitionStore from pylint.reporters import BaseReporter from pylint.reporters.ureports.nodes import Section +from pylint.utils import FileState def test_mapreducemixin() -> None: @@ -87,3 +89,14 @@ def test_load_and_save_results() -> None: save_results(object(), "") # type: ignore[arg-type] with pytest.warns(DeprecationWarning): load_results("") + + +def test_filestate() -> None: + """Test that FileState needs its arguments.""" + with pytest.warns(DeprecationWarning): + FileState() + with pytest.warns(DeprecationWarning): + FileState("foo") + with pytest.warns(DeprecationWarning): + FileState(msg_store=MessageDefinitionStore()) + FileState("foo", MessageDefinitionStore())