Skip to content

Commit

Permalink
Merge f2ecb99 into 3c82e8c
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoliwa committed Dec 26, 2021
2 parents 3c82e8c + f2ecb99 commit 2356700
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 27 deletions.
5 changes: 3 additions & 2 deletions docs/cli.rst
Expand Up @@ -49,7 +49,7 @@ Main options
Commands:
check Don't modify files, just print the differences.
fix Fix files, modifying them directly.
init Create a configuration file if it doesn't exist already.
init Create a [tool.nitpick] section in the configuration file if it...
ls List of files configured in the Nitpick style.
.. _cli_cmd_fix:
Expand Down Expand Up @@ -123,7 +123,8 @@ At the end of execution, this command displays:
Usage: nitpick init [OPTIONS]
Create a configuration file if it doesn't exist already.
Create a [tool.nitpick] section in the configuration file if it doesn't
exist already.
Options:
--help Show this message and exit.
14 changes: 8 additions & 6 deletions src/nitpick/cli.py
Expand Up @@ -21,10 +21,11 @@
from click.exceptions import Exit
from loguru import logger

from nitpick.constants import DOT_NITPICK_TOML, PROJECT_NAME
from nitpick.constants import PROJECT_NAME, TOOL_KEY, TOOL_NITPICK_KEY
from nitpick.core import Nitpick
from nitpick.enums import OptionEnum
from nitpick.exceptions import QuitComplainingError
from nitpick.formats import TOMLFormat
from nitpick.generic import relative_to_current_dir
from nitpick.violations import Reporter

Expand Down Expand Up @@ -142,12 +143,13 @@ def ls(context, files): # pylint: disable=invalid-name
@nitpick_cli.command()
@click.pass_context
def init(context):
"""Create a configuration file if it doesn't exist already."""
"""Create a [tool.nitpick] section in the configuration file if it doesn't exist already."""
nit = get_nitpick(context)
config = nit.project.read_configuration()
if config.file:
click.secho(f"A config file already exists: {config.file.name}", fg="yellow")

if config.file and PROJECT_NAME in TOMLFormat(path=config.file).as_data[TOOL_KEY]:
click.secho(f"The config file {config.file.name} already has a [{TOOL_NITPICK_KEY}] section.", fg="yellow")
raise Exit(1)

nit.project.create_configuration()
click.secho(f"Config file created: {DOT_NITPICK_TOML}", fg="green")
nit.project.create_configuration(config)
click.secho(f"A [{TOOL_NITPICK_KEY}] section was created in the config file: {config.file.name}", fg="green")
5 changes: 3 additions & 2 deletions src/nitpick/constants.py
Expand Up @@ -63,10 +63,11 @@
SEPARATOR_QUOTED_SPLIT = "#$@"

# Config sections and keys
TOOL_NITPICK = "tool.nitpick"
TOOL_KEY = "tool"
TOOL_NITPICK_KEY = f"{TOOL_KEY}.{PROJECT_NAME}"

# JMESPath expressions
TOOL_NITPICK_JMEX = jmespath.compile(TOOL_NITPICK)
TOOL_NITPICK_JMEX = jmespath.compile(TOOL_NITPICK_KEY)
NITPICK_STYLES_INCLUDE_JMEX = jmespath.compile("nitpick.styles.include")
NITPICK_MINIMUM_VERSION_JMEX = jmespath.compile("nitpick.minimum_version")

Expand Down
3 changes: 3 additions & 0 deletions src/nitpick/formats.py
Expand Up @@ -8,6 +8,7 @@

