Skip to content

Commit

Permalink
feat: enforce settings on tox.ini (#309)
Browse files Browse the repository at this point in the history
* refactor: move some configs from setup.cfg to tox.ini
* build: fix version on .bumpversion.cfg
* style: enforce configs on tox.ini
* docs: add tox to the examples, check links after other commands
* test: tox.ini is applied with the default style
  • Loading branch information
andreoliwa authored Mar 9, 2021
1 parent 8cc5bf7 commit 44d6cf4
Show file tree
Hide file tree
Showing 21 changed files with 309 additions and 207 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.24.0
current_version = 0.24.1
commit = False
tag = False

Expand Down
38 changes: 38 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -412,3 +412,41 @@ Contents of `styles/python39.toml <https://github.com/andreoliwa/nitpick/blob/v0
["pyproject.toml".tool.poetry.dependencies]
python = "^3.9"
.. _example-tox:

tox_
----

Contents of `styles/tox.toml <https://github.com/andreoliwa/nitpick/blob/v0.24.1/styles/tox.toml>`_:

.. code-block:: toml
["tox.ini".tox]
# https://tox.readthedocs.io/en/latest/config.html
isolated_build = true
["tox.ini".testenv]
description = "Run tests with pytest and coverage"
extras = "test"
["tox.ini"."coverage:run"]
# https://coverage.readthedocs.io/en/latest/config.html#run
branch = true
parallel = true
source = "src/"
# TODO: deal with multiline INI values in https://github.com/andreoliwa/nitpick/issues/271
#omit = """tests/*
#.tox/*
#*/pypoetry/virtualenvs/*
#"""
# This config is needed by https://github.com/marketplace/actions/coveralls-python#usage
relative_files = true
["tox.ini"."coverage:report"]
# https://coverage.readthedocs.io/en/latest/config.html#report
show_missing = true
precision = 2
skip_covered = true
skip_empty = true
sort = "Cover"
1 change: 1 addition & 0 deletions docs/generate_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"python37.toml": "Python 3.7",
"python38.toml": "Python 3.8",
"python39.toml": "Python 3.9",
"tox.toml": "tox_",
}
)
CLI_MAPPING = [
Expand Down
2 changes: 1 addition & 1 deletion docs/ideas/ini.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ inline-quotes = "{{ nit.present(str, choices=['double', 'single']) }}"
skip__separators = ","
known_first_party__separators = ","

["setup.cfg"."tool:pytest"]
["tox.ini".pytest]
# https://github.com/andreoliwa/nitpick/issues/271
addopts__separators = " "
norecursedirs__separators = " "
Expand Down
1 change: 1 addition & 0 deletions docs/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Examples of ``.ini`` files handled by this plugin:

- `setup.cfg <https://docs.python.org/3/distutils/configfile.html>`_
- `.editorconfig <https://editorconfig.org/>`_
- `tox.ini <https://github.com/tox-dev/tox>`_

Style examples enforcing values on INI files: :ref:`flake8 configuration <example-flake8>`.

Expand Down
23 changes: 12 additions & 11 deletions docs/targets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@
.. _Bash: https://www.gnu.org/software/bash/
.. _black: https://github.com/psf/black
.. _commitlint: https://commitlint.js.org/
.. _Django: https://www.djangoproject.com
.. _Django: https://github.com/django/django
.. _EditorConfig: https://editorconfig.org
.. _flake8: https://gitlab.com/pycqa/flake8/
.. _flake8: https://gitlab.com/pycqa/flake8
.. _Flask CLI: https://flask.palletsprojects.com/en/1.1.x/cli/
.. _Invoke: https://github.com/pyinvoke/invoke
.. _IPython: https://ipython.org
.. _isort: https://github.com/PyCQA/isort/
.. _mypy: https://github.com/python/mypy/
.. _Nitpick: https://github.com/andreoliwa/nitpick/
.. _IPython: https://github.com/ipython/ipython
.. _isort: https://github.com/PyCQA/isort
.. _mypy: https://github.com/python/mypy
.. _Nitpick: https://github.com/andreoliwa/nitpick
.. _package.json: https://docs.npmjs.com/files/package.json
.. _Pipenv: https://github.com/pypa/pipenv/
.. _Pipenv: https://github.com/pypa/pipenv
.. _pipx: https://github.com/pipxproject/pipx
.. _Poetry: https://github.com/python-poetry/poetry/
.. _pre-commit: https://pre-commit.com/
.. _Pylint: https://www.pylint.org
.. _pytest: https://pytest.org/
.. _Poetry: https://github.com/python-poetry/poetry
.. _pre-commit: https://github.com/pre-commit/pre-commit
.. _Pylint: https://github.com/PyCQA/pylint
.. _pytest: https://github.com/pytest-dev/pytest
.. _TOML: https://github.com/toml-lang/toml
.. _tox: https://github.com/tox-dev/tox
1 change: 1 addition & 0 deletions nitpick-style.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ include = [
"styles/isort",
"styles/mypy",
"styles/pytest",
"styles/tox",
"styles/package-json",
"styles/editorconfig",
]
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
[
"@semantic-release/exec",
{
"prepareCmd": "bumpversion --allow-dirty --no-commit --no-tag --new-version ${nextRelease.version} patch && pre-commit run --all-files end-of-file-fixer || true && rm -rf dist/ && poetry build && twine upload --verbose --disable-progress-bar --skip-existing --password $TWINE_TEST_PASSWORD -r testpypi dist/*",
"prepareCmd": "bumpversion --allow-dirty --no-commit --no-tag --new-version ${nextRelease.version} patch && pre-commit run --all-files || true && rm -rf dist/ && poetry build && twine upload --verbose --disable-progress-bar --skip-existing --password $TWINE_TEST_PASSWORD -r testpypi dist/*",
"publishCmd": "twine upload --verbose --disable-progress-bar --skip-existing dist/*"
}
],
Expand All @@ -27,7 +27,7 @@
"@semantic-release/git",
{
"assets": [
"setup.cfg",
".bumpversion.cfg",
"src/nitpick/__init__.py",
"pyproject.toml",
"package.json",
Expand Down Expand Up @@ -55,9 +55,9 @@
"cli",
"flake8",
"style",
"pre-commit",
"pyproject.toml",
"setup.cfg",
"yaml",
"toml",
"ini",
"json",
"deps",
"deps-dev",
Expand Down
116 changes: 0 additions & 116 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,121 +27,5 @@ warn_no_return = True
warn_redundant_casts = True
warn_unused_ignores = True

[tool:pytest]
addopts = -v
norecursedirs = .* build dist CVS _darcs {arch} *.egg venv var docs
# https://docs.pytest.org/en/stable/reference.html#confval-testpaths
testpaths = src tests

[tox:tox]
# https://tox.readthedocs.io/en/latest/config.html
isolated_build = True
envlist = clean,lint,py39,py38,py37,py36,docs,report

[gh-actions]
# https://github.com/ymyzk/tox-gh-actions
python =
3.9: py39
3.8: py38, clean, lint, docs, report
3.7: py37
3.6: py36

[testenv]
description = Run tests with pytest and coverage
extras = test
depends =
{py39,py38,py37,py36}: clean
report: py39,py38,py37,py36
setenv =
PY_IGNORE_IMPORTMISMATCH = 1
commands =
python -m pip --version
# https://pytest-cov.readthedocs.io/en/latest/config.html#caveats
# https://docs.pytest.org/en/stable/skipping.html
python -m pytest --cov-config=setup.cfg --cov --cov-append --cov-report=term-missing --doctest-modules -s -rxXs {posargs:-vv}

[testenv:clean]
description = Erase data for the coverage report before running tests
platform = linux|darwin
skip_install = true
deps = coverage
commands = coverage erase

[testenv:lint]
description = Lint all files with pre-commit
basepython = python3.8
platform = linux|darwin
# pylint needs both these extras:
extras =
# Install pylint itself
lint
# For pylint to inspect tests
test
deps =
pip>=19.2
safety
# Run nitpick and pylint with tox, because local repos don't seem to work well with https://pre-commit.ci/
commands =
# Run Nitpick locally on itself
flake8 --select=NIP
pylint src/
safety check

[testenv:report]
description = Coverage report
platform = linux|darwin
skip_install = true
deps = coverage
commands =
coverage report
coverage html

[testenv:docs]
description = Build the HTML docs using Sphinx (sphinx-build, API docs, link checks)
basepython = python3.8
platform = linux|darwin
extras = doc
commands =
python3 docs/generate_rst.py
sphinx-apidoc --force --follow-links --module-first --separate --implicit-namespaces --ext-autodoc --ext-doctest --ext-intersphinx --ext-todo --ext-coverage --ext-imgmath --ext-mathjax --ext-ifconfig --ext-viewcode --ext-githubpages --output-dir docs/source src/nitpick/
# To stop failing when a page is unreachable, add a hyphen at the start of the line:
# https://tox.readthedocs.io/en/latest/example/basic.html#ignoring-exit-code
# Some errors during link check have to be ignored.
# E.g.: when a new TOML style is added, its link will be broken until a new release is published.
- sphinx-build --color -j auto -b linkcheck docs "{toxworkdir}/docs_out"
# Use these options to debug Sphinx: -nWT --keep-going -vvv
sphinx-build --color -j auto -d "{toxworkdir}/docs_doctree" -b html docs "{toxworkdir}/docs_out" {posargs}

[coverage:run]
# https://coverage.readthedocs.io/en/latest/config.html#run
branch = true
parallel = true
source = src/
omit =
tests/*
.tox/*
# This config is needed by https://github.com/marketplace/actions/coveralls-python#usage
relative_files = True

[coverage:report]
# https://coverage.readthedocs.io/en/latest/config.html#report
show_missing = true
precision = 2
skip_covered = true
skip_empty = true
sort = Cover

# https://coverage.readthedocs.io/en/latest/excluding.html#advanced-exclusion
exclude_lines =
pragma: no cover
def __repr__
if self.debug:
if settings.DEBUG
if TYPE_CHECKING:
raise AssertionError
raise NotImplementedError
if 0:
if __name__ == .__main__.:

[bandit]
exclude = tests/*
1 change: 1 addition & 0 deletions src/nitpick/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
MANAGE_PY = "manage.py"
PRE_COMMIT_CONFIG_YAML = ".pre-commit-config.yaml"
EDITOR_CONFIG = ".editorconfig"
TOX_INI = "tox.ini"

SINGLE_QUOTE = "'"
DOUBLE_QUOTE = '"'
Expand Down
7 changes: 4 additions & 3 deletions src/nitpick/plugins/ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class IniPlugin(NitpickPlugin):
- `setup.cfg <https://docs.python.org/3/distutils/configfile.html>`_
- `.editorconfig <https://editorconfig.org/>`_
- `tox.ini <https://github.com/tox-dev/tox>`_
Style examples enforcing values on INI files: :ref:`flake8 configuration <example-flake8>`.
"""
Expand Down Expand Up @@ -112,7 +113,7 @@ def remove_top_section(multiline_text: str) -> str:
return "\n".join(line for line in multiline_text.splitlines() if TOP_SECTION not in line)

def get_missing_output(self) -> str:
"""Get a missing output string example from the missing sections in setup.cfg."""
"""Get a missing output string example from the missing sections in an INI file."""
missing = self.missing_sections
if not missing:
return ""
Expand All @@ -130,7 +131,7 @@ def get_missing_output(self) -> str:

# TODO: convert the contents to dict (with IniConfig().sections?) and mimic other plugins doing dict diffs
def enforce_rules(self) -> Iterator[Fuss]:
"""Enforce rules on missing sections and missing key/value pairs in setup.cfg."""
"""Enforce rules on missing sections and missing key/value pairs in an INI file."""
try:
yield from self._read_file()
except Error:
Expand Down Expand Up @@ -218,7 +219,7 @@ def enforce_comma_separated_values(self, section, key, raw_actual: Any, raw_expe
def compare_different_keys(self, section, key, raw_actual: Any, raw_expected: Any) -> Iterator[Fuss]:
"""Compare different keys, with special treatment when they are lists or numeric."""
if isinstance(raw_actual, (int, float, bool)) or isinstance(raw_expected, (int, float, bool)):
# A boolean "True" or "true" has the same effect on setup.cfg.
# A boolean "True" or "true" has the same effect on ConfigParser files.
actual = str(raw_actual).lower()
expected = str(raw_expected).lower()
else:
Expand Down
6 changes: 3 additions & 3 deletions src/nitpick/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from sortedcontainers import SortedDict

from nitpick import fields
from nitpick.constants import READ_THE_DOCS_URL
from nitpick.constants import READ_THE_DOCS_URL, SETUP_CFG
from nitpick.generic import flatten


Expand Down Expand Up @@ -44,7 +44,7 @@ class NitpickStylesSectionSchema(BaseNitpickSchema):


class IniSchema(BaseNitpickSchema):
"""Validation schema for setup.cfg."""
"""Validation schema for INI files."""

error_messages = {"unknown": help_message("Unknown configuration", "nitpick_section.html#comma-separated-values")}

Expand All @@ -59,7 +59,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(IniSchema, data_key="setup.cfg")
setup_cfg = fields.Nested(IniSchema, data_key=SETUP_CFG)


class NitpickSectionSchema(BaseNitpickSchema):
Expand Down
4 changes: 2 additions & 2 deletions src/nitpick/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ def file_field_pair(filename: str, base_file_class: Type[NitpickPlugin]) -> Dict
if base_file_class.validation_schema:
field = fields.Nested(base_file_class.validation_schema, **kwargs)
else:
# For default files (pyproject.toml, setup.cfg...), there is no strict schema;
# For some files (e.g.: pyproject.toml, INI files), there is no strict schema;
# it can be anything they allow.
# It's out of Nitpick's scope to validate those files.
field = fields.Dict(fields.String, **kwargs)
Expand All @@ -321,7 +321,7 @@ def rebuild_dynamic_schema(self, data: JsonDict = None) -> None:
if data is None:
# Data is empty; so this is the first time the dynamic class is being rebuilt.
# Loop on classes with predetermined names, and add fields for them on the dynamic validation schema.
# E.g.: setup.cfg, pre-commit, pyproject.toml: files whose names we already know at this point.
# E.g.: pre-commit, pyproject.toml: files whose names we already know at this point.
for subclass in fixed_name_classes:
new_files_found.update(self.file_field_pair(subclass.filename, subclass))
else:
Expand Down
28 changes: 28 additions & 0 deletions styles/tox.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
["tox.ini".tox]
# https://tox.readthedocs.io/en/latest/config.html
isolated_build = true

["tox.ini".testenv]
description = "Run tests with pytest and coverage"
extras = "test"

["tox.ini"."coverage:run"]
# https://coverage.readthedocs.io/en/latest/config.html#run
branch = true
parallel = true
source = "src/"
# TODO: deal with multiline INI values in https://github.com/andreoliwa/nitpick/issues/271
#omit = """tests/*
#.tox/*
#*/pypoetry/virtualenvs/*
#"""
# This config is needed by https://github.com/marketplace/actions/coveralls-python#usage
relative_files = true

["tox.ini"."coverage:report"]
# https://coverage.readthedocs.io/en/latest/config.html#report
show_missing = true
precision = 2
skip_covered = true
skip_empty = true
sort = "Cover"
Loading

0 comments on commit 44d6cf4

Please sign in to comment.