From fd053aaf2066b9413156ac4e5b7013b846a21b1f Mon Sep 17 00:00:00 2001 From: Augusto Wagner Andreoli Date: Sun, 3 Mar 2019 12:32:28 +0100 Subject: [PATCH] feat: allow configuration of a missing message for each file --- README.md | 2 +- flake8_nitpick/config.py | 6 +----- flake8_nitpick/files/base.py | 20 +++++++++++++------- flake8_nitpick/files/pre_commit.py | 1 - flake8_nitpick/files/setup_cfg.py | 2 +- nitpick-style.toml | 6 ++++++ tests/test_nitpick.py | 2 +- tests/test_pre_commit.py | 4 ++-- tests/test_pyproject_toml.py | 9 ++++++--- 9 files changed, 31 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 6c616684..9b447d78 100644 --- a/README.md +++ b/README.md @@ -100,5 +100,5 @@ On `setup.cfg`, some keys are lists of multiple values separated by commas, like On the style file, it's possible to indicate which key/value pairs should be treated as multiple values instead of an exact string. Multiple keys can be added. - ["setup.cfg"] + ["setup.cfg".nitpick] comma_separated_values = ["flake8.ignore", "isort.some_key", "another_section.another_key"] diff --git a/flake8_nitpick/config.py b/flake8_nitpick/config.py index 135017e9..6aefcb74 100644 --- a/flake8_nitpick/config.py +++ b/flake8_nitpick/config.py @@ -80,11 +80,7 @@ def clear_cache_dir(self) -> None: def load_toml(self) -> YieldFlake8Error: """Load TOML configuration from files.""" pyproject_path: Path = self.root_dir / PyProjectTomlFile.file_name - if not pyproject_path.exists(): - yield self.flake8_error( - 1, f"{PyProjectTomlFile.file_name} does not exist. Install poetry and run 'poetry init' to create it." - ) - else: + if pyproject_path.exists(): self.pyproject_toml = toml.load(str(pyproject_path)) self.tool_nitpick_toml = self.pyproject_toml.get("tool", {}).get("nitpick", {}) diff --git a/flake8_nitpick/files/base.py b/flake8_nitpick/files/base.py index 2be6c350..ad07f3af 100644 --- a/flake8_nitpick/files/base.py +++ b/flake8_nitpick/files/base.py @@ -1,6 +1,5 @@ """Base file checker.""" from pathlib import Path -from typing import Optional from flake8_nitpick.types import YieldFlake8Error from flake8_nitpick.utils import NitpickMixin @@ -11,7 +10,6 @@ class BaseFile(NitpickMixin): file_name: str error_base_number = 300 - missing_file_extra_message: Optional[str] = None def __init__(self) -> None: """Init instance.""" @@ -20,8 +18,13 @@ def __init__(self) -> None: self.config = NitpickConfig.get_singleton() self.error_prefix = f"File: {self.file_name}: " self.file_path: Path = self.config.root_dir / self.file_name + + # Configuration for this file as a TOML dict, taken from the style file. self.file_toml = self.config.style_toml.get(self.toml_key, {}) + # Nitpick configuration for this file as a TOML dict, taken from the style file. + self.nitpick_toml = self.file_toml.get("nitpick", {}) + @property def toml_key(self): """Remove the dot in the beginning of the file name, otherwise it's an invalid TOML key.""" @@ -29,22 +32,25 @@ def toml_key(self): def check_exists(self) -> YieldFlake8Error: """Check if the file should exist; if there is style configuration for the file, then it should exist.""" + # The file should exist when there is any rule configured for it in the style file, + # or when this flag is manually set + # TODO: add this to the docs should_exist: bool = self.config.files.get(self.toml_key, bool(self.file_toml)) file_exists = self.file_path.exists() if should_exist and not file_exists: suggestion = self.suggest_initial_file() phrases = ["Missing file"] - if self.missing_file_extra_message: - phrases.append(self.missing_file_extra_message) + missing_message = self.nitpick_toml.get("missing_message", "") + if missing_message: + phrases.append(missing_message) if suggestion: - phrases.append(f"Suggested initial content:\n{suggestion}") + phrases.append(f"Suggested content:\n{suggestion}") yield self.flake8_error(1, ". ".join(phrases)) elif not should_exist and file_exists: yield self.flake8_error(2, "File should be deleted") elif file_exists: - for error in self.check_rules(): - yield error + yield from self.check_rules() def check_rules(self) -> YieldFlake8Error: """Check rules for this file. It should be overridden by inherited class if they need.""" diff --git a/flake8_nitpick/files/pre_commit.py b/flake8_nitpick/files/pre_commit.py index 105a6a14..89fbdf59 100644 --- a/flake8_nitpick/files/pre_commit.py +++ b/flake8_nitpick/files/pre_commit.py @@ -14,7 +14,6 @@ class PreCommitFile(BaseFile): file_name = ".pre-commit-config.yaml" error_base_number = 330 - missing_file_extra_message = "Run 'pre-commit install' after creating the file" KEY_REPOS = "repos" KEY_HOOKS = "hooks" diff --git a/flake8_nitpick/files/setup_cfg.py b/flake8_nitpick/files/setup_cfg.py index 52869e33..2fe167f2 100644 --- a/flake8_nitpick/files/setup_cfg.py +++ b/flake8_nitpick/files/setup_cfg.py @@ -24,7 +24,7 @@ def check_rules(self) -> YieldFlake8Error: if not self.file_path.exists(): return - self.comma_separated_values = set(self.file_toml.pop(self.COMMA_SEPARATED_VALUES, [])) + self.comma_separated_values = set(self.nitpick_toml.pop(self.COMMA_SEPARATED_VALUES, [])) setup_cfg = ConfigParser() setup_cfg.read_file(self.file_path.open()) diff --git a/nitpick-style.toml b/nitpick-style.toml index e12a365b..c3adbb7a 100644 --- a/nitpick-style.toml +++ b/nitpick-style.toml @@ -24,6 +24,9 @@ file = ".venv" file = ".pyup.yml" message = "Configure .travis.yml with safety instead: https://github.com/pyupio/safety#using-safety-with-a-ci-service" +["pyproject.toml".nitpick] +"missing_message" = "Install poetry and run 'poetry init' to create it" + ["pyproject.toml".tool.black] line-length = 120 @@ -88,6 +91,9 @@ warn_no_return = true warn_redundant_casts = true warn_unused_ignores = true +["pre-commit-config.yaml".nitpick] +"missing_message" = "Create the file with the contents below, then run 'pre-commit install'" + # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks ["pre-commit-config.yaml"] diff --git a/tests/test_nitpick.py b/tests/test_nitpick.py index 43545d1b..84b0e2f2 100644 --- a/tests/test_nitpick.py +++ b/tests/test_nitpick.py @@ -25,7 +25,7 @@ def test_comma_separated_keys_on_style_file(request): ProjectMock(request) .style( """ - ["setup.cfg"] + ["setup.cfg".nitpick] comma_separated_values = ["food.eat"] ["setup.cfg".food] eat = "salt,ham,eggs" diff --git a/tests/test_pre_commit.py b/tests/test_pre_commit.py index 9c972b60..79a72844 100644 --- a/tests/test_pre_commit.py +++ b/tests/test_pre_commit.py @@ -23,7 +23,7 @@ def test_missing_pre_commit_config_yaml(request): ) project.assert_errors_contain( """ - NIP331 File: .pre-commit-config.yaml: Missing file. Run 'pre-commit install' after creating the file. Suggested initial content: + NIP331 File: .pre-commit-config.yaml: Missing file. Suggested content: repos: - hooks: - any: valid @@ -51,7 +51,7 @@ def test_root_values_on_missing_file(request): ) project.assert_errors_contain( """ - NIP331 File: .pre-commit-config.yaml: Missing file. Run 'pre-commit install' after creating the file. Suggested initial content: + NIP331 File: .pre-commit-config.yaml: Missing file. Suggested content: fail_fast: true whatever: '1' """ diff --git a/tests/test_pyproject_toml.py b/tests/test_pyproject_toml.py index 8b59bd31..a3db90a7 100644 --- a/tests/test_pyproject_toml.py +++ b/tests/test_pyproject_toml.py @@ -5,6 +5,9 @@ def test_missing_pyproject_toml(request): """Suggest poetry init when pyproject.toml does not exist.""" - ProjectMock(request, pyproject_toml=False).lint().assert_errors_contain( - f"NIP201 {PyProjectTomlFile.file_name} does not exist. Install poetry and run 'poetry init' to create it." - ) + ProjectMock(request, pyproject_toml=False).style( + """ + ["pyproject.toml".nitpick] + "missing_message" = "Do something" + """ + ).lint().assert_errors_contain(f"NIP311 File: {PyProjectTomlFile.file_name}: Missing file. Do something")