From a6590c505e6ccdb7000464405634a2cc8fcd2bfb Mon Sep 17 00:00:00 2001 From: Guillaume Mulocher Date: Fri, 29 Mar 2024 17:48:41 +0100 Subject: [PATCH] ci: One TOML to control them all linters (#616) --- .pre-commit-config.yaml | 6 ++-- anta/cli/__init__.py | 8 ++++-- anta/decorators.py | 4 +-- pylintrc | 31 -------------------- pyproject.toml | 41 +++++++++++++++++++++++++-- tests/units/cli/get/test_utils.py | 4 +-- tests/units/cli/nrfu/test_commands.py | 14 ++++----- tests/units/reporter/test__init__.py | 33 +++++++++++++-------- tests/units/test_catalog.py | 8 +++--- tests/units/test_logger.py | 8 +++--- 10 files changed, 88 insertions(+), 69 deletions(-) delete mode 100644 pylintrc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 31784327d..585bcb8ab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,9 +58,9 @@ repos: description: This hook runs pylint. types: [python] args: - - -rn # Only display messages - - -sn # Don't display the score - - --rcfile=pylintrc # Link to config file + - -rn # Only display messages + - -sn # Don't display the score + - --rcfile=pyproject.toml # Link to config file - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.9.0 diff --git a/anta/cli/__init__.py b/anta/cli/__init__.py index 44e5c6711..759194db1 100644 --- a/anta/cli/__init__.py +++ b/anta/cli/__init__.py @@ -61,8 +61,12 @@ def cli() -> None: """Entrypoint for pyproject.toml.""" try: anta(obj={}, auto_envvar_prefix="ANTA") - except Exception as e: # pylint: disable=broad-exception-caught - anta_log_exception(e, f"Uncaught Exception when running ANTA CLI\n{GITHUB_SUGGESTION}", logger) + except Exception as exc: # pylint: disable=broad-exception-caught + anta_log_exception( + exc, + f"Uncaught Exception when running ANTA CLI\n{GITHUB_SUGGESTION}", + logger, + ) sys.exit(ExitCode.INTERNAL_ERROR) diff --git a/anta/decorators.py b/anta/decorators.py index 37f4fe2ff..76e16f56c 100644 --- a/anta/decorators.py +++ b/anta/decorators.py @@ -48,9 +48,9 @@ async def wrapper(*args: Any, **kwargs: Any) -> Any: anta_test = args[0] if new_tests: new_test_names = ", ".join(new_tests) - logger.warning(f"{anta_test.name} test is deprecated. Consider using the following new tests: {new_test_names}.") + logger.warning("%s test is deprecated. Consider using the following new tests: %s.", anta_test.name, new_test_names) else: - logger.warning(f"{anta_test.name} test is deprecated.") + logger.warning("%s test is deprecated.", anta_test.name) return await function(*args, **kwargs) return cast(F, wrapper) diff --git a/pylintrc b/pylintrc deleted file mode 100644 index a02d42c67..000000000 --- a/pylintrc +++ /dev/null @@ -1,31 +0,0 @@ -[MESSAGES CONTROL] -disable= - invalid-name, - logging-fstring-interpolation, - fixme - -[BASIC] -good-names=runCmds, i, y, t, c, x, e, fd, ip, v - -[DESIGN] -max-statements=61 -max-returns=8 -max-locals=23 - -[FORMAT] -max-line-length=165 -max-module-lines=1700 - -[SIMILARITIES] -# making similarity lines limit a bit higher than default 4 -min-similarity-lines=10 - -[TYPECHECK] -# https://stackoverflow.com/questions/49680191/click-and-pylint -signature-mutators=click.decorators.option - -[MAIN] -load-plugins=pylint_pydantic -extension-pkg-whitelist=pydantic -ignore-paths = ^tests/units/anta_tests/.*/data.py$, - ^tests/units/anta_tests/routing/.*/data.py$, diff --git a/pyproject.toml b/pyproject.toml index 7574cc08f..bad739dd6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -240,8 +240,8 @@ description = Check the code style commands = ruff check . ruff format . --check - pylint --rcfile=pylintrc anta - pylint --rcfile=pylintrc tests + pylint anta + pylint tests [testenv:type] description = Check typing @@ -267,6 +267,9 @@ commands = depends = py311 """ +################################ +# Ruff +################################ [tool.ruff] # Exclude a variety of commonly ignored directories. @@ -401,3 +404,37 @@ runtime-evaluated-base-classes = ["pydantic.BaseModel", "anta.models.AntaTest.In "anta/inventory/__init__.py" = [ "PLR0913", # Ok to have more than 5 arguments in the AntaInventory class ] + +################################ +# Pylint +################################ +[tool.pylint.'MESSAGES CONTROL'] +disable = [ + "invalid-name", + "fixme" +] + +[tool.pylint.DESIGN] +max-statements=61 +max-returns=8 +max-locals=23 + +[tool.pylint.FORMAT] +max-line-length=165 +max-module-lines=1700 + +[tool.pylint.SIMILARITIES] +# making similarity lines limit a bit higher than default 4 +min-similarity-lines=10 + +[tool.pylint.TYPECHECK] +# https://stackoverflow.com/questions/49680191/click-and-pylint +signature-mutators="click.decorators.option" + +[tool.pylint.MAIN] +load-plugins="pylint_pydantic" +extension-pkg-whitelist="pydantic" +ignore-paths = [ + "^tests/units/anta_tests/.*/data.py$", + "^tests/units/anta_tests/routing/.*/data.py$", +] diff --git a/tests/units/cli/get/test_utils.py b/tests/units/cli/get/test_utils.py index 8d24f186f..0dce33581 100644 --- a/tests/units/cli/get/test_utils.py +++ b/tests/units/cli/get/test_utils.py @@ -21,7 +21,7 @@ def test_get_cv_token() -> None: """Test anta.get.utils.get_cv_token.""" - ip = "42.42.42.42" + ip_addr = "42.42.42.42" username = "ant" password = "formica" @@ -29,7 +29,7 @@ def test_get_cv_token() -> None: mocked_ret = MagicMock(autospec=requests.Response) mocked_ret.json.return_value = {"sessionId": "simple"} patched_request.return_value = mocked_ret - res = get_cv_token(ip, username, password) + res = get_cv_token(ip_addr, username, password) patched_request.assert_called_once_with( "POST", "https://42.42.42.42/cvpservice/login/authenticate.do", diff --git a/tests/units/cli/nrfu/test_commands.py b/tests/units/cli/nrfu/test_commands.py index 8a58d08b5..4ea40b7d3 100644 --- a/tests/units/cli/nrfu/test_commands.py +++ b/tests/units/cli/nrfu/test_commands.py @@ -66,13 +66,13 @@ def test_anta_nrfu_json(click_runner: CliRunner) -> None: result = click_runner.invoke(anta, ["nrfu", "json"]) assert result.exit_code == ExitCode.OK assert "JSON results" in result.output - m = re.search(r"\[\n {[\s\S]+ }\n\]", result.output) - assert m is not None - result_list = json.loads(m.group()) - for r in result_list: - if r["name"] == "dummy": - assert r["test"] == "VerifyEOSVersion" - assert r["result"] == "success" + match = re.search(r"\[\n {[\s\S]+ }\n\]", result.output) + assert match is not None + result_list = json.loads(match.group()) + for res in result_list: + if res["name"] == "dummy": + assert res["test"] == "VerifyEOSVersion" + assert res["result"] == "success" def test_anta_nrfu_template(click_runner: CliRunner) -> None: diff --git a/tests/units/reporter/test__init__.py b/tests/units/reporter/test__init__.py index b5b413b28..0dc9f9a5c 100644 --- a/tests/units/reporter/test__init__.py +++ b/tests/units/reporter/test__init__.py @@ -30,8 +30,18 @@ class TestReportTable: pytest.param([], "*", "", id="empty list with delimiter"), pytest.param(["elem1"], None, "elem1", id="one elem list no delimiter"), pytest.param(["elem1"], "*", "* elem1", id="one elem list with delimiter"), - pytest.param(["elem1", "elem2"], None, "elem1\nelem2", id="two elems list no delimiter"), - pytest.param(["elem1", "elem2"], "&", "& elem1\n& elem2", id="two elems list with delimiter"), + pytest.param( + ["elem1", "elem2"], + None, + "elem1\nelem2", + id="two elems list no delimiter", + ), + pytest.param( + ["elem1", "elem2"], + "&", + "& elem1\n& elem2", + id="two elems list with delimiter", + ), ], ) def test__split_list_to_txt_list(self, usr_list: list[str], delimiter: str | None, expected_output: str) -> None: @@ -94,12 +104,12 @@ def test_report_all( ) -> None: """Test report_all.""" # pylint: disable=too-many-arguments - rm = result_manager_factory(number_of_tests) + manager = result_manager_factory(number_of_tests) report = ReportTable() kwargs = {"title": title} kwargs = {k: v for k, v in kwargs.items() if v is not None} - res = report.report_all(rm, **kwargs) # type: ignore[arg-type] + res = report.report_all(manager, **kwargs) # type: ignore[arg-type] assert isinstance(res, Table) assert res.title == (title or "All tests results") @@ -125,17 +135,16 @@ def test_report_summary_tests( # pylint: disable=too-many-arguments # TODO: refactor this later... this is injecting double test results by modyfing the device name # should be a fixture - rm = result_manager_factory(number_of_tests) - new_results = [result.model_copy() for result in rm.results] + manager = result_manager_factory(number_of_tests) + new_results = [result.model_copy() for result in manager.results] for result in new_results: result.name = "test_device" result.result = "failure" - rm.results = new_results report = ReportTable() kwargs = {"tests": [test] if test is not None else None, "title": title} kwargs = {k: v for k, v in kwargs.items() if v is not None} - res = report.report_summary_tests(rm, **kwargs) # type: ignore[arg-type] + res = report.report_summary_tests(manager, **kwargs) # type: ignore[arg-type] assert isinstance(res, Table) assert res.title == (title or "Summary per test") @@ -161,17 +170,17 @@ def test_report_summary_devices( # pylint: disable=too-many-arguments # TODO: refactor this later... this is injecting double test results by modyfing the device name # should be a fixture - rm = result_manager_factory(number_of_tests) - new_results = [result.model_copy() for result in rm.results] + manager = result_manager_factory(number_of_tests) + new_results = [result.model_copy() for result in manager.results] for result in new_results: result.name = dev or "test_device" result.result = "failure" - rm.results = new_results + manager.results = new_results report = ReportTable() kwargs = {"devices": [dev] if dev is not None else None, "title": title} kwargs = {k: v for k, v in kwargs.items() if v is not None} - res = report.report_summary_devices(rm, **kwargs) # type: ignore[arg-type] + res = report.report_summary_devices(manager, **kwargs) # type: ignore[arg-type] assert isinstance(res, Table) assert res.title == (title or "Summary per device") diff --git a/tests/units/test_catalog.py b/tests/units/test_catalog.py index 80138c07d..8de6382b4 100644 --- a/tests/units/test_catalog.py +++ b/tests/units/test_catalog.py @@ -206,8 +206,8 @@ def test_from_list(self, catalog_data: dict[str, Any]) -> None: def test_from_dict(self, catalog_data: dict[str, Any]) -> None: """Instantiate AntaCatalog from a dict.""" file = DATA_DIR / catalog_data["filename"] - with file.open(encoding="UTF-8") as f: - data = safe_load(f) + with file.open(encoding="UTF-8") as file: + data = safe_load(file) catalog: AntaCatalog = AntaCatalog.from_dict(data) assert len(catalog.tests) == len(catalog_data["tests"]) @@ -248,8 +248,8 @@ def test_from_list_fail(self, catalog_data: dict[str, Any]) -> None: def test_from_dict_fail(self, catalog_data: dict[str, Any]) -> None: """Errors when instantiating AntaCatalog from a list of tuples.""" file = DATA_DIR / catalog_data["filename"] - with file.open(encoding="UTF-8") as f: - data = safe_load(f) + with file.open(encoding="UTF-8") as file: + data = safe_load(file) with pytest.raises((ValidationError, TypeError)) as exec_info: AntaCatalog.from_dict(data) if isinstance(exec_info.value, ValidationError): diff --git a/tests/units/test_logger.py b/tests/units/test_logger.py index 782490e34..d9b7c7672 100644 --- a/tests/units/test_logger.py +++ b/tests/units/test_logger.py @@ -69,9 +69,9 @@ def test_anta_log_exception( # Need to raise to trigger nice stacktrace for __DEBUG__ == True try: raise exception - except ValueError as e: + except ValueError as exc: with patch("anta.logger.__DEBUG__", new=debug_value): - anta_log_exception(e, message=message, calling_logger=calling_logger) + anta_log_exception(exc, message=message, calling_logger=calling_logger) # Two log captured if debug_value: @@ -110,7 +110,7 @@ def test_tb_to_str() -> None: """Test tb_to_str.""" try: my_raising_function(ValueError("test")) - except ValueError as e: - output = tb_to_str(e) + except ValueError as exc: + output = tb_to_str(exc) assert "Traceback" in output assert 'my_raising_function(ValueError("test"))' in output