import dictdiffer
import toml
from autorepr import autorepr
from loguru import logger
from ruamel.yaml import YAML, RoundTripRepresenter
from ruamel.yaml.comments import CommentedMap, CommentedSeq
Expand Down Expand Up @@ -95,6 +96,8 @@ class BaseFormat(metaclass=abc.ABCMeta):
:param ignore_keys: List of keys to ignore when using the comparison methods.
"""

__repr__ = autorepr(["path"])

def __init__(
self,
*,
Expand Down
28 changes: 18 additions & 10 deletions src/nitpick/project.py
Expand Up @@ -12,8 +12,9 @@
from more_itertools import peekable
from more_itertools.more import always_iterable
from pluggy import PluginManager
from tomlkit import comment, document, dumps, table
from tomlkit import comment, document, dumps, parse, table
from tomlkit.items import Key, KeyType
from tomlkit.toml_document import TOMLDocument

from nitpick import fields, plugins
from nitpick.constants import (
Expand All @@ -26,8 +27,8 @@
READ_THE_DOCS_URL,
ROOT_FILES,
ROOT_PYTHON_FILES,
TOOL_NITPICK,
TOOL_NITPICK_JMEX,
TOOL_NITPICK_KEY,
)
from nitpick.exceptions import QuitComplainingError
from nitpick.formats import TOMLFormat
Expand Down Expand Up @@ -160,7 +161,7 @@ def read_configuration(self) -> Configuration:
Reporter(FileInfo(self, PYPROJECT_TOML)).make_fuss(
StyleViolations.INVALID_DATA_TOOL_NITPICK,
flatten_marshmallow_errors(validation_errors),
section=TOOL_NITPICK,
section=TOOL_NITPICK_KEY,
)
)

Expand Down Expand Up @@ -193,14 +194,21 @@ def merge_styles(self, offline: bool) -> Iterator[Fuss]:
self.nitpick_section = self.style_dict.get("nitpick", {})
self.nitpick_files_section = self.nitpick_section.get("files", {})

def create_configuration(self) -> None:
def create_configuration(self, config: Configuration) -> None:
"""Create a configuration file."""
from nitpick.style import Style # pylint: disable=import-outside-toplevel

doc = document()
doc.add(comment("This file was generated by the `nitpick init` command"))
doc.add(comment(f"More info at {READ_THE_DOCS_URL}configuration.html"))
doc.add(Key(TOOL_NITPICK, KeyType.Bare), table().add("style", [Style.get_default_style_url()]))
if config.file:
doc: TOMLDocument = parse(config.file.read_text())
else:
doc = document()
config.file = self.root / DOT_NITPICK_TOML

path: Path = self.root / DOT_NITPICK_TOML
path.write_text(dumps(doc, sort_keys=True))
tool_nitpick = table()
tool_nitpick.add(comment("Generated by the 'nitpick init' command"))
tool_nitpick.add(comment(f"More info at {READ_THE_DOCS_URL}configuration.html"))
tool_nitpick.add("style", [Style.get_default_style_url()])
doc.add(Key(TOOL_NITPICK_KEY, KeyType.Bare), tool_nitpick)

# config.file will always have a value at this point, but mypy can't see it.
config.file.write_text(dumps(doc, sort_keys=True)) # type: ignore
50 changes: 43 additions & 7 deletions tests/test_cli.py
Expand Up @@ -2,7 +2,7 @@
import pytest
import responses

from nitpick.constants import DOT_NITPICK_TOML, PYPROJECT_TOML, READ_THE_DOCS_URL, TOOL_NITPICK
from nitpick.constants import DOT_NITPICK_TOML, PYPROJECT_TOML, READ_THE_DOCS_URL, TOOL_NITPICK_KEY
from nitpick.style import Style
from nitpick.style.fetchers.github import GitHubProtocol
from tests.helpers import XFAIL_ON_WINDOWS, ProjectMock
Expand Down Expand Up @@ -37,10 +37,16 @@ def test_simple_error(tmp_path):


@pytest.mark.parametrize("config_file", [DOT_NITPICK_TOML, PYPROJECT_TOML])
def test_config_file_already_exists(tmp_path, config_file):
def test_config_file_already_has_tool_nitpick_section(tmp_path, config_file):
"""Test if both config files already exist."""
project = ProjectMock(tmp_path, pyproject_toml=False, setup_py=True).save_file(config_file, "")
project.cli_init(f"A config file already exists: {config_file}", exit_code=1)
project = ProjectMock(tmp_path, pyproject_toml=False, setup_py=True).save_file(
config_file,
f"""
[{TOOL_NITPICK_KEY}]
style = ['/this/should/not/be/validated-yet.toml']
""",
)
project.cli_init(f"The config file {config_file} already has a [{TOOL_NITPICK_KEY}] section.", exit_code=1)


@responses.activate
Expand All @@ -50,13 +56,43 @@ def test_create_basic_dot_nitpick_toml(tmp_path):

project = ProjectMock(tmp_path, pyproject_toml=False, setup_py=True)
url = Style.get_default_style_url()
project.cli_init(f"Config file created: {DOT_NITPICK_TOML}").assert_file_contents(
project.cli_init(
f"A [{TOOL_NITPICK_KEY}] section was created in the config file: {DOT_NITPICK_TOML}"
).assert_file_contents(
DOT_NITPICK_TOML,
f"""
# This file was generated by the `nitpick init` command
[{TOOL_NITPICK_KEY}]
# Generated by the 'nitpick init' command
# More info at {READ_THE_DOCS_URL}configuration.html
style = ["{url}"]
""",
)
assert url.startswith(GitHubProtocol.LONG.value)


@responses.activate
def test_add_tool_nitpick_section_to_pyproject_toml(tmp_path):
"""Add a [tool.nitpick] section to pyproject.toml."""
responses.add(responses.GET, "https://api.github.com/repos/andreoliwa/nitpick", '{"default_branch": "develop"}')

project = ProjectMock(tmp_path).pyproject_toml(
"""
[tool.black]
line-length = 120
"""
)
url = Style.get_default_style_url()
project.cli_init(
f"A [{TOOL_NITPICK_KEY}] section was created in the config file: {PYPROJECT_TOML}"
).assert_file_contents(
PYPROJECT_TOML,
f"""
[tool.black]
line-length = 120
[{TOOL_NITPICK}]
[{TOOL_NITPICK_KEY}]
# Generated by the 'nitpick init' command
# More info at {READ_THE_DOCS_URL}configuration.html
style = ["{url}"]
""",
)
Expand Down

0 comments on commit 2356700

Please sign in to comment.