Add typing to ``filepath`` (#4980)

* Change tests for ``filepath`` changes
* Add pylint/typing.py and FileItem NamedTuple
* Use NamedTuple more efficiently
* Fix errors and tests after adding warning
* Add deprecation for future API change in Checker

Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
diff --git a/pylint/config/option_manager_mixin.py b/pylint/config/option_manager_mixin.py
index c48d207..f18fcfe 100644
--- a/pylint/config/option_manager_mixin.py
+++ b/pylint/config/option_manager_mixin.py
@@ -332,7 +332,7 @@
             provider = self._all_options[opt]
             provider.set_option(opt, opt_value)
 
-    def load_command_line_configuration(self, args=None):
+    def load_command_line_configuration(self, args=None) -> List[str]:
         """Override configuration according to command line parameters
 
         return additional arguments
diff --git a/pylint/lint/expand_modules.py b/pylint/lint/expand_modules.py
index 11927eb..1d44323 100644
--- a/pylint/lint/expand_modules.py
+++ b/pylint/lint/expand_modules.py
@@ -4,6 +4,8 @@
 
 from astroid import modutils
 
+from pylint.typing import ErrorDescriptionDict, ModuleDescriptionDict
+
 
 def _modpath_from_file(filename, is_namespace, path=None):
     def _is_package_cb(path, parts):
@@ -42,12 +44,12 @@
     ignore_list: List[str],
     ignore_list_re: List[Pattern],
     ignore_list_paths_re: List[Pattern],
-) -> Tuple[List[dict], List[dict]]:
+) -> Tuple[List[ModuleDescriptionDict], List[ErrorDescriptionDict]]:
     """take a list of files/modules/packages and return the list of tuple
     (file, module name) which have to be actually checked
     """
-    result = []
-    errors = []
+    result: List[ModuleDescriptionDict] = []
+    errors: List[ErrorDescriptionDict] = []
     path = sys.path.copy()
 
     for something in files_or_modules:
diff --git a/pylint/lint/parallel.py b/pylint/lint/parallel.py
index 2f3d0dd..1896fc9 100644
--- a/pylint/lint/parallel.py
+++ b/pylint/lint/parallel.py
@@ -3,12 +3,12 @@
 
 import collections
 import functools
-from typing import TYPE_CHECKING, Dict, List, Union
+from typing import TYPE_CHECKING, Any, DefaultDict, Dict, Iterable, List, Tuple, Union
 
 from pylint import reporters
 from pylint.lint.utils import _patch_sys_path
 from pylint.message import Message
-from pylint.typing import CheckerStats
+from pylint.typing import CheckerStats, FileItem
 
 if TYPE_CHECKING:
     from typing import Counter  # typing.Counter added in Python 3.6.1
@@ -67,11 +67,13 @@
     _patch_sys_path(arguments or ())
 
 
-def _worker_check_single_file(file_item):
-    name, filepath, modname = file_item
-
+def _worker_check_single_file(
+    file_item: FileItem,
+) -> Tuple[int, Any, str, Any, List[Tuple[Any, ...]], Any, Any, DefaultDict[Any, List]]:
+    if not _worker_linter:
+        raise Exception("Worker linter not yet initialised")
     _worker_linter.open()
-    _worker_linter.check_single_file(name, filepath, modname)
+    _worker_linter.check_single_file_item(file_item)
     mapreduce_data = collections.defaultdict(list)
     for checker in _worker_linter.get_checkers():
         try:
@@ -84,7 +86,7 @@
     return (
         id(multiprocessing.current_process()),
         _worker_linter.current_name,
-        filepath,
+        file_item.filepath,
         _worker_linter.file_state.base_name,
         msgs,
         _worker_linter.stats,
@@ -114,7 +116,7 @@
             checker.reduce_map_data(linter, collated_map_reduce_data[checker.name])
 
 
-def check_parallel(linter, jobs, files, arguments=None):
+def check_parallel(linter, jobs, files: Iterable[FileItem], arguments=None):
     """Use the given linter to lint the files with given amount of workers (jobs)
     This splits the work filestream-by-filestream. If you need to do work across
     multiple files, as in the similarity-checker, then inherit from MapReduceMixin and
@@ -156,7 +158,7 @@
             linter.set_current_module(module, file_path)
             for msg in messages:
                 msg = Message(*msg)
-                linter.reporter.handle_message(msg)
+                linter.reporter.handle_message(msg)  # type: ignore  # linter.set_reporter() call above makes linter have a reporter attr
             all_stats.append(stats)
             all_mapreduce_data[worker_idx].append(mapreduce_data)
             linter.msg_status |= msg_status
diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py
index d731e71..e8efc2f 100644
--- a/pylint/lint/pylinter.py
+++ b/pylint/lint/pylinter.py
@@ -11,6 +11,7 @@
 import traceback
 import warnings
 from io import TextIOWrapper
+from typing import Iterable, Iterator, List, Optional, Sequence, Union
 
 import astroid
 from astroid import AstroidError, nodes
@@ -31,7 +32,7 @@
 )
 from pylint.message import MessageDefinitionStore, MessagesHandlerMixIn
 from pylint.reporters.ureports import nodes as report_nodes
