From b086a24c5503c09e26ca429455bd4fea54cf01bb Mon Sep 17 00:00:00 2001 From: "Augusto W. Andreoli" Date: Wed, 11 Nov 2020 00:41:03 +0100 Subject: [PATCH] fix: toml module now accepts keys beginning with dot (fix #183) test: deprecation of the section without dots refactor: remove unused hook refactor: a single hook to handle and validate refactor: a simpler hook implementation refactor: reduce complexity chore: add dots, remove pytest warnings chore: validate JSON files with a schema build: fix lint warnings and (almost all) tests refactor: add Deprecation class fix: don't display a deprecation warning for the merged style --- docs/defaults.rst | 18 +++--- poetry.lock | 33 ++++------- setup.cfg | 24 ++++---- src/nitpick/config.py | 16 +++++- src/nitpick/exceptions.py | 41 ++++++++++++++ src/nitpick/flake8.py | 14 ++--- src/nitpick/formats.py | 9 --- src/nitpick/plugins/__init__.py | 9 +-- src/nitpick/plugins/base.py | 19 +++---- src/nitpick/plugins/json.py | 6 +- src/nitpick/plugins/pre_commit.py | 10 ++-- src/nitpick/plugins/pyproject_toml.py | 11 ++-- src/nitpick/plugins/setup_cfg.py | 14 ++--- src/nitpick/plugins/text.py | 8 ++- src/nitpick/schemas.py | 3 +- src/nitpick/style.py | 81 +++++++++++++++++++++------ styles/black.toml | 4 +- styles/flake8.toml | 2 +- styles/isort.toml | 2 +- styles/mypy.toml | 2 +- styles/pre-commit/bash.toml | 2 +- styles/pre-commit/commitlint.toml | 2 +- styles/pre-commit/general.toml | 2 +- styles/pre-commit/python.toml | 2 +- tests/conftest.py | 10 ++-- tests/helpers.py | 4 +- tests/test_json.py | 2 +- tests/test_pre_commit.py | 46 +++++++++++---- tests/test_style.py | 12 ++-- 29 files changed, 255 insertions(+), 153 deletions(-) diff --git a/docs/defaults.rst b/docs/defaults.rst index 0d6c8e4d..43094b49 100644 --- a/docs/defaults.rst +++ b/docs/defaults.rst @@ -40,7 +40,7 @@ Content of `styles/black.toml #"""] @@ -83,7 +83,7 @@ Content of `styles/flake8.toml =5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] -docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] @@ -85,7 +85,7 @@ python-versions = "*" [[package]] name = "certifi" -version = "2020.6.20" +version = "2020.11.8" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -653,7 +653,7 @@ python-versions = "*" [[package]] name = "sortedcontainers" -version = "2.2.2" +version = "2.3.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" category = "main" optional = false @@ -909,8 +909,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, - {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, + {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, + {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, ] babel = [ {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, @@ -921,8 +921,8 @@ backcall = [ {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] certifi = [ - {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, - {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, + {file = "certifi-2020.11.8-py2.py3-none-any.whl", hash = "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd"}, + {file = "certifi-2020.11.8.tar.gz", hash = "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, @@ -1182,8 +1182,6 @@ responses = [ {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win32.whl", hash = "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b"}, - {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a"}, - {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5"}, {file = "ruamel.yaml.clib-0.2.2.tar.gz", hash = "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7"}, ] six = [ @@ -1195,8 +1193,8 @@ snowballstemmer = [ {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] sortedcontainers = [ - {file = "sortedcontainers-2.2.2-py2.py3-none-any.whl", hash = "sha256:c633ebde8580f241f274c1f8994a665c0e54a17724fecd0cae2f079e09c36d3f"}, - {file = "sortedcontainers-2.2.2.tar.gz", hash = "sha256:4e73a757831fc3ca4de2859c422564239a31d8213d09a2a666e375807034d2ba"}, + {file = "sortedcontainers-2.3.0-py2.py3-none-any.whl", hash = "sha256:37257a32add0a3ee490bb170b599e93095eed89a55da91fa9f48753ea12fd73f"}, + {file = "sortedcontainers-2.3.0.tar.gz", hash = "sha256:59cc937650cf60d677c16775597c89a960658a09cf7c1a668f86e1e4464b10a1"}, ] sphinx = [ {file = "Sphinx-3.3.0-py3-none-any.whl", hash = "sha256:3abdb2c57a65afaaa4f8573cbabd5465078eb6fd282c1e4f87f006875a7ec0c7"}, @@ -1254,28 +1252,19 @@ typed-ast = [ {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f"}, {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298"}, {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d"}, {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c"}, - {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072"}, - {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91"}, - {file = "typed_ast-1.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d"}, - {file = "typed_ast-1.4.1-cp39-cp39-win32.whl", hash = "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395"}, - {file = "typed_ast-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c"}, {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] urllib3 = [ diff --git a/setup.cfg b/setup.cfg index ba06c30a..26503c24 100644 --- a/setup.cfg +++ b/setup.cfg @@ -66,7 +66,7 @@ norecursedirs = .* build dist CVS _darcs {arch} *.egg venv var docs [tox:tox] isolated_build = True -requires = +requires = tox-travis tox-venv tox-pyenv @@ -76,12 +76,12 @@ envlist = clean,lint,py39,py38,py37,py36,py35,report description = Run tests with pytest and coverage deps = pytest-cov extras = test -depends = +depends = {py39,py38,py37,py36,py35}: clean report: py39,py38,py37,py36,py35 -setenv = +setenv = PY_IGNORE_IMPORTMISMATCH = 1 -commands = +commands = python -m pip --version python -m pytest --cov-config=setup.cfg --cov --cov-append --cov-report=term-missing --doctest-modules {posargs:-vv} @@ -95,13 +95,13 @@ commands = coverage erase description = Lint all files with pre-commit basepython = python3.7 platform = linux|darwin -extras = +extras = lint test -deps = +deps = pre-commit safety -commands = +commands = pre-commit run --all-files safety check @@ -109,14 +109,14 @@ commands = description = Coverage report skip_install = true deps = coverage -commands = +commands = coverage report coverage html [coverage:run] branch = true parallel = true -omit = +omit = tests/* .tox/* /home/travis/virtualenv/* @@ -135,12 +135,12 @@ sort = Cover description = Build the HTML docs using Sphinx (sphinx-build, API docs, link checks) basepython = python3.7 extras = doc -commands = +commands = sphinx-apidoc --force --module-first --separate --implicit-namespaces --output-dir docs/source src/nitpick/ python3 docs/generate_rst.py - + sphinx-build --color -b linkcheck docs "{toxworkdir}/docs_out" - + sphinx-build -d "{toxworkdir}/docs_doctree" --color -b html docs "{toxworkdir}/docs_out" {posargs} [bandit] diff --git a/src/nitpick/config.py b/src/nitpick/config.py index ee220dd6..d3100636 100644 --- a/src/nitpick/config.py +++ b/src/nitpick/config.py @@ -2,6 +2,8 @@ import logging from typing import TYPE_CHECKING, Optional +from identify import identify + from nitpick.app import NitpickApp from nitpick.constants import ( MERGED_STYLE_TOML, @@ -10,6 +12,7 @@ TOOL_NITPICK, TOOL_NITPICK_JMEX, ) +from nitpick.exceptions import Deprecation from nitpick.formats import TOMLFormat from nitpick.generic import search_dict, version_to_tuple from nitpick.mixin import NitpickMixin @@ -68,7 +71,7 @@ def merge_styles(self) -> YieldFlake8Error: self.style_dict = style.merge_toml_dict() if not NitpickApp.current().style_errors: # Don't show duplicated errors: if there are style errors already, don't validate the merged style. - style.validate_style(MERGED_STYLE_TOML, self.style_dict) + style.validate_style(MERGED_STYLE_TOML, self.style_dict, True) from nitpick.flake8 import NitpickExtension # pylint: disable=import-outside-toplevel @@ -82,3 +85,14 @@ def merge_styles(self) -> YieldFlake8Error: self.nitpick_section = self.style_dict.get("nitpick", {}) self.nitpick_files_section = self.nitpick_section.get("files", {}) + + +class FileNameCleaner: # pylint: disable=too-few-public-methods + """Clean the file name and get its tags.""" + + def __init__(self, path_from_root: str) -> None: + if Deprecation.pre_commit_without_dash(path_from_root): + self.path_from_root = "." + path_from_root + else: + self.path_from_root = "." + path_from_root[1:] if path_from_root.startswith("-") else path_from_root + self.tags = identify.tags_from_filename(path_from_root) diff --git a/src/nitpick/exceptions.py b/src/nitpick/exceptions.py index fdb214cb..5c7744b5 100644 --- a/src/nitpick/exceptions.py +++ b/src/nitpick/exceptions.py @@ -1,5 +1,9 @@ """Nitpick exceptions.""" +import warnings from pathlib import Path +from typing import Any, Dict + +from nitpick.constants import PROJECT_NAME class NitpickError(Exception): @@ -53,3 +57,40 @@ class StyleError(NitpickError): def __init__(self, style_file_name: str, *args: object) -> None: self.style_file_name = style_file_name super().__init__(*args) + + +class Deprecation: + """All deprecation messages in a single class. + + When it's time to break compatibility, remove a method/warning below, + and older config files will trigger validation errors on Nitpick. + """ + + @staticmethod + def pre_commit_without_dash(path_from_root: str) -> bool: + """The pre-commit config should start with a dot on the config file.""" + from nitpick.plugins.pre_commit import PreCommitPlugin # pylint: disable=import-outside-toplevel + + if path_from_root == PreCommitPlugin.file_name[1:]: + warnings.warn( + 'The section name for dotfiles should start with a dot: [".{}"]'.format(path_from_root), + DeprecationWarning, + ) + return True + + return False + + @staticmethod + def jsonfile_section(style_errors: Dict[str, Any], is_merged_style: bool) -> bool: + """The [nitpick.JSONFile] is not needed anymore; JSON files are now detected by the extension.""" + has_nitpick_jsonfile_section = style_errors.get(PROJECT_NAME, {}).pop("JSONFile", None) + if has_nitpick_jsonfile_section: + if not style_errors[PROJECT_NAME]: + style_errors.pop(PROJECT_NAME) + if not is_merged_style: + warnings.warn( + "The [nitpick.JSONFile] section is not needed anymore; just declare your JSON files directly", + DeprecationWarning, + ) + return True + return False diff --git a/src/nitpick/flake8.py b/src/nitpick/flake8.py index e5aa87e4..001d5532 100644 --- a/src/nitpick/flake8.py +++ b/src/nitpick/flake8.py @@ -5,10 +5,10 @@ import attr from flake8.options.manager import OptionManager -from identify import identify from nitpick import __version__ from nitpick.app import NitpickApp +from nitpick.config import FileNameCleaner from nitpick.constants import PROJECT_NAME from nitpick.mixin import NitpickMixin from nitpick.typedefs import YieldFlake8Error @@ -58,17 +58,17 @@ def run(self) -> YieldFlake8Error: return [] # Get all root keys from the style TOML. - for path, config_dict in app.config.style_dict.items(): + for config_key, config_dict in app.config.style_dict.items(): # All except "nitpick" are file names. - if path == PROJECT_NAME: + if config_key == PROJECT_NAME: continue # For each file name, find the plugin that can handle the file. - tags = identify.tags_from_filename(path) - for base_file in app.plugin_manager.hook.handle_config_file( # pylint: disable=no-member - config=config_dict, file_name=path, tags=tags + cleaner = FileNameCleaner(config_key) + for plugin_instance in app.plugin_manager.hook.handler( # pylint: disable=no-member + file_name=cleaner.path_from_root, tags=cleaner.tags ): - yield from base_file.check_exists() + yield from plugin_instance.process(config_dict) return [] diff --git a/src/nitpick/formats.py b/src/nitpick/formats.py index 2665c094..f5ec99ab 100644 --- a/src/nitpick/formats.py +++ b/src/nitpick/formats.py @@ -205,15 +205,6 @@ def compare_with_dictdiffer( class TOMLFormat(BaseFormat): """TOML configuration format.""" - @staticmethod - def group_name_for(file_name: str) -> str: - """Return a TOML group name for a file name. - - If the file name begins with a dot, remove it. - Otherwise an error is raised: TomlDecodeError: Invalid group name 'xxx'. Try quoting it. - """ - return file_name.lstrip(".") - def load(self) -> bool: """Load a TOML file by its path, a string or a dict.""" if self._loaded: diff --git a/src/nitpick/plugins/__init__.py b/src/nitpick/plugins/__init__.py index 6646ed83..24164834 100644 --- a/src/nitpick/plugins/__init__.py +++ b/src/nitpick/plugins/__init__.py @@ -10,7 +10,6 @@ import pluggy from nitpick.constants import PROJECT_NAME -from nitpick.typedefs import JsonDict if TYPE_CHECKING: from nitpick.plugins.base import NitpickPlugin @@ -22,14 +21,12 @@ @hookspec def plugin_class() -> Type["NitpickPlugin"]: - """You should return your plugin class here.""" + """Return your plugin class here (it should inherit from :py:class:`nitpick.plugins.base.NitpickPlugin`).""" @hookspec -def handle_config_file( # pylint: disable=unused-argument - config: JsonDict, file_name: str, tags: Set[str] -) -> Optional["NitpickPlugin"]: - """You should return a valid :py:class:`nitpick.plugins.base.NitpickPlugin` instance or ``None``. +def handler(file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: # pylint: disable=unused-argument + """Return a valid :py:class:`nitpick.plugins.base.NitpickPlugin` instance or ``None``. :return: A plugin instance if your plugin handles this file name or any of its ``identify`` tags. Return ``None`` if your plugin doesn't handle this file or file type. diff --git a/src/nitpick/plugins/base.py b/src/nitpick/plugins/base.py index d16c3111..29668d58 100644 --- a/src/nitpick/plugins/base.py +++ b/src/nitpick/plugins/base.py @@ -5,7 +5,6 @@ import jmespath from nitpick.app import NitpickApp -from nitpick.formats import TOMLFormat from nitpick.generic import search_dict from nitpick.mixin import NitpickMixin from nitpick.typedefs import JsonDict, YieldFlake8Error @@ -35,15 +34,15 @@ class NitpickPlugin(NitpickMixin, metaclass=abc.ABCMeta): #: Which ``identify`` tags this :py:class:`nitpick.plugins.base.NitpickPlugin` child recognises. identify_tags = set() # type: Set[str] - def __init__(self, config: JsonDict, file_name: str = None) -> None: - if file_name is not None: - self.file_name = file_name + def __init__(self, path_from_root: str = None) -> None: + if path_from_root is not None: + self.file_name = path_from_root self.error_prefix = "File {}".format(self.file_name) self.file_path = NitpickApp.current().root_dir / self.file_name # type: Path # Configuration for this file as a TOML dict, taken from the style file. - self.file_dict = config or {} # type: JsonDict + self.file_dict = {} # type: JsonDict # Nitpick configuration for this file as a TOML dict, taken from the style file. self.nitpick_file_dict = search_dict( @@ -66,12 +65,12 @@ def get_compiled_jmespath_file_names(cls): """Return a compiled JMESPath expression for file names, using the class name as part of the key.""" return jmespath.compile("nitpick.{}.file_names".format(cls.__name__)) - def check_exists(self) -> YieldFlake8Error: - """Check if the file should exist.""" + def process(self, config: JsonDict) -> YieldFlake8Error: + """Process the file, check if it should exist, check rules.""" + self.file_dict = config or {} + config_data_exists = bool(self.file_dict or self.nitpick_file_dict) - should_exist = NitpickApp.current().config.nitpick_files_section.get( - TOMLFormat.group_name_for(self.file_name), True - ) # type: bool + should_exist = NitpickApp.current().config.nitpick_files_section.get(self.file_name, True) # type: bool file_exists = self.file_path.exists() if config_data_exists and not file_exists: diff --git a/src/nitpick/plugins/json.py b/src/nitpick/plugins/json.py index 5acebd0a..a8773586 100644 --- a/src/nitpick/plugins/json.py +++ b/src/nitpick/plugins/json.py @@ -92,6 +92,8 @@ def plugin_class() -> Type["NitpickPlugin"]: @hookimpl -def handle_config_file(config: JsonDict, file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: +def handler(file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: """Handle JSON files.""" - return JSONPlugin(config, file_name) if "json" in tags else None + if "json" in tags: + return JSONPlugin(file_name) + return None diff --git a/src/nitpick/plugins/pre_commit.py b/src/nitpick/plugins/pre_commit.py index eaa6d769..2225c058 100644 --- a/src/nitpick/plugins/pre_commit.py +++ b/src/nitpick/plugins/pre_commit.py @@ -4,7 +4,7 @@ import attr -from nitpick.formats import TOMLFormat, YAMLFormat +from nitpick.formats import YAMLFormat from nitpick.generic import find_object_by_key, search_dict from nitpick.plugins import hookimpl from nitpick.plugins.base import NitpickPlugin @@ -197,8 +197,8 @@ def plugin_class() -> Type["NitpickPlugin"]: @hookimpl -def handle_config_file( # pylint: disable=unused-argument - config: JsonDict, file_name: str, tags: Set[str] -) -> Optional["NitpickPlugin"]: +def handler(file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: # pylint: disable=unused-argument """Handle pre-commit config file.""" - return PreCommitPlugin(config) if file_name == TOMLFormat.group_name_for(PreCommitPlugin.file_name) else None + if file_name == PreCommitPlugin.file_name: + return PreCommitPlugin() + return None diff --git a/src/nitpick/plugins/pyproject_toml.py b/src/nitpick/plugins/pyproject_toml.py index ee3610b3..53a57855 100644 --- a/src/nitpick/plugins/pyproject_toml.py +++ b/src/nitpick/plugins/pyproject_toml.py @@ -4,7 +4,7 @@ from nitpick.app import NitpickApp from nitpick.plugins import hookimpl from nitpick.plugins.base import NitpickPlugin -from nitpick.typedefs import JsonDict, YieldFlake8Error +from nitpick.typedefs import YieldFlake8Error class PyProjectTomlPlugin(NitpickPlugin): @@ -37,9 +37,8 @@ def plugin_class() -> Type["NitpickPlugin"]: @hookimpl -def handle_config_file( # pylint: disable=unused-argument - config: JsonDict, file_name: str, tags: Set[str] -) -> Optional["NitpickPlugin"]: +def handler(file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: # pylint: disable=unused-argument """Handle pyproject.toml file.""" - base_file = PyProjectTomlPlugin(config) - return base_file if file_name == base_file.file_name else None + if file_name == PyProjectTomlPlugin.file_name: + return PyProjectTomlPlugin() + return None diff --git a/src/nitpick/plugins/setup_cfg.py b/src/nitpick/plugins/setup_cfg.py index 48d28130..04a2af7b 100644 --- a/src/nitpick/plugins/setup_cfg.py +++ b/src/nitpick/plugins/setup_cfg.py @@ -7,7 +7,7 @@ from nitpick.plugins import hookimpl from nitpick.plugins.base import NitpickPlugin -from nitpick.typedefs import JsonDict, YieldFlake8Error +from nitpick.typedefs import YieldFlake8Error class SetupCfgPlugin(NitpickPlugin): @@ -23,8 +23,8 @@ class SetupCfgPlugin(NitpickPlugin): expected_sections = set() # type: Set[str] missing_sections = set() # type: Set[str] - def __init__(self, config: JsonDict, file_name: str = None) -> None: - super().__init__(config, file_name) + def __init__(self, path_from_root: str = None) -> None: + super().__init__(path_from_root) self.comma_separated_values = set(self.nitpick_file_dict.get(self.COMMA_SEPARATED_VALUES, [])) # type: Set[str] def suggest_initial_contents(self) -> str: @@ -124,8 +124,8 @@ def plugin_class() -> Type["NitpickPlugin"]: @hookimpl -def handle_config_file( # pylint: disable=unused-argument - config: JsonDict, file_name: str, tags: Set[str] -) -> Optional["NitpickPlugin"]: +def handler(file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: # pylint: disable=unused-argument """Handle the setup.cfg file.""" - return SetupCfgPlugin(config) if file_name == SetupCfgPlugin.file_name else None + if file_name == SetupCfgPlugin.file_name: + return SetupCfgPlugin() + return None diff --git a/src/nitpick/plugins/text.py b/src/nitpick/plugins/text.py index a632d93a..daf23f4e 100644 --- a/src/nitpick/plugins/text.py +++ b/src/nitpick/plugins/text.py @@ -9,7 +9,7 @@ from nitpick.plugins import hookimpl from nitpick.plugins.base import NitpickPlugin from nitpick.schemas import help_message -from nitpick.typedefs import JsonDict, YieldFlake8Error +from nitpick.typedefs import YieldFlake8Error LOGGER = logging.getLogger(__name__) @@ -71,6 +71,8 @@ def plugin_class() -> Type["NitpickPlugin"]: @hookimpl -def handle_config_file(config: JsonDict, file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: +def handler(file_name: str, tags: Set[str]) -> Optional["NitpickPlugin"]: """Handle text files.""" - return TextPlugin(config, file_name) if "plain-text" in tags else None + if "plain-text" in tags: + return TextPlugin(file_name) + return None diff --git a/src/nitpick/schemas.py b/src/nitpick/schemas.py index 2853a77b..2e71e447 100644 --- a/src/nitpick/schemas.py +++ b/src/nitpick/schemas.py @@ -8,7 +8,6 @@ from nitpick import fields from nitpick.constants import READ_THE_DOCS_URL from nitpick.generic import flatten -from nitpick.plugins.setup_cfg import SetupCfgPlugin def flatten_marshmallow_errors(errors: Dict) -> str: @@ -72,7 +71,7 @@ class NitpickFilesSectionSchema(BaseNitpickSchema): absent = fields.Dict(fields.NonEmptyString, fields.String()) present = fields.Dict(fields.NonEmptyString, fields.String()) # TODO: load this schema dynamically, then add this next field setup_cfg - setup_cfg = fields.Nested(SetupCfgSchema, data_key=SetupCfgPlugin.file_name) + setup_cfg = fields.Nested(SetupCfgSchema, data_key="setup.cfg") class NitpickSectionSchema(BaseNitpickSchema): diff --git a/src/nitpick/style.py b/src/nitpick/style.py index ce0342e0..3e87e8c7 100644 --- a/src/nitpick/style.py +++ b/src/nitpick/style.py @@ -1,14 +1,14 @@ """Style files.""" import logging -import warnings from collections import OrderedDict from pathlib import Path -from typing import Dict, List, Optional, Set, Type +from typing import Any, Dict, List, Optional, Set, Type from urllib.parse import urlparse, urlunparse import click import requests from identify import identify +from marshmallow import Schema from slugify import slugify from toml import TomlDecodeError @@ -22,11 +22,12 @@ RAW_GITHUB_CONTENT_BASE_URL, TOML_EXTENSION, ) +from nitpick.exceptions import Deprecation from nitpick.formats import TOMLFormat from nitpick.generic import MergeDict, climb_directory_tree, is_url, pretty_exception, search_dict from nitpick.plugins.base import NitpickPlugin from nitpick.plugins.pyproject_toml import PyProjectTomlPlugin -from nitpick.schemas import BaseStyleSchema, flatten_marshmallow_errors +from nitpick.schemas import BaseStyleSchema, NitpickSectionSchema, flatten_marshmallow_errors from nitpick.typedefs import JsonDict, StrOrList LOGGER = logging.getLogger(__name__) @@ -42,6 +43,7 @@ def __init__(self) -> None: self._dynamic_schema_class = BaseStyleSchema # type: type self.rebuild_dynamic_schema() + self.style_errors = {} # type: Dict[str, Any] @staticmethod def get_default_style_url(): @@ -65,26 +67,40 @@ def find_initial_styles(self, configured_styles: StrOrList): self.include_multiple_styles(chosen_styles) - def validate_style(self, style_file_name: str, original_data: JsonDict): + def validate_style(self, style_file_name: str, original_data: JsonDict, is_merged_style: bool): """Validate a style file (TOML) against a Marshmallow schema.""" self.rebuild_dynamic_schema(original_data) style_errors = self._dynamic_schema_class().validate(original_data) if style_errors: - has_nitpick_jsonfile_section = style_errors.get(PROJECT_NAME, {}).pop("JSONFile", None) - if has_nitpick_jsonfile_section: - warnings.warn( - "The [nitpick.JSONFile] section is not needed anymore; just declare your JSON files directly", - DeprecationWarning, - ) - if not style_errors[PROJECT_NAME]: - style_errors.pop(PROJECT_NAME) + Deprecation.jsonfile_section(style_errors, is_merged_style) if style_errors: NitpickApp.current().add_style_error( style_file_name, "Invalid config:", flatten_marshmallow_errors(style_errors) ) + def validate_schema( + self, + path_from_root: str, + schema: Type[Schema], + original_data: JsonDict, + is_merged_style: bool, + ): + """Validate the schema for the file.""" + if not schema: + return + + inherited_schema = schema is not BaseStyleSchema + data_to_validate = original_data if inherited_schema else {path_from_root: None} + local_errors = schema().validate(data_to_validate) + if local_errors and inherited_schema: + local_errors = {path_from_root: local_errors} + + if local_errors: + Deprecation.jsonfile_section(local_errors, is_merged_style) + self.style_errors.update(local_errors) + def include_multiple_styles(self, chosen_styles: StrOrList) -> None: """Include a list of styles (or just one) into this style tree.""" style_uris = [chosen_styles] if isinstance(chosen_styles, str) else chosen_styles # type: List[str] @@ -94,24 +110,54 @@ def include_multiple_styles(self, chosen_styles: StrOrList) -> None: continue toml = TOMLFormat(path=style_path) + app = NitpickApp.current() try: - toml_dict = toml.as_data + read_toml_dict = toml.as_data except TomlDecodeError as err: - NitpickApp.current().add_style_error(style_path.name, pretty_exception(err, "Invalid TOML")) + app.add_style_error(style_path.name, pretty_exception(err, "Invalid TOML")) # If the TOML itself could not be parsed, we can't go on return try: - display_name = str(style_path.relative_to(NitpickApp.current().root_dir)) + display_name = str(style_path.relative_to(app.root_dir)) except ValueError: display_name = style_uri - self.validate_style(display_name, toml_dict) + + toml_dict = self._validate_config(read_toml_dict) + + if self.style_errors: + NitpickApp.current().add_style_error( + display_name, "Invalid config:", flatten_marshmallow_errors(self.style_errors) + ) self._all_styles.add(toml_dict) sub_styles = search_dict(NITPICK_STYLES_INCLUDE_JMEX, toml_dict, []) # type: StrOrList if sub_styles: self.include_multiple_styles(sub_styles) + def _validate_config(self, config_dict: dict) -> dict: + self.style_errors = {} + toml_dict = OrderedDict() + for key, value_dict in config_dict.items(): + from nitpick.config import FileNameCleaner # pylint: disable=import-outside-toplevel + + cleaner = FileNameCleaner(key) + toml_dict[cleaner.path_from_root] = value_dict + if key == PROJECT_NAME: + schemas = [NitpickSectionSchema] + else: + schemas = [ + plugin.validation_schema + for plugin in NitpickApp.current().plugin_manager.hook.handler( # pylint: disable=no-member + file_name=cleaner.path_from_root, tags=cleaner.tags + ) + ] + if not schemas: + self.style_errors[key] = [BaseStyleSchema.error_messages["unknown"]] + for schema in schemas: + self.validate_schema(cleaner.path_from_root, schema, value_dict, False) + return toml_dict + def get_style_path(self, style_uri: str) -> Optional[Path]: """Get the style path from the URI. Add the .toml extension if it's missing.""" clean_style_uri = style_uri.strip() @@ -225,10 +271,9 @@ def merge_toml_dict(self) -> JsonDict: @staticmethod def file_field_pair(file_name: str, base_file_class: Type[NitpickPlugin]) -> Dict[str, fields.Field]: """Return a schema field with info from a config file class.""" - valid_toml_key = TOMLFormat.group_name_for(file_name) unique_file_name_with_underscore = slugify(file_name, separator="_") - kwargs = {"data_key": valid_toml_key} + kwargs = {"data_key": file_name} if base_file_class.validation_schema: field = fields.Nested(base_file_class.validation_schema, **kwargs) else: diff --git a/styles/black.toml b/styles/black.toml index 45f95b37..2f20ae46 100644 --- a/styles/black.toml +++ b/styles/black.toml @@ -1,7 +1,7 @@ ["pyproject.toml".tool.black] line-length = 120 -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/python/black rev: 20.8b1 @@ -18,7 +18,7 @@ yaml = """ # https://github.com/uiri/toml/issues/123 # https://github.com/uiri/toml/issues/230 # If they are fixed one day, remove this 'yaml' key and use only a 'repos' list with a single element: -#["pre-commit-config.yaml"] +#[".pre-commit-config.yaml"] #repos = [""" # #"""] diff --git a/styles/flake8.toml b/styles/flake8.toml index fe50ea32..cec581cc 100644 --- a/styles/flake8.toml +++ b/styles/flake8.toml @@ -10,7 +10,7 @@ exclude = ".tox,build" # Nitpick recommends those plugins as part of the style, but doesn't install them automatically as before. # This way, the developer has the choice of overriding this style, instead of having lots of plugins installed # without being asked. -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://gitlab.com/pycqa/flake8 rev: 3.8.4 diff --git a/styles/isort.toml b/styles/isort.toml index 118dee92..6b8d12c3 100644 --- a/styles/isort.toml +++ b/styles/isort.toml @@ -11,7 +11,7 @@ include_trailing_comma = true force_grid_wrap = 0 combine_as_imports = true -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/asottile/seed-isort-config rev: v2.2.0 diff --git a/styles/mypy.toml b/styles/mypy.toml index 2274cd8e..2e33d4e4 100644 --- a/styles/mypy.toml +++ b/styles/mypy.toml @@ -15,7 +15,7 @@ warn_no_return = true warn_redundant_casts = true warn_unused_ignores = true -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/pre-commit/mirrors-mypy rev: v0.790 diff --git a/styles/pre-commit/bash.toml b/styles/pre-commit/bash.toml index 608c3668..cec09472 100644 --- a/styles/pre-commit/bash.toml +++ b/styles/pre-commit/bash.toml @@ -1,4 +1,4 @@ -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/openstack/bashate rev: 2.0.0 diff --git a/styles/pre-commit/commitlint.toml b/styles/pre-commit/commitlint.toml index fa2bfcb2..a545e8a4 100644 --- a/styles/pre-commit/commitlint.toml +++ b/styles/pre-commit/commitlint.toml @@ -1,4 +1,4 @@ -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook rev: v3.0.0 diff --git a/styles/pre-commit/general.toml b/styles/pre-commit/general.toml index 37d9c5c9..22dcdbe0 100644 --- a/styles/pre-commit/general.toml +++ b/styles/pre-commit/general.toml @@ -1,4 +1,4 @@ -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.3.0 diff --git a/styles/pre-commit/python.toml b/styles/pre-commit/python.toml index 9c59162e..7b786eef 100644 --- a/styles/pre-commit/python.toml +++ b/styles/pre-commit/python.toml @@ -1,4 +1,4 @@ -[["pre-commit-config.yaml".repos]] +[[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.7.0 diff --git a/tests/conftest.py b/tests/conftest.py index 804b1bfb..04f40c68 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,7 +16,7 @@ # On macOS, use /private/ as the root instead of /, otherwise lots of tests will fail. _ROOT = "/private" + _ROOT -TEMP_ROOT_PATH = Path(_ROOT).expanduser().absolute() +TEMP_PATH = Path(_ROOT).expanduser().absolute() @pytest.fixture(scope="session", autouse=True) @@ -24,13 +24,13 @@ def delete_project_temp_root(): """Delete the temporary root before or after running the tests, depending on the env variable.""" if NITPICK_TEST_DIR: # If the environment variable is configured, delete its contents before the tests. - if TEMP_ROOT_PATH.exists(): - shutil.rmtree(str(TEMP_ROOT_PATH)) - TEMP_ROOT_PATH.mkdir() + if TEMP_PATH.exists(): + shutil.rmtree(str(TEMP_PATH)) + TEMP_PATH.mkdir() yield if not NITPICK_TEST_DIR: # If the environment variable is not configured, then a random temp dir will be used; # its contents should be deleted after the tests. - shutil.rmtree(str(TEMP_ROOT_PATH)) + shutil.rmtree(str(TEMP_PATH)) diff --git a/tests/helpers.py b/tests/helpers.py index 52f5e5b2..a469067f 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -16,7 +16,7 @@ from nitpick.plugins.pyproject_toml import PyProjectTomlPlugin from nitpick.plugins.setup_cfg import SetupCfgPlugin from nitpick.typedefs import PathOrStr -from tests.conftest import TEMP_ROOT_PATH +from tests.conftest import TEMP_PATH if TYPE_CHECKING: from nitpick.typedefs import Flake8Error # pylint: disable=ungrouped-imports @@ -42,7 +42,7 @@ def __init__(self, pytest_request: FixtureRequest, **kwargs) -> None: """Create the root dir and make it the current dir (needed by NitpickChecker).""" subdir = "/".join(pytest_request.module.__name__.split(".")[1:]) caller_function_name = pytest_request.node.name - self.root_dir = TEMP_ROOT_PATH / subdir / caller_function_name # type: Path + self.root_dir = TEMP_PATH / subdir / caller_function_name # type: Path # To make debugging of mock projects easy, each test should not reuse another test directory. self.root_dir.mkdir(parents=True) diff --git a/tests/test_json.py b/tests/test_json.py index 3664038e..84348ed1 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -161,7 +161,7 @@ def test_jsonfile_deprecated(request): """ ).save_file("my.json", '{"x":1}').flake8().assert_no_errors() - assert len(captured) == 2 # Twice, one for the original style file, one for the merged style + assert len(captured) == 1 assert issubclass(captured[-1].category, DeprecationWarning) assert "The [nitpick.JSONFile] section is not needed anymore; just declare your JSON files directly" in str( captured[-1].message diff --git a/tests/test_pre_commit.py b/tests/test_pre_commit.py index 83d1cc33..dd571b8c 100644 --- a/tests/test_pre_commit.py +++ b/tests/test_pre_commit.py @@ -1,6 +1,7 @@ """Pre-commit tests.""" from textwrap import dedent +import pytest from testfixtures import compare from nitpick.plugins.pre_commit import PreCommitHook @@ -19,7 +20,7 @@ def test_pre_commit_referenced_in_style(request): """Only check files if they have configured styles.""" ProjectMock(request).style( """ - ["pre-commit-config.yaml"] + [".pre-commit-config.yaml"] fail_fast = true """ ).pre_commit("").flake8().assert_single_error( @@ -64,7 +65,7 @@ def test_root_values_on_missing_file(request): """Test values on the root of the config file when it's missing.""" ProjectMock(request).style( """ - ["pre-commit-config.yaml"] + [".pre-commit-config.yaml"] bla_bla = "oh yeah" fail_fast = true whatever = "1" @@ -83,7 +84,7 @@ def test_root_values_on_existing_file(request): """Test values on the root of the config file when there is a file.""" ProjectMock(request).style( """ - ["pre-commit-config.yaml"] + [".pre-commit-config.yaml"] fail_fast = true blabla = "what" something = true @@ -116,7 +117,7 @@ def test_missing_repos(request): """Test missing repos on file.""" ProjectMock(request).style( """ - ["pre-commit-config.yaml"] + [".pre-commit-config.yaml"] fail_fast = true """ ).pre_commit( @@ -134,7 +135,7 @@ def test_missing_repo_key(request): """Test missing repo key on the style file.""" ProjectMock(request).style( """ - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] grepo = "glocal" """ ).pre_commit( @@ -152,7 +153,7 @@ def test_repo_does_not_exist(request): """Test repo does not exist on the pre-commit file.""" ProjectMock(request).style( """ - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] repo = "local" """ ).pre_commit( @@ -170,7 +171,7 @@ def test_missing_hooks_in_repo(request): """Test missing hooks in repo.""" ProjectMock(request).style( """ - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] repo = "whatever" """ ).pre_commit( @@ -187,7 +188,7 @@ def test_style_missing_hooks_in_repo(request): """Test style file is missing hooks in repo.""" ProjectMock(request).style( """ - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] repo = "another" """ ).pre_commit( @@ -206,7 +207,7 @@ def test_style_missing_id_in_hook(request): """Test style file is missing id in hook.""" ProjectMock(request).style( ''' - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] repo = "another" hooks = """ - name: isort @@ -233,7 +234,7 @@ def test_missing_hook_with_id(request): """Test missing hook with specific id.""" ProjectMock(request).style( ''' - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] repo = "other" hooks = """ - id: black @@ -329,7 +330,7 @@ def test_missing_different_values(request): ProjectMock(request).named_style( "root", ''' - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/user/repo rev: 1.2.3 @@ -427,3 +428,26 @@ def test_missing_different_values(request): """, 8, ) + + +def test_pre_commit_section_without_dot_deprecated(request): + """A pre-commit section without dot is deprecated.""" + project = ( + ProjectMock(request) + .style( + """ + ["pre-commit-config.yaml"] + fail_fast = true + """ + ) + .pre_commit("") + ) + + with pytest.deprecated_call() as warning_list: + project.flake8().assert_single_error("NIP331 File .pre-commit-config.yaml doesn't have the 'repos' root key") + + assert len(warning_list) == 1 + assert ( + str(warning_list[0].message) + == 'The section name for dotfiles should start with a dot: [".pre-commit-config.yaml"]' + ) diff --git a/tests/test_style.py b/tests/test_style.py index 7f1b3c88..756006f2 100644 --- a/tests/test_style.py +++ b/tests/test_style.py @@ -9,7 +9,7 @@ import responses from nitpick.constants import READ_THE_DOCS_URL, TOML_EXTENSION -from tests.conftest import TEMP_ROOT_PATH +from tests.conftest import TEMP_PATH from tests.helpers import ProjectMock, assert_conditions if TYPE_CHECKING: @@ -187,7 +187,7 @@ def test_minimum_version(mocked_version, offline, request): @pytest.mark.parametrize("offline", [False, True]) def test_relative_and_other_root_dirs(offline, request): """Test styles in relative and in other root dirs.""" - another_dir = TEMP_ROOT_PATH / "another_dir" # type: Path + another_dir = TEMP_PATH / "another_dir" # type: Path project = ( ProjectMock(request) .named_style( @@ -286,7 +286,7 @@ def test_relative_and_other_root_dirs(offline, request): @pytest.mark.parametrize("offline", [False, True]) def test_symlink_subdir(offline, request): """Test relative styles in subdirectories of a symlink dir.""" - target_dir = TEMP_ROOT_PATH / "target_dir" # type: Path + target_dir = TEMP_PATH / "target_dir" # type: Path ProjectMock(request).named_style( "{}/parent".format(target_dir), """ @@ -438,7 +438,7 @@ def test_fetch_private_github_urls(request): @pytest.mark.parametrize("offline", [False, True]) def test_merge_styles_into_single_file(offline, request): - """Merge all styles into a single TOML file on the cache dir. Also test merging lists (pre-commit's repos).""" + """Merge all styles into a single TOML file on the cache dir. Also test merging lists (pre-commit repos).""" ProjectMock(request).load_styles("black", "isort").named_style( "isort_overrides", """ @@ -472,7 +472,7 @@ def test_merge_styles_into_single_file(offline, request): combine_as_imports = true another_key = "some value" - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/python/black rev: 20.8b1 @@ -486,7 +486,7 @@ def test_merge_styles_into_single_file(offline, request): additional_dependencies: [black==20.8b1] """ - [["pre-commit-config.yaml".repos]] + [[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/asottile/seed-isort-config rev: v2.2.0