Skip to content

Commit

Permalink
fix: override a remote style with "./your-local-style.toml" (#295)
Browse files Browse the repository at this point in the history
* test_local_style_should_override_settings() is failing on Windows
  • Loading branch information
andreoliwa committed Feb 23, 2021
1 parent ded80db commit fe5f085
Show file tree
Hide file tree
Showing 27 changed files with 231 additions and 140 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,6 @@ For merging, you should:
3. Add yourself to ``AUTHORS.rst``.

.. [1] If you don't have all the necessary python versions available locally you can rely on Travis - it will
`run the tests <https://travis-ci.com/andreoliwa/nitpick/pull_requests>`_ for each change you add in the pull request.
`run the tests <https://github.com/andreoliwa/nitpick/actions/workflows/python.yaml>`_ for each change you add in the pull request.
It will be slower though ...
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ update-poetry: # Update Poetry dependencies
poetry update
.PHONY: update-poetry

lint .cache/make/lint: .github/*/* .travis/* docs/*.py src/*/* styles/*/* tests/*/* nitpick-style.toml .cache/make/long-poetry # Lint the project (tox running pre-commit, flake8)
lint .cache/make/lint: .github/*/* docs/*.py src/*/* styles/*/* tests/*/* nitpick-style.toml .cache/make/long-poetry # Lint the project (tox running pre-commit, flake8)
tox -e lint
touch .cache/make/lint
.PHONY: lint
Expand Down
2 changes: 1 addition & 1 deletion docs/defaults.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Content of `styles/absent-files.toml <https://raw.githubusercontent.com/andreoli
"Pipfile" = "Use pyproject.toml instead"
"Pipfile.lock" = "Use pyproject.toml instead"
".venv" = ""
".pyup.yml" = "Configure .travis.yml with safety instead: https://github.com/pyupio/safety#using-safety-with-a-ci-service"
".pyup.yml" = "Configure safety instead: https://github.com/pyupio/safety#using-safety-with-a-ci-service"
.. _default-black:

Expand Down
4 changes: 1 addition & 3 deletions docs/generate_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ def generate_defaults(filename: str):

if missing:
click.secho(
"ERROR: Add missing style files to the 'style_mapping' var in '{}', as file/header pairs. Example:".format(
__file__
),
f"ERROR: Add missing style files to the 'style_mapping' var in '{__file__}', as file/header pairs. Example:",
fg="red",
)
pprint(missing)
Expand Down
6 changes: 3 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Nitpick
.. image:: https://img.shields.io/pypi/v/nitpick.svg
:target: https://pypi.org/project/nitpick/
:alt: PyPI
.. image:: https://api.travis-ci.com/andreoliwa/nitpick.svg
:target: https://travis-ci.com/andreoliwa/nitpick
:alt: Travis CI
.. image:: https://github.com/andreoliwa/nitpick/actions/workflows/python.yaml/badge.svg
:target: https://github.com/andreoliwa/nitpick/actions/workflows/python.yaml
:alt: GitHub Workflow
.. image:: https://readthedocs.org/projects/nitpick/badge/?version=latest
:target: https://nitpick.rtfd.io/en/latest/?badge=latest
:alt: Documentation Status
Expand Down
7 changes: 7 additions & 0 deletions docs/source/nitpick.enums.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
nitpick.enums module
====================

.. automodule:: nitpick.enums
:members:
:undoc-members:
:show-inheritance:
1 change: 1 addition & 0 deletions docs/source/nitpick.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Submodules
nitpick.cli
nitpick.constants
nitpick.core
nitpick.enums
nitpick.exceptions
nitpick.fields
nitpick.flake8
Expand Down
47 changes: 44 additions & 3 deletions docs/tool_nitpick_section.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,27 @@ You can configure your own style like this:
[tool.nitpick]
style = "/path/to/your-style-file.toml"
You can set ``style`` with any local file or URL. E.g.: you can use the raw URL of a `GitHub Gist <https://gist.github.com>`_.
You can set ``style`` with any local file or URL.

Remote style
------------

Use the URL of the remote file. If it's hosted on GitHub, use the raw GitHub URL:

.. code-block:: toml
[tool.nitpick]
style = "https://raw.githubusercontent.com/andreoliwa/nitpick/v0.23.1/nitpick-style.toml"
You can also use the raw URL of a `GitHub Gist <https://gist.github.com>`_:

.. code-block:: toml
[tool.nitpick]
style = "https://gist.githubusercontent.com/andreoliwa/f4fccf4e3e83a3228e8422c01a48be61/raw/ff3447bddfc5a8665538ddf9c250734e7a38eabb/remote-style.toml"
Local style
-----------

Using a file in your home directory:

Expand All @@ -21,6 +41,9 @@ Using a file in your home directory:
[tool.nitpick]
style = "~/some/path/to/another-style.toml"
Multiple styles
---------------

You can also use multiple styles and mix local files and URLs:

.. code-block:: toml
Expand All @@ -32,5 +55,23 @@ You can also use multiple styles and mix local files and URLs:
"https://example.com/on/the/web/third.toml"
]
The order is important: each style will override any keys that might be set by the previous ``.toml`` file.
If a key is defined in more than one file, the value from the last file will prevail.
.. note::