-from pylint.typing import CheckerStats
+from pylint.typing import CheckerStats, FileItem, ModuleDescriptionDict
 from pylint.utils import ASTWalker, FileState, utils
 from pylint.utils.pragma_parser import (
     OPTION_PO,
@@ -938,16 +939,20 @@
             if not msg.may_be_emitted():
                 self._msgs_state[msg.msgid] = False
 
-    def check(self, files_or_modules):
+    def check(self, files_or_modules: Union[Sequence[str], str]) -> None:
         """main checking entry: check a list of files or modules from their name.
 
         files_or_modules is either a string or list of strings presenting modules to check.
         """
         self.initialize()
-
         if not isinstance(files_or_modules, (list, tuple)):
-            files_or_modules = (files_or_modules,)
-
+            # pylint: disable-next=fixme
+            # TODO: Update typing and docstring for 'files_or_modules' when removing the deprecation
+            warnings.warn(
+                "In pylint 3.0, the checkers check function will only accept sequence of string",
+                DeprecationWarning,
+            )
+            files_or_modules = (files_or_modules,)  # type: ignore
         if self.config.from_stdin:
             if len(files_or_modules) != 1:
                 raise exceptions.InvalidArgsError(
@@ -973,46 +978,47 @@
                 files_or_modules,
             )
 
-    def check_single_file(self, name, filepath, modname):
-        """Check single file
+    def check_single_file(self, name: str, filepath: str, modname: str) -> None:
+        warnings.warn(
+            "In pylint 3.0, the checkers check_single_file function will be removed. "
+            "Use check_single_file_item instead.",
+            DeprecationWarning,
+        )
+        self.check_single_file_item(FileItem(name, filepath, modname))
+
+    def check_single_file_item(self, file: FileItem) -> None:
+        """Check single file item
 
         The arguments are the same that are documented in _check_files
 
         The initialize() method should be called before calling this method
         """
         with self._astroid_module_checker() as check_astroid_module:
-            self._check_file(
-                self.get_ast, check_astroid_module, name, filepath, modname
-            )
+            self._check_file(self.get_ast, check_astroid_module, file)
 
-    def _check_files(self, get_ast, file_descrs):
-        """Check all files from file_descrs
-
-        The file_descrs should be iterable of tuple (name, filepath, modname)
-        where
-        - name: full name of the module
-        - filepath: path of the file
-        - modname: module name
-        """
+    def _check_files(
+        self,
+        get_ast,
+        file_descrs: Iterable[FileItem],
+    ) -> None:
+        """Check all files from file_descrs"""
         with self._astroid_module_checker() as check_astroid_module:
-            for name, filepath, modname in file_descrs:
+            for file in file_descrs:
                 try:
-                    self._check_file(
-                        get_ast, check_astroid_module, name, filepath, modname
-                    )
+                    self._check_file(get_ast, check_astroid_module, file)
                 except Exception as ex:  # pylint: disable=broad-except
                     template_path = prepare_crash_report(
-                        ex, filepath, self.crash_file_path
+                        ex, file.filepath, self.crash_file_path
                     )
-                    msg = get_fatal_error_message(filepath, template_path)
+                    msg = get_fatal_error_message(file.filepath, template_path)
                     if isinstance(ex, AstroidError):
                         symbol = "astroid-error"
-                        msg = (filepath, msg)
+                        self.add_message(symbol, args=(file.filepath, msg))
                     else:
                         symbol = "fatal"
-                    self.add_message(symbol, args=msg)
+                        self.add_message(symbol, args=msg)
 
-    def _check_file(self, get_ast, check_astroid_module, name, filepath, modname):
+    def _check_file(self, get_ast, check_astroid_module, file: FileItem):
         """Check a file using the passed utility functions (get_ast and check_astroid_module)
 
         :param callable get_ast: callable returning AST from defined file taking the following arguments
@@ -1020,19 +1026,17 @@
         - name: Python module name
         :param callable check_astroid_module: callable checking an AST taking the following arguments
         - ast: AST of the module
-        :param str name: full name of the module
-        :param str filepath: path to checked file
-        :param str modname: name of the checked Python module
+        :param FileItem file: data about the file
         """
-        self.set_current_module(name, filepath)
+        self.set_current_module(file.name, file.filepath)
         # get the module representation
-        ast_node = get_ast(filepath, name)
+        ast_node = get_ast(file.filepath, file.name)
         if ast_node is None:
             return
 
         self._ignore_file = False
 
-        self.file_state = FileState(modname)
+        self.file_state = FileState(file.modpath)
         # 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  # pylint: disable=maybe-no-member
@@ -1045,7 +1049,7 @@
             self.add_message(msgid, line, None, args)
 
     @staticmethod
-    def _get_file_descr_from_stdin(filepath):
+    def _get_file_descr_from_stdin(filepath: str) -> FileItem:
         """Return file description (tuple of module name, file path, base name) from given file path
 
         This method is used for creating suitable file description for _check_files when the
@@ -1059,9 +1063,9 @@
         except ImportError:
             modname = os.path.splitext(os.path.basename(filepath))[0]
 
-        return (modname, filepath, filepath)
+        return FileItem(modname, filepath, filepath)
 
-    def _iterate_file_descrs(self, files_or_modules):
+    def _iterate_file_descrs(self, files_or_modules) -> Iterator[FileItem]:
         """Return generator yielding file descriptions (tuples of module name, file path, base name)
 
         The returned generator yield one item for each Python module that should be linted.
@@ -1069,9 +1073,9 @@
         for descr in self._expand_files(files_or_modules):
             name, filepath, is_arg = descr["name"], descr["path"], descr["isarg"]
             if self.should_analyze_file(name, filepath, is_argument=is_arg):
-                yield (name, filepath, descr["basename"])
+                yield FileItem(name, filepath, descr["basename"])
 
-    def _expand_files(self, modules):
+    def _expand_files(self, modules) -> List[ModuleDescriptionDict]:
         """get modules and errors from a list of modules and handle errors"""
         result, errors = expand_modules(
             modules,
@@ -1088,7 +1092,7 @@
             self.add_message(key, args=message)
         return result
 
-    def set_current_module(self, modname, filepath=None):
+    def set_current_module(self, modname, filepath: Optional[str] = None):
         """set the name of the currently analyzed module and
         init statistics for it
         """
@@ -1097,10 +1101,10 @@
         self.reporter.on_set_current_module(modname, filepath)
         self.current_name = modname
         self.current_file = filepath or modname
-        self.stats["by_module"][modname] = {}
-        self.stats["by_module"][modname]["statement"] = 0
+        self.stats["by_module"][modname] = {}  # type: ignore # Refactor of PyLinter.stats necessary
+        self.stats["by_module"][modname]["statement"] = 0  # type: ignore
         for msg_cat in MSG_TYPES.values():
-            self.stats["by_module"][modname][msg_cat] = 0
+            self.stats["by_module"][modname][msg_cat] = 0  # type: ignore
 
     @contextlib.contextmanager
     def _astroid_module_checker(self):
diff --git a/pylint/lint/utils.py b/pylint/lint/utils.py
index 280b144..ed0cefb 100644
--- a/pylint/lint/utils.py
+++ b/pylint/lint/utils.py
@@ -5,8 +5,7 @@
 import sys
 import traceback
 from datetime import datetime
-from pathlib import Path, PosixPath
-from typing import Union
+from pathlib import Path
 
 from pylint.config import PYLINT_HOME
 from pylint.lint.expand_modules import get_python_path
@@ -16,9 +15,7 @@
     """Raised if an error occurs during argument preprocessing."""
 
 
-def prepare_crash_report(
-    ex: Exception, filepath: PosixPath, crash_file_path: Union[Path, str]
-) -> Path:
+def prepare_crash_report(ex: Exception, filepath: str, crash_file_path: str) -> Path:
     issue_template_path = (
         Path(PYLINT_HOME) / datetime.now().strftime(str(crash_file_path))
     ).resolve()
@@ -63,7 +60,7 @@
     return issue_template_path
 
 
-def get_fatal_error_message(filepath: str, issue_template_path: str) -> str:
+def get_fatal_error_message(filepath: str, issue_template_path: Path) -> str:
     return (
         f"Fatal error while checking '{filepath}'. "
         f"Please open an issue in our bug tracker so we address this. "
diff --git a/pylint/reporters/base_reporter.py b/pylint/reporters/base_reporter.py
index 4cf5d58..e74ffdd 100644
--- a/pylint/reporters/base_reporter.py
+++ b/pylint/reporters/base_reporter.py
@@ -3,7 +3,7 @@
 
 import os
 import sys
-from typing import List
+from typing import List, Optional
 
 from pylint.message import Message
 from pylint.typing import CheckerStats
@@ -63,7 +63,7 @@
 
     # Event callbacks
 
-    def on_set_current_module(self, module, filepath):
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         """Hook called when a module starts to be analysed."""
 
     def on_close(
diff --git a/pylint/reporters/multi_reporter.py b/pylint/reporters/multi_reporter.py
index 2ac361b..445e9b3 100644
--- a/pylint/reporters/multi_reporter.py
+++ b/pylint/reporters/multi_reporter.py
@@ -3,7 +3,7 @@
 
 
 import os
-from typing import IO, Any, AnyStr, Callable, List, Optional, Union
+from typing import IO, Any, AnyStr, Callable, List, Optional
 
 from pylint.interfaces import IReporter
 from pylint.message import Message
@@ -12,7 +12,6 @@
 from pylint.typing import CheckerStats
 
 AnyFile = IO[AnyStr]
-AnyPath = Union[str, bytes, os.PathLike]
 PyLinter = Any
 
 
@@ -89,7 +88,7 @@
         for rep in self._sub_reporters:
             rep.display_messages(layout)
 
-    def on_set_current_module(self, module: str, filepath: Optional[AnyPath]) -> None:
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         """hook called when a module starts to be analysed"""
         for rep in self._sub_reporters:
             rep.on_set_current_module(module, filepath)
diff --git a/pylint/reporters/text.py b/pylint/reporters/text.py
index 6d9a05f..32c75fd 100644
--- a/pylint/reporters/text.py
+++ b/pylint/reporters/text.py
@@ -25,6 +25,7 @@
 import os
 import sys
 import warnings
+from typing import Optional
 
 from pylint import utils
 from pylint.interfaces import IReporter
@@ -136,7 +137,7 @@
         self._modules = set()
         self._template = self.line_format
 
-    def on_set_current_module(self, module, filepath):
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         self._template = str(self.linter.config.msg_template or self._template)
 
     def write_message(self, msg):
diff --git a/pylint/testutils/reporter_for_tests.py b/pylint/testutils/reporter_for_tests.py
index b9e01b5..9527544 100644
--- a/pylint/testutils/reporter_for_tests.py
+++ b/pylint/testutils/reporter_for_tests.py
@@ -3,7 +3,7 @@
 
 from io import StringIO
 from os import getcwd, linesep, sep
-from typing import Dict, List
+from typing import Dict, List, Optional
 
 from pylint import interfaces
 from pylint.message import Message
@@ -51,7 +51,7 @@
         return result
 
     # pylint: disable=unused-argument
-    def on_set_current_module(self, module, filepath):
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         pass
 
     # pylint: enable=unused-argument
@@ -63,14 +63,14 @@
 
 
 class MinimalTestReporter(BaseReporter):
-    def on_set_current_module(self, module, filepath):
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         self.messages = []
 
     _display = None
 
 
 class FunctionalTestReporter(BaseReporter):
-    def on_set_current_module(self, module, filepath):
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         self.messages = []
 
     def display_reports(self, layout):
diff --git a/pylint/typing.py b/pylint/typing.py
index 9ce1c58..4c12710 100644
--- a/pylint/typing.py
+++ b/pylint/typing.py
@@ -2,11 +2,49 @@
 # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
 
 """A collection of typing utilities."""
-from typing import TYPE_CHECKING, Dict, List, Union
+import sys
+from typing import TYPE_CHECKING, Dict, List, NamedTuple, Union
 
 if TYPE_CHECKING:
     from typing import Counter  # typing.Counter added in Python 3.6.1
 
+if sys.version_info >= (3, 8):
+    from typing import Literal, TypedDict
+else:
+    from typing_extensions import Literal, TypedDict
+
+
+class FileItem(NamedTuple):
+    """Represents data about a file handled by pylint
+
+    Each file item has:
+    - name: full name of the module
+    - filepath: path of the file
+    - modname: module name
+    """
+
+    name: str
+    filepath: str
+    modpath: str
+
+
+class ModuleDescriptionDict(TypedDict):
+    """Represents data about a checked module"""
+
+    path: str
+    name: str
+    isarg: bool
+    basepath: str
+    basename: str
+
+
+class ErrorDescriptionDict(TypedDict):
+    """Represents data about errors collected during checking of a module"""
+
+    key: Literal["fatal"]
+    mod: str
+    ex: Union[ImportError, SyntaxError]
+
 
 # The base type of the "stats" attribute of a checker
 CheckerStats = Dict[
diff --git a/tests/benchmark/test_baseline_benchmarks.py b/tests/benchmark/test_baseline_benchmarks.py
index 27dada3..9b64cd0 100644
--- a/tests/benchmark/test_baseline_benchmarks.py
+++ b/tests/benchmark/test_baseline_benchmarks.py
@@ -22,6 +22,7 @@
 from pylint.checkers.base_checker import BaseChecker
 from pylint.lint import PyLinter, Run, check_parallel
 from pylint.testutils import GenericTestReporter as Reporter
+from pylint.typing import FileItem
 from pylint.utils import register_plugins
 
 
@@ -111,7 +112,7 @@
     impact everything else"""
 
     empty_filepath = _empty_filepath()
-    empty_file_info = (
+    empty_file_info = FileItem(
         "name-emptyfile-file",
         _empty_filepath(),
         "modname-emptyfile-mod",
diff --git a/tests/checkers/unittest_variables.py b/tests/checkers/unittest_variables.py
index 7ab79bf..62a9ca3 100644
--- a/tests/checkers/unittest_variables.py
+++ b/tests/checkers/unittest_variables.py
@@ -368,7 +368,7 @@
 
         sys.path.insert(0, REGR_DATA_DIR)
         try:
-            linter.check(os.path.join(REGR_DATA_DIR, "package_all"))
+            linter.check([os.path.join(REGR_DATA_DIR, "package_all")])
             got = linter.reporter.finalize().strip()
             assert got == "E:  3: Undefined variable name 'missing' in __all__"
         finally:
diff --git a/tests/extensions/test_broad_try_clause.py b/tests/extensions/test_broad_try_clause.py
index 21c79fe..a41a7ab 100644
--- a/tests/extensions/test_broad_try_clause.py
+++ b/tests/extensions/test_broad_try_clause.py
@@ -13,6 +13,7 @@
 """Tests for the pylint checker in :mod:`pylint.extensions.broad_try_clause`"""
 import unittest
 from os import path as osp
+from typing import Optional
 
 from pylint import checkers
 from pylint.extensions.broad_try_clause import BroadTryClauseChecker
@@ -21,7 +22,7 @@
 
 
 class BroadTryClauseTestReporter(BaseReporter):
-    def on_set_current_module(self, module: str, filepath: str) -> None:
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         self.messages = []
 
     def _display(self, layout):
diff --git a/tests/extensions/test_comparetozero.py b/tests/extensions/test_comparetozero.py
index 167a615..c90c211 100644
--- a/tests/extensions/test_comparetozero.py
+++ b/tests/extensions/test_comparetozero.py
@@ -14,6 +14,7 @@
 
 import os
 import unittest
+from typing import Optional
 
 from pylint import checkers
 from pylint.extensions.comparetozero import CompareToZeroChecker
@@ -22,7 +23,7 @@
 
 
 class CompareToZeroTestReporter(BaseReporter):
-    def on_set_current_module(self, module: str, filepath: str) -> None:
+    def on_set_current_module(self, module: str, filepath: Optional[str]) -> None:
         self.messages = []
 
     def _display(self, layout):
diff --git a/tests/lint/test_utils.py b/tests/lint/test_utils.py
index 80e7287..f7294f3 100644
--- a/tests/lint/test_utils.py
+++ b/tests/lint/test_utils.py
@@ -1,4 +1,4 @@
-from pathlib import PosixPath
+from pathlib import Path, PosixPath
 
 from pylint.lint.utils import get_fatal_error_message, prepare_crash_report
 
@@ -13,7 +13,7 @@
         raise Exception(exception_content)
     except Exception as ex:  # pylint: disable=broad-except
         template_path = prepare_crash_report(
-            ex, python_file, tmp_path / "pylint-crash-%Y.txt"
+            ex, str(python_file), str(tmp_path / "pylint-crash-%Y.txt")
         )
     assert str(tmp_path) in str(template_path)
     with open(template_path, encoding="utf8") as f:
@@ -27,7 +27,7 @@
 def test_get_fatal_error_message() -> None:
     python_path = "mypath.py"
     crash_path = "crash.txt"
-    msg = get_fatal_error_message(python_path, crash_path)
+    msg = get_fatal_error_message(python_path, Path(crash_path))
     assert python_path in msg
     assert crash_path in msg
     assert "open an issue" in msg
diff --git a/tests/lint/unittest_lint.py b/tests/lint/unittest_lint.py
index c31cbdb..d15686b 100644
--- a/tests/lint/unittest_lint.py
+++ b/tests/lint/unittest_lint.py
@@ -269,7 +269,7 @@
     linter.open()
     out = StringIO()
     linter.set_reporter(text.TextReporter(out))
-    linter.check("abc")
+    linter.check(["abc"])
 
 
 def test_enable_message(init_linter: PyLinter) -> None:
@@ -573,7 +573,7 @@
 
 def test_analyze_explicit_script(linter: PyLinter) -> None:
     linter.set_reporter(testutils.GenericTestReporter())
-    linter.check(os.path.join(DATA_DIR, "ascript"))
+    linter.check([os.path.join(DATA_DIR, "ascript")])
     assert ["C:  2: Line too long (175/100)"] == linter.reporter.messages
 
 
@@ -826,16 +826,16 @@
 def test_by_module_statement_value(init_linter: PyLinter) -> None:
     """Test "statement" for each module analized of computed correctly."""
     linter = init_linter
-    linter.check(os.path.join(os.path.dirname(__file__), "data"))
+    linter.check([os.path.join(os.path.dirname(__file__), "data")])
 
     by_module_stats: Dict[str, Dict[str, int]] = linter.stats["by_module"]  # type: ignore
     for module, module_stats in by_module_stats.items():
 
         linter2 = init_linter
         if module == "data":
-            linter2.check(os.path.join(os.path.dirname(__file__), "data/__init__.py"))
+            linter2.check([os.path.join(os.path.dirname(__file__), "data/__init__.py")])
         else:
-            linter2.check(os.path.join(os.path.dirname(__file__), module))
+            linter2.check([os.path.join(os.path.dirname(__file__), module)])
 
         # Check that the by_module "statement" is equal to the global "statement"
         # computed for that module
diff --git a/tests/test_check_parallel.py b/tests/test_check_parallel.py
index 66236ac..67cd23a 100644
--- a/tests/test_check_parallel.py
+++ b/tests/test_check_parallel.py
@@ -11,7 +11,7 @@
 
 import collections
 import os
-from typing import List, Tuple
+from typing import List
 
 import pytest
 from astroid import nodes
@@ -24,15 +24,15 @@
 from pylint.lint.parallel import _worker_initialize as worker_initialize
 from pylint.lint.parallel import check_parallel
 from pylint.testutils import GenericTestReporter as Reporter
-from pylint.typing import CheckerStats
+from pylint.typing import CheckerStats, FileItem
 
 
-def _gen_file_data(idx: int = 0) -> Tuple[str, str, str]:
+def _gen_file_data(idx: int = 0) -> FileItem:
     """Generates a file to use as a stream"""
     filepath = os.path.abspath(
         os.path.join(os.path.dirname(__file__), "input", "similar1")
     )
-    file_data = (
+    file_data = FileItem(
         f"--test-file_data-name-{idx}--",
         filepath,
         f"--test-file_data-modname-{idx}--",
@@ -40,7 +40,7 @@
     return file_data
 
 
-def _gen_file_datas(count: int = 1) -> List[Tuple[str, str, str]]:
+def _gen_file_datas(count: int = 1) -> List[FileItem]:
     return [_gen_file_data(idx) for idx in range(count)]
 
 
@@ -178,7 +178,7 @@
     def test_worker_check_single_file_uninitialised(self) -> None:
         pylint.lint.parallel._worker_linter = None
         with pytest.raises(  # Objects that do not match the linter interface will fail
-            AttributeError, match="'NoneType' object has no attribute 'open'"
+            Exception, match="Worker linter not yet initialised"
         ):
             worker_check_single_file(_gen_file_data())
 
@@ -290,7 +290,9 @@
 
         # Invoke the lint process in a multiprocess way, although we only specify one
         # job.
-        check_parallel(linter, jobs=1, files=single_file_container, arguments=None)
+        check_parallel(
+            linter, jobs=1, files=iter(single_file_container), arguments=None
+        )
         assert len(linter.get_checkers()) == 2, (
             "We should only have the 'master' and 'sequential-checker' "
             "checkers registered"
@@ -319,7 +321,7 @@
 
         # now run the regular mode of checking files and check that, in this proc, we
         # collect the right data
-        filepath = single_file_container[0][1]  # get the filepath element
+        filepath = [single_file_container[0][1]]  # get the filepath element
         linter.check(filepath)
         assert {
             "by_module": {
@@ -357,7 +359,9 @@
 
         # Invoke the lint process in a multiprocess way, although we only specify one
         # job.
-        check_parallel(linter, jobs=1, files=single_file_container, arguments=None)
+        check_parallel(
+            linter, jobs=1, files=iter(single_file_container), arguments=None
+        )
 
         assert {
             "by_module": {
diff --git a/tests/test_import_graph.py b/tests/test_import_graph.py
index 8029707..42e3baf 100644
--- a/tests/test_import_graph.py
+++ b/tests/test_import_graph.py
@@ -106,7 +106,7 @@
     linter.global_set_option("int-import-graph", "int_import.dot")
     # ignore this file causing spurious MemoryError w/ some python version (>=2.3?)
     linter.global_set_option("ignore", ("func_unknown_encoding.py",))
-    linter.check("input")
+    linter.check(["input"])
     linter.generate_reports()
     assert exists("import.dot")
     assert exists("ext_import.dot")
diff --git a/tests/test_regr.py b/tests/test_regr.py
index 12dd034..afb5e69 100644
--- a/tests/test_regr.py
+++ b/tests/test_regr.py
@@ -23,7 +23,7 @@
 import os
 import sys
 from os.path import abspath, dirname, join
-from typing import Dict, Iterator
+from typing import Iterator
 
 import astroid
 import pytest
@@ -61,15 +61,15 @@
 @pytest.mark.parametrize(
     "file_name, check",
     [
-        ("package.__init__", Equals("")),
-        ("precedence_test", Equals("")),
-        ("import_package_subpackage_module", Equals("")),
-        ("pylint.checkers.__init__", lambda x: "__path__" not in x),
-        (join(REGR_DATA, "classdoc_usage.py"), Equals("")),
-        (join(REGR_DATA, "module_global.py"), Equals("")),
-        (join(REGR_DATA, "decimal_inference.py"), Equals("")),
-        (join(REGR_DATA, "absimp", "string.py"), Equals("")),
-        (join(REGR_DATA, "bad_package"), lambda x: "Unused import missing" in x),
+        (["package.__init__"], Equals("")),
+        (["precedence_test"], Equals("")),
+        (["import_package_subpackage_module"], Equals("")),
+        (["pylint.checkers.__init__"], lambda x: "__path__" not in x),
+        ([join(REGR_DATA, "classdoc_usage.py")], Equals("")),
+        ([join(REGR_DATA, "module_global.py")], Equals("")),
+        ([join(REGR_DATA, "decimal_inference.py")], Equals("")),
+        ([join(REGR_DATA, "absimp", "string.py")], Equals("")),
+        ([join(REGR_DATA, "bad_package")], lambda x: "Unused import missing" in x),
     ],
 )
 def test_package(finalize_linter, file_name, check):
@@ -94,7 +94,7 @@
     "fname", [x for x in os.listdir(REGR_DATA) if x.endswith("_crash.py")]
 )
 def test_descriptor_crash(fname: str, finalize_linter: PyLinter) -> None:
-    finalize_linter.check(join(REGR_DATA, fname))
+    finalize_linter.check([join(REGR_DATA, fname)])
     finalize_linter.reporter.finalize().strip()
 
 
@@ -109,16 +109,14 @@
 
 @pytest.mark.usefixtures("modify_path")
 def test_check_package___init__(finalize_linter: PyLinter) -> None:
-    filename = "package.__init__"
+    filename = ["package.__init__"]
     finalize_linter.check(filename)
-    by_module_stats: Dict[str, Dict[str, int]] = finalize_linter.stats["by_module"]  # type: ignore
-    checked = list(by_module_stats.keys())
-    assert checked == [filename]
+    checked = list(finalize_linter.stats["by_module"].keys())  # type: ignore # Refactor of PyLinter.stats necessary
+    assert checked == filename
 
     os.chdir(join(REGR_DATA, "package"))
-    finalize_linter.check("__init__")
-    by_module_stats: Dict[str, Dict[str, int]] = finalize_linter.stats["by_module"]  # type: ignore
-    checked = list(by_module_stats.keys())
+    finalize_linter.check(["__init__"])
+    checked = list(finalize_linter.stats["by_module"].keys())  # type: ignore
     assert checked == ["__init__"]
 
 
diff --git a/tests/unittest_reporting.py b/tests/unittest_reporting.py
index d1d483a..88f9c43 100644
--- a/tests/unittest_reporting.py
+++ b/tests/unittest_reporting.py
@@ -29,6 +29,7 @@
 from pylint.lint import PyLinter
 from pylint.reporters import BaseReporter
 from pylint.reporters.text import ParseableTextReporter, TextReporter
+from pylint.typing import FileItem
 
 
 @pytest.fixture(scope="module")
@@ -120,7 +121,7 @@
             linter.reporter.set_output(text)
 
         linter.open()
-        linter.check_single_file("somemodule", source_file, "somemodule")
+        linter.check_single_file_item(FileItem("somemodule", source_file, "somemodule"))
         linter.add_message("line-too-long", line=1, args=(1, 2))
         linter.generate_reports()
         linter.reporter.writeln("direct output")