summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Sassoulas <pierre.sassoulas@gmail.com>2021-11-28 19:50:59 +0100
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2021-12-03 18:38:20 +0100
commit5bb0095aa122fd75108dc8049193b55b987ef224 (patch)
treec46e8ad64c446004bc72316c78aa25a305019fbe
parentbb3c4467374a31b713099a14f800fa3d5b6a4650 (diff)
downloadpylint-git-5bb0095aa122fd75108dc8049193b55b987ef224.tar.gz
Add typing to LintModuleOutputUpdate._check_output_text
Better typing for test options and fix existing issue
-rw-r--r--ChangeLog4
-rw-r--r--pylint/testutils/__init__.py2
-rw-r--r--pylint/testutils/functional/find_functional_tests.py1
-rw-r--r--pylint/testutils/functional/lint_module_output_update.py19
-rw-r--r--pylint/testutils/functional/test_file.py60
-rw-r--r--pylint/testutils/lint_module_test.py2
-rw-r--r--tests/functional/f/fixme.rc4
-rw-r--r--tests/functional/r/regression/regression_issue_4631.rc2
-rw-r--r--tests/functional/t/too/too_few_public_methods_excluded.rc2
-rw-r--r--tests/functional/t/too/too_many_ancestors_ignored_parents.rc2
-rw-r--r--tests/functional/t/too/too_many_statements.rc2
-rw-r--r--tests/test_functional.py2
-rw-r--r--tests/testutils/test_lint_module_output_update.py2
13 files changed, 76 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index 83b0b1586..9cf285dc2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,8 +11,8 @@ Release date: TBA
..
Put new features here and also in 'doc/whatsnew/2.13.rst'
-* Some file in ``pylint.testutils`` were deprecated, imports should be done from the
- ``pylint.testutils`` API directly
+* Some files in ``pylint.testutils`` were deprecated. In the future imports should be done from the
+ ``pylint.testutils.functional`` namespace directly.
..
Insert your changelog randomly, it will reduce merge conflicts
diff --git a/pylint/testutils/__init__.py b/pylint/testutils/__init__.py
index 803a1ae16..53e301da3 100644
--- a/pylint/testutils/__init__.py
+++ b/pylint/testutils/__init__.py
@@ -49,7 +49,7 @@ __all__ = [
from pylint.testutils.checker_test_case import CheckerTestCase
from pylint.testutils.constants import UPDATE_FILE, UPDATE_OPTION
from pylint.testutils.decorator import set_config
-from pylint.testutils.functional.test_file import FunctionalTestFile
+from pylint.testutils.functional import FunctionalTestFile
from pylint.testutils.get_test_info import _get_tests_info
from pylint.testutils.global_test_linter import linter
from pylint.testutils.lint_module_test import LintModuleTest
diff --git a/pylint/testutils/functional/find_functional_tests.py b/pylint/testutils/functional/find_functional_tests.py
index 27e5880da..610b05db1 100644
--- a/pylint/testutils/functional/find_functional_tests.py
+++ b/pylint/testutils/functional/find_functional_tests.py
@@ -15,6 +15,7 @@ REASONABLY_DISPLAYABLE_VERTICALLY = 48
def get_functional_test_files_from_directory(
input_dir: Union[Path, str]
) -> List[FunctionalTestFile]:
+ """Get all functional tests in the input_dir."""
suite = []
for dirpath, _, filenames in os.walk(input_dir):
if dirpath.endswith("__pycache__"):
diff --git a/pylint/testutils/functional/lint_module_output_update.py b/pylint/testutils/functional/lint_module_output_update.py
index dfb891189..0bd46fc0b 100644
--- a/pylint/testutils/functional/lint_module_output_update.py
+++ b/pylint/testutils/functional/lint_module_output_update.py
@@ -3,19 +3,22 @@
import csv
import os
-from typing import Optional
+from typing import List, Optional
from _pytest.config import Config
from pylint.constants import PY38_PLUS
from pylint.testutils.functional.test_file import FunctionalTestFile
-from pylint.testutils.lint_module_test import LintModuleTest
+from pylint.testutils.lint_module_test import LintModuleTest, MessageCounter
+from pylint.testutils.output_line import OutputLine
class LintModuleOutputUpdate(LintModuleTest):
- """If message files should be updated instead of checked."""
+ """Class to be used if expected output files should be updated instead of checked."""
class TestDialect(csv.excel):
+ """Dialect used by the csv writer."""
+
delimiter = ":"
lineterminator = "\n"
@@ -32,11 +35,19 @@ class LintModuleOutputUpdate(LintModuleTest):
)
super().__init__(test_file, config)
- def _check_output_text(self, _, expected_output, actual_output):
+ def _check_output_text(
+ self,
+ _: MessageCounter,
+ expected_output: List[OutputLine],
+ actual_output: List[OutputLine],
+ ) -> None:
+ """Overwrite or remove the expected output file based on actual output."""
+ # Remove the file if no output is actually expected and a file exists
if not expected_output and not actual_output:
if os.path.exists(self._test_file.expected_output):
os.remove(self._test_file.expected_output)
return
+ # Write file with expected output
with open(self._test_file.expected_output, "w", encoding="utf-8") as f:
writer = csv.writer(f, dialect="test")
for line in actual_output:
diff --git a/pylint/testutils/functional/test_file.py b/pylint/testutils/functional/test_file.py
index 4bf0777f8..8aa0361d4 100644
--- a/pylint/testutils/functional/test_file.py
+++ b/pylint/testutils/functional/test_file.py
@@ -2,10 +2,13 @@
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
import configparser
+import sys
from os.path import basename, exists, join
+from typing import List, Tuple
-def parse_python_version(ver_str):
+def parse_python_version(ver_str: str) -> Tuple[int, ...]:
+ """Convert python version to a tuple of integers for easy comparison."""
return tuple(int(digit) for digit in ver_str.split("."))
@@ -13,6 +16,33 @@ class NoFileError(Exception):
pass
+if sys.version_info >= (3, 8):
+ from typing import TypedDict
+else:
+ from typing_extensions import TypedDict
+
+
+class TestFileOptions(TypedDict):
+ min_pyver: Tuple[int, ...]
+ max_pyver: Tuple[int, ...]
+ min_pyver_end_position: Tuple[int, ...]
+ requires: List[str]
+ except_implementations: str # Type is actually comma separated list of string
+ exclude_platforms: str # Type is actually comma separated list of string
+
+
+# mypy need something literal, we can't create this dynamically from TestFileOptions
+POSSIBLE_TEST_OPTIONS = {
+ "min_pyver",
+ "max_pyver",
+ "min_pyver_end_position",
+ "requires",
+ "except_implementations",
+ "exclude_platforms",
+ "exclude_platforms",
+}
+
+
class FunctionalTestFile:
"""A single functional test case file with options."""
@@ -23,23 +53,23 @@ class FunctionalTestFile:
"requires": lambda s: s.split(","),
}
- def __init__(self, directory, filename):
+ def __init__(self, directory: str, filename: str) -> None:
self._directory = directory
self.base = filename.replace(".py", "")
- self.options = {
+ self.options: TestFileOptions = {
"min_pyver": (2, 5),
"max_pyver": (4, 0),
"min_pyver_end_position": (3, 8),
"requires": [],
- "except_implementations": [],
- "exclude_platforms": [],
+ "except_implementations": "",
+ "exclude_platforms": "",
}
self._parse_options()
- def __repr__(self):
+ def __repr__(self) -> str:
return f"FunctionalTest:{self.base}"
- def _parse_options(self):
+ def _parse_options(self) -> None:
cp = configparser.ConfigParser()
cp.add_section("testoptions")
try:
@@ -49,26 +79,30 @@ class FunctionalTestFile:
for name, value in cp.items("testoptions"):
conv = self._CONVERTERS.get(name, lambda v: v)
- self.options[name] = conv(value)
+
+ assert (
+ name in POSSIBLE_TEST_OPTIONS
+ ), f"[testoptions]' can only contains one of {POSSIBLE_TEST_OPTIONS}"
+ self.options[name] = conv(value) # type: ignore[misc]
@property
- def option_file(self):
+ def option_file(self) -> str:
return self._file_type(".rc")
@property
- def module(self):
+ def module(self) -> str:
package = basename(self._directory)
return ".".join([package, self.base])
@property
- def expected_output(self):
+ def expected_output(self) -> str:
return self._file_type(".txt", check_exists=False)
@property
- def source(self):
+ def source(self) -> str:
return self._file_type(".py")
- def _file_type(self, ext, check_exists=True):
+ def _file_type(self, ext: str, check_exists: bool = True) -> str:
name = join(self._directory, self.base + ext)
if not check_exists or exists(name):
return name
diff --git a/pylint/testutils/lint_module_test.py b/pylint/testutils/lint_module_test.py
index 05d6f4a22..cbdedeecc 100644
--- a/pylint/testutils/lint_module_test.py
+++ b/pylint/testutils/lint_module_test.py
@@ -17,7 +17,7 @@ from pylint import checkers
from pylint.lint import PyLinter
from pylint.message.message import Message
from pylint.testutils.constants import _EXPECTED_RE, _OPERATORS, UPDATE_OPTION
-from pylint.testutils.functional.test_file import (
+from pylint.testutils.functional.test_file import ( # need to import from functional.test_file to avoid cyclic import
FunctionalTestFile,
NoFileError,
parse_python_version,
diff --git a/tests/functional/f/fixme.rc b/tests/functional/f/fixme.rc
index 6b903c1bd..be1b23458 100644
--- a/tests/functional/f/fixme.rc
+++ b/tests/functional/f/fixme.rc
@@ -1,3 +1,5 @@
-[testoptions]
+[MISCELLANEOUS]
+# List of note tags to take in consideration, separated by a comma.
notes=XXX,TODO,./TODO
+# Regular expression of note tags to take in consideration.
notes-rgx=FIXME(?!.*ISSUE-\d+)|TO.*DO
diff --git a/tests/functional/r/regression/regression_issue_4631.rc b/tests/functional/r/regression/regression_issue_4631.rc
index 44c9b77ee..88cdb85bf 100644
--- a/tests/functional/r/regression/regression_issue_4631.rc
+++ b/tests/functional/r/regression/regression_issue_4631.rc
@@ -1,2 +1,2 @@
-[testoptions]
+[MASTER]
limit-inference-results=0
diff --git a/tests/functional/t/too/too_few_public_methods_excluded.rc b/tests/functional/t/too/too_few_public_methods_excluded.rc
index 00c025832..b6a2cc937 100644
--- a/tests/functional/t/too/too_few_public_methods_excluded.rc
+++ b/tests/functional/t/too/too_few_public_methods_excluded.rc
@@ -1,4 +1,4 @@
-[testoptions]
+[DESIGN]
min-public-methods=10 # to combat inherited methods
exclude-too-few-public-methods=json.*,^.*Control$
diff --git a/tests/functional/t/too/too_many_ancestors_ignored_parents.rc b/tests/functional/t/too/too_many_ancestors_ignored_parents.rc
index 1d06dad25..aa652704b 100644
--- a/tests/functional/t/too/too_many_ancestors_ignored_parents.rc
+++ b/tests/functional/t/too/too_many_ancestors_ignored_parents.rc
@@ -1,3 +1,3 @@
-[testoptions]
+[DESIGN]
max-parents=2
ignored-parents=functional.t.too.too_many_ancestors_ignored_parents.E
diff --git a/tests/functional/t/too/too_many_statements.rc b/tests/functional/t/too/too_many_statements.rc
index d6d22f237..19e0d5151 100644
--- a/tests/functional/t/too/too_many_statements.rc
+++ b/tests/functional/t/too/too_many_statements.rc
@@ -1,2 +1,2 @@
-[testoptions]
+[DESIGN]
max-statements=5
diff --git a/tests/test_functional.py b/tests/test_functional.py
index c877db49b..eb923401d 100644
--- a/tests/test_functional.py
+++ b/tests/test_functional.py
@@ -34,9 +34,9 @@ from pylint import testutils
from pylint.testutils import UPDATE_FILE, UPDATE_OPTION
from pylint.testutils.functional import (
FunctionalTestFile,
+ LintModuleOutputUpdate,
get_functional_test_files_from_directory,
)
-from pylint.testutils.functional.lint_module_output_update import LintModuleOutputUpdate
from pylint.utils import HAS_ISORT_5
# TODOs
diff --git a/tests/testutils/test_lint_module_output_update.py b/tests/testutils/test_lint_module_output_update.py
index 9f581ce76..ad414a9dd 100644
--- a/tests/testutils/test_lint_module_output_update.py
+++ b/tests/testutils/test_lint_module_output_update.py
@@ -29,7 +29,7 @@ def lint_module_fixture(
@pytest.mark.skipif(PY38_PLUS, reason="Requires python 3.7 or lower")
def test_not_py38(tmp_path: Path) -> None:
- with pytest.raises(RuntimeError, match="new, better AST in python 3.8"):
+ with pytest.raises(RuntimeError, match="new AST parser"):
LintModuleOutputUpdate(
test_file=FunctionalTestFile(str(tmp_path), str(tmp_path / "filename.py"))
)