The order is important: each style will override any keys that might be set by the previous ``.toml`` file.

If a key is defined in more than one file, the value from the last file will prevail.

Override a remote style
-----------------------

You can use a remote style as a starting point, and override settings on your local style file.

Use ``./`` to indicate the local style:

.. code-block:: toml
[tool.nitpick]
style = [
"https://example.com/on/the/web/remote-style.toml",
"./my-local-style.toml",
]
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"docs/conf.py",
"docs/targets.rst",
"docs/quickstart.rst",
"docs/tool_nitpick_section.rst",
"nitpick-style.toml",
"README.md",
"CHANGELOG.md"
Expand Down
5 changes: 4 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ replace = {new_version}
search = {current_version}
replace = {new_version}

[bumpversion:file:docs/tool_nitpick_section.rst]
search = {current_version}
replace = {new_version}

[bumpversion:file:nitpick-style.toml]
search = {current_version}
replace = {new_version}
Expand Down Expand Up @@ -151,7 +155,6 @@ parallel = true
omit =
tests/*
.tox/*
/home/travis/virtualenv/*
; This config is needed by https://github.com/marketplace/actions/coveralls-python#usage
relative_files = True

Expand Down
32 changes: 3 additions & 29 deletions src/nitpick/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration
"""
import os
from enum import Enum
from pathlib import Path
from typing import Optional

Expand All @@ -23,35 +21,11 @@

from nitpick.constants import PROJECT_NAME
from nitpick.core import Nitpick
from nitpick.enums import OptionEnum
from nitpick.generic import relative_to_current_dir
from nitpick.violations import Reporter


class _FlagMixin:
"""Private mixin used to test the flags."""

name: str

def as_flake8_flag(self) -> str:
"""Format the name of a flag to be used on the CLI."""
slug = self.name.lower().replace("_", "-")
return f"--{PROJECT_NAME}-{slug}"

def as_envvar(self) -> str:
"""Format the name of an environment variable."""
return f"{PROJECT_NAME.upper()}_{self.name.upper()}"

def get_environ(self) -> str:
"""Get the value of an environment variable."""
return os.environ.get(self.as_envvar(), "")


class NitpickFlag(_FlagMixin, Enum):
"""Flags to be used with the CLI."""

OFFLINE = "Offline mode: no style will be downloaded (no HTTP requests at all)"


@click.group()
@click.option(
"--project",
Expand All @@ -60,10 +34,10 @@ class NitpickFlag(_FlagMixin, Enum):
help="Path to project root",
)
@click.option(
f"--{NitpickFlag.OFFLINE.name.lower()}", # pylint: disable=no-member
f"--{OptionEnum.OFFLINE.name.lower()}", # pylint: disable=no-member
is_flag=True,
default=False,
help=NitpickFlag.OFFLINE.value,
help=OptionEnum.OFFLINE.value,
)
def nitpick_cli(project: Path = None, offline=False): # pylint: disable=unused-argument
"""Enforce the same configuration across multiple projects."""
Expand Down
12 changes: 9 additions & 3 deletions src/nitpick/constants.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Constants."""
import os

import jmespath

PROJECT_NAME = "nitpick"
FLAKE8_PREFIX = "NIP"
CACHE_DIR_NAME = ".cache"
TOML_EXTENSION = ".toml"
NITPICK_STYLE_TOML = "nitpick-style{}".format(TOML_EXTENSION)
MERGED_STYLE_TOML = "merged-style{}".format(TOML_EXTENSION)
RAW_GITHUB_CONTENT_BASE_URL = "https://raw.githubusercontent.com/andreoliwa/{}".format(PROJECT_NAME)
NITPICK_STYLE_TOML = f"nitpick-style{TOML_EXTENSION}"
MERGED_STYLE_TOML = f"merged-style{TOML_EXTENSION}"
RAW_GITHUB_CONTENT_BASE_URL = f"https://raw.githubusercontent.com/andreoliwa/{PROJECT_NAME}"
READ_THE_DOCS_URL = "https://nitpick.rtfd.io/en/latest/"

# Special files
Expand Down Expand Up @@ -35,3 +37,7 @@
TOOL_NITPICK_JMEX = jmespath.compile(TOOL_NITPICK)
NITPICK_STYLES_INCLUDE_JMEX = jmespath.compile("nitpick.styles.include")
NITPICK_MINIMUM_VERSION_JMEX = jmespath.compile("nitpick.minimum_version")

#: Dot/slash is used to indicate a local style file
SLASH = os.path.sep
DOT_SLASH = f".{SLASH}"
30 changes: 30 additions & 0 deletions src/nitpick/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Enums."""
import os
from enum import Enum

from nitpick import PROJECT_NAME


class _OptionMixin:
"""Private mixin used to test the CLI options."""

name: str

def as_flake8_flag(self) -> str:
"""Format the name of a flag to be used on the CLI."""
slug = self.name.lower().replace("_", "-")
return f"--{PROJECT_NAME}-{slug}"

def as_envvar(self) -> str:
"""Format the name of an environment variable."""
return f"{PROJECT_NAME.upper()}_{self.name.upper()}"

def get_environ(self) -> str:
"""Get the value of an environment variable."""
return os.environ.get(self.as_envvar(), "")


class OptionEnum(_OptionMixin, Enum):
"""Options to be used with the CLI."""

OFFLINE = "Offline mode: no style will be downloaded (no HTTP requests at all)"
3 changes: 1 addition & 2 deletions src/nitpick/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ def pre_commit_without_dash(path_from_root: str) -> bool:

if path_from_root == PreCommitPlugin.filename[1:]:
warnings.warn(
'The section name for dotfiles should start with a dot: [".{}"]'.format(path_from_root),
DeprecationWarning,
f'The section name for dotfiles should start with a dot: [".{path_from_root}"]', DeprecationWarning
)
return True

Expand Down
8 changes: 4 additions & 4 deletions src/nitpick/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ def validate_section_dot_field(section_field: str) -> bool:
"""Validate if the combination section/field has a dot separating them."""
common = "Use <section_name>.<field_name>"
if "." not in section_field:
raise ValidationError("Dot is missing. {}".format(common))
raise ValidationError(f"Dot is missing. {common}")
parts = section_field.split(".")
if len(parts) > 2:
raise ValidationError("There's more than one dot. {}".format(common))
raise ValidationError(f"There's more than one dot. {common}")
if not parts[0].strip():
raise ValidationError("Empty section name. {}".format(common))
raise ValidationError(f"Empty section name. {common}")
if not parts[1].strip():
raise ValidationError("Empty field name. {}".format(common))
raise ValidationError(f"Empty field name. {common}")
return True


Expand Down
6 changes: 3 additions & 3 deletions src/nitpick/flake8.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
from loguru import logger

from nitpick import __version__
from nitpick.cli import NitpickFlag
from nitpick.constants import FLAKE8_PREFIX, PROJECT_NAME
from nitpick.core import Nitpick
from nitpick.enums import OptionEnum
from nitpick.exceptions import QuitComplainingError
from nitpick.typedefs import Flake8Error
from nitpick.violations import Fuss
Expand Down Expand Up @@ -64,7 +64,7 @@ def collect_errors(self) -> Iterator[Fuss]:
def add_options(option_manager: OptionManager):
"""Add the offline option."""
option_manager.add_option(
NitpickFlag.OFFLINE.as_flake8_flag(), action="store_true", help=NitpickFlag.OFFLINE.value
OptionEnum.OFFLINE.as_flake8_flag(), action="store_true", help=OptionEnum.OFFLINE.value
)

@staticmethod
Expand All @@ -76,5 +76,5 @@ def parse_options(option_manager: OptionManager, options, args): # pylint: disa
log_mapping = {1: logging.INFO, 2: logging.DEBUG}
logging.basicConfig(level=log_mapping.get(options.verbose, logging.WARNING))

nit = Nitpick.singleton().init(offline=bool(options.nitpick_offline or NitpickFlag.OFFLINE.get_environ()))
nit = Nitpick.singleton().init(offline=bool(options.nitpick_offline or OptionEnum.OFFLINE.get_environ()))
logger.info("Offline mode: {}", nit.offline)
4 changes: 2 additions & 2 deletions src/nitpick/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def flatten(dict_, parent_key="", separator=".", current_lists=None) -> JsonDict

items = [] # type: List[Tuple[str, Any]]
for key, value in dict_.items():
quoted_key = "{quote}{key}{quote}".format(quote=DOUBLE_QUOTE, key=key) if separator in str(key) else key
quoted_key = f"{DOUBLE_QUOTE}{key}{DOUBLE_QUOTE}" if separator in str(key) else key
new_key = str(parent_key) + separator + str(quoted_key) if parent_key else quoted_key
if isinstance(value, dict):
items.extend(flatten(value, new_key, separator, current_lists).items())
Expand Down Expand Up @@ -83,7 +83,7 @@ def quoted_split(string_: str, separator=".") -> List[str]:
return string_.split(separator)

quoted_regex = re.compile(
"([{single}{double}][^{single}{double}]+[{single}{double}])".format(single=SINGLE_QUOTE, double=DOUBLE_QUOTE)
f"([{SINGLE_QUOTE}{DOUBLE_QUOTE}][^{SINGLE_QUOTE}{DOUBLE_QUOTE}]+[{SINGLE_QUOTE}{DOUBLE_QUOTE}])"
)

def remove_quotes(match):
Expand Down
10 changes: 5 additions & 5 deletions src/nitpick/plugins/pre_commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class PreCommitHook:
@property
def unique_key(self) -> str:
"""Unique key of this hook, to be used in a dict."""
return "{}_{}".format(self.repo, self.hook_id)
return f"{self.repo}_{self.hook_id}"

@property
def key_value_pair(self) -> Tuple[str, "PreCommitHook"]:
Expand All @@ -52,7 +52,7 @@ def get_all_hooks_from(cls, str_or_yaml: Union[str, YamlData]):
for index, hook in enumerate(repo.get(KEY_HOOKS, [])):
repo_data_only = repo.copy()
repo_data_only.pop(KEY_HOOKS)
hook_data_only = search_dict("{}[{}]".format(KEY_HOOKS, index), repo, {})
hook_data_only = search_dict(f"{KEY_HOOKS}[{index}]", repo, {})
repo_data_only.update({KEY_HOOKS: [hook_data_only]})
hooks.append(
PreCommitHook(repo.get(KEY_REPO), hook[KEY_ID], YAMLFormat(data=[repo_data_only])).key_value_pair
Expand Down Expand Up @@ -154,7 +154,7 @@ def enforce_repo_block(self, expected_repo_block: OrderedDict) -> Iterator[Fuss]

# Display the current revision of the hook
current_revision = comparison.flat_actual.get("rev", None)
revision_message = " (rev: {})".format(current_revision) if current_revision else ""
revision_message = f" (rev: {current_revision})" if current_revision else ""
yield from self.warn_missing_different(comparison, f": hook {hook.hook_id!r}{revision_message}")

def enforce_repo_old_format(self, index: int, repo_data: OrderedDict) -> Iterator[Fuss]:
Expand Down Expand Up @@ -202,9 +202,9 @@ def format_hook(expected_dict) -> str:
output: List[str] = []
for line in lines.split("\n"):
if line.startswith("id:"):
output.insert(0, " - {}".format(line))
output.insert(0, f" - {line}")
else:
output.append(" {}".format(line))
output.append(f" {line}")
return "\n".join(output)


Expand Down
2 changes: 1 addition & 1 deletion src/nitpick/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def find_main_python_file(self) -> Path: # TODO: add unit tests
# 1.
[self.root / root_file for root_file in ROOT_PYTHON_FILES],
# 2.
self.root.glob("*/{}".format(MANAGE_PY)),
self.root.glob(f"*/{MANAGE_PY}"),
# 3.
self.root.glob("*.py"),
self.root.glob("*/*.py"),
Expand Down
Loading

0 comments on commit fe5f085

Please sign in to comment.