diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index b52bc6c0..9a5c3669 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -20,6 +20,8 @@ Nitpick_ could always use more documentation, whether as part of the official docs, in docstrings, or even on the web in blog posts, articles, and such. +.. _development: + Development =========== diff --git a/docs/cli.rst b/docs/cli.rst index 85c75c72..766ddf4d 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -13,7 +13,7 @@ Nitpick_ has a CLI to apply changes to files automatically. 1. It doesn't work for all the plugins yet. Currently, it works for: - - :ref:`setupcfgplugin` + - :ref:`iniplugin` - :ref:`pyprojecttomlplugin` 2. It tries to preserve the comments and the formatting of the original file. @@ -31,7 +31,7 @@ Main options ------------ -.. code-block:: shell +.. code-block:: Usage: nitpick [OPTIONS] COMMAND [ARGS]... @@ -57,7 +57,7 @@ At the end of execution, this command displays: - the number of violations that have to be changed manually. -.. code-block:: shell +.. code-block:: Usage: nitpick run [OPTIONS] [FILES]... @@ -77,7 +77,7 @@ At the end of execution, this command displays: ----------------------------- -.. code-block:: shell +.. code-block:: Usage: nitpick ls [OPTIONS] [FILES]... diff --git a/docs/conf.py b/docs/conf.py index 4643a0b5..f6b3992d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -224,9 +224,10 @@ # http://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html # Example configuration for intersphinx: refer to the Python standard library. +# The inventory should be present for each of these URLs in the "objects.inv" file intersphinx_mapping = { "python": ("https://docs.python.org/3", None), - "marshmallow": ("https://marshmallow.readthedocs.io/en/stable", None), + "marshmallow": ("https://marshmallow.readthedocs.io/en/latest", None), "ruamel.yaml": ("https://yaml.readthedocs.io/en/latest", None), "jmespath": ("https://jmespath.readthedocs.io/en/latest", None), } diff --git a/docs/defaults.rst b/docs/defaults.rst index 348a7458..82ea8fc4 100644 --- a/docs/defaults.rst +++ b/docs/defaults.rst @@ -16,7 +16,7 @@ All TOML_ configs below are taken from the `default style file`_. Absent files ------------ -Content of `styles/absent-files.toml `_: +Contents of `styles/absent-files.toml `_: .. code-block:: toml @@ -33,7 +33,7 @@ Content of `styles/absent-files.toml `_: +Contents of `styles/black.toml `_: .. code-block:: toml @@ -67,7 +67,7 @@ Content of `styles/black.toml `_: +Contents of `styles/flake8.toml `_: .. code-block:: toml @@ -111,7 +111,7 @@ Content of `styles/flake8.toml `_: +Contents of `styles/ipython.toml `_: .. code-block:: toml @@ -124,7 +124,7 @@ Content of `styles/ipython.toml `_: +Contents of `styles/isort.toml `_: .. code-block:: toml @@ -154,7 +154,7 @@ Content of `styles/isort.toml `_: +Contents of `styles/mypy.toml `_: .. code-block:: toml @@ -188,7 +188,7 @@ Content of `styles/mypy.toml `_: +Contents of `styles/package-json.toml `_: .. code-block:: toml @@ -209,7 +209,7 @@ Content of `styles/package-json.toml `_: +Contents of `styles/poetry.toml `_: .. code-block:: toml @@ -221,7 +221,7 @@ Content of `styles/poetry.toml `_: +Contents of `styles/pre-commit/bash.toml `_: .. code-block:: toml @@ -238,7 +238,7 @@ Content of `styles/pre-commit/bash.toml `_: +Contents of `styles/pre-commit/commitlint.toml `_: .. code-block:: toml @@ -257,7 +257,7 @@ Content of `styles/pre-commit/commitlint.toml `_: +Contents of `styles/pre-commit/general.toml `_: .. code-block:: toml @@ -280,7 +280,7 @@ Content of `styles/pre-commit/general.toml `_: +Contents of `styles/pre-commit/main.toml `_: .. code-block:: toml @@ -295,14 +295,14 @@ Content of `styles/pre-commit/main.toml `_: +Contents of `styles/pre-commit/python.toml `_: .. code-block:: toml [[".pre-commit-config.yaml".repos]] yaml = """ - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.7.1 + rev: v1.8.0 hooks: - id: python-check-blanket-noqa - id: python-check-mock-methods @@ -316,7 +316,7 @@ Content of `styles/pre-commit/python.toml `_: +Contents of `styles/pylint.toml `_: .. code-block:: toml @@ -328,7 +328,7 @@ Content of `styles/pylint.toml `_: +Contents of `styles/python36.toml `_: .. code-block:: toml @@ -340,7 +340,7 @@ Content of `styles/python36.toml `_: +Contents of `styles/python37.toml `_: .. code-block:: toml @@ -352,7 +352,7 @@ Content of `styles/python37.toml `_: +Contents of `styles/python38.toml `_: .. code-block:: toml @@ -364,7 +364,7 @@ Content of `styles/python38.toml `_: +Contents of `styles/python39.toml `_: .. code-block:: toml diff --git a/docs/generate_rst.py b/docs/generate_rst.py index 18b1a2f2..f91cc710 100644 --- a/docs/generate_rst.py +++ b/docs/generate_rst.py @@ -84,7 +84,7 @@ def generate_defaults(filename: str): {header} {dashes} - Content of `{toml_file} <{base_url}/develop/{toml_file}>`_: + Contents of `{toml_file} <{base_url}/develop/{toml_file}>`_: .. code-block:: toml @@ -173,7 +173,7 @@ def generate_cli(filename: str) -> None: {dashes} {long} - .. code-block:: shell + .. code-block:: {help} """ diff --git a/docs/ideas/ini.toml b/docs/ideas/ini.toml new file mode 100644 index 00000000..f8acfd18 --- /dev/null +++ b/docs/ideas/ini.toml @@ -0,0 +1,40 @@ +# Keys should be present +["setup.cfg".flake8] +ignore__present = "str" +max-line-length__present = "int" +exclude__present = "str" +max-complexity__present = "int" +inline-quotes__present = "str" + +# Keys should be absent +["setup.cfg".some-section] +ignore__present = true +max-line-length__present = true +exclude__present = true +max-complexity__present = true +inline-quotes__present = true + +# Section should be absent +["setup.cfg".darglint] +__present = false +blabla = "{{ nit.section_absent() }}" + +# Section should be absent +["setup.cfg"."tox:tox"] +__present = false +["setup.cfg"."gh-actions"] +__present = false + +# Section should be present +["tox.ini"."tox"] +__present = true +["tox.ini".gh-actions] +__present = true + +# Keys should be present using Jinja +["setup.cfg".flake82] +ignore = "{{ nit.present(str, validators=[comma_separated_str]) }}" +max-line-length = "{{ nit.present(int, validators=[range(80, 120)]) }}" +exclude = "{{ nit.present(str, validators=[comma_separated_str]) }}" +max-complexity = "{{ nit.present(int) }}" +inline-quotes = "{{ nit.present(str, choices=['double', 'single']) }}" diff --git a/docs/ideas/text-plugin.toml b/docs/ideas/text.toml similarity index 100% rename from docs/ideas/text-plugin.toml rename to docs/ideas/text.toml diff --git a/docs/ideas/toml.toml b/docs/ideas/toml.toml new file mode 100644 index 00000000..8a9f65e3 --- /dev/null +++ b/docs/ideas/toml.toml @@ -0,0 +1,36 @@ +# Keys are absent +["pyproject.toml".tool.poetry.dev-dependencies] +pep257__present = false +pycodestyle__present = false +pur__present = false +pep257 = "{{ nit.absent() }}" # Jinja +pycodestyle = "{{ nit.absent() }}" # Jinja +pur = "{{ nit.absent() }}" # Jinja + +# Keys are absent +["pyproject.toml".tool.poetry.dependencies] +pep257__present = false +pycodestyle__present = false +pur__present = false +pep257 = "{{ nit.absent() }}" # Jinja +pycodestyle = "{{ nit.absent() }}" # Jinja +pur = "{{ nit.absent() }}" # Jinja + +# TODO: pre-processing with Jinja to generate multiple sections with the same config? ["pyproject.toml".tool.poetry.{{ ['dependencies', 'dev-dependencies'] }}] + +# Keys are present, with the expected types +["pyproject.toml".build-system] +requires__present = "List[str]" +build-backend__present = "str" +requires = "{{ nit.present(List[str]) }}" # Jinja +build-backend = "{{ nit.present(str) }}" # Jinja + +# Integer key exists +["pyproject.toml".tool.black] +line-length__present = "int" +line-length = "{{ nit.present(int) }}" # Jinja + +# Section exists with anything inside +["pyproject.toml".tool.black2] +__present = true +blabla = "{{ nit.section_present() }}" # Jinja diff --git a/docs/ideas/yaml.toml b/docs/ideas/yaml.toml new file mode 100644 index 00000000..e69de29b diff --git a/docs/plugins.rst b/docs/plugins.rst index ee61bf14..f6fe0107 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -13,25 +13,17 @@ Below are the currently included plugins. .. auto-generated-from-here -.. _setupcfgplugin: - -setup.cfg ---------- - -Enforce config on `setup.cfg `_. - -Example: :ref:`flake8 configuration `. - .. _pyprojecttomlplugin: pyproject.toml -------------- -Enforce config on `pyproject.toml `_. +Enforce config on `pyproject.toml (PEP 518) `_. -See also `PEP 518 `_. +See also `the [tool.poetry] section of the pyproject.toml file +`_. -Example: :ref:`the Python 3.7 default `. +Example: :ref:`the Python 3.8 default `. There are many other examples in :ref:`defaults`. .. _precommitplugin: @@ -43,6 +35,20 @@ Enforce configuration for `.pre-commit-config.yaml `. +.. _iniplugin: + +INI files +--------- + +Enforce config on INI files. + +Examples of ``.ini`` files handled by this plugin: + +- `setup.cfg `_ +- `.editorconfig `_ + +Example of Nitpick styles enforcing values on INI files: :ref:`flake8 configuration `. + .. _jsonplugin: JSON files diff --git a/docs/source/nitpick.plugins.ini.rst b/docs/source/nitpick.plugins.ini.rst new file mode 100644 index 00000000..13760cc2 --- /dev/null +++ b/docs/source/nitpick.plugins.ini.rst @@ -0,0 +1,7 @@ +nitpick.plugins.ini module +========================== + +.. automodule:: nitpick.plugins.ini + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/nitpick.plugins.rst b/docs/source/nitpick.plugins.rst index eab3a9a4..e487b2c8 100644 --- a/docs/source/nitpick.plugins.rst +++ b/docs/source/nitpick.plugins.rst @@ -14,8 +14,8 @@ Submodules nitpick.plugins.base nitpick.plugins.info + nitpick.plugins.ini nitpick.plugins.json nitpick.plugins.pre_commit nitpick.plugins.pyproject_toml - nitpick.plugins.setup_cfg nitpick.plugins.text diff --git a/docs/source/nitpick.plugins.setup_cfg.rst b/docs/source/nitpick.plugins.setup_cfg.rst deleted file mode 100644 index 08b146aa..00000000 --- a/docs/source/nitpick.plugins.setup_cfg.rst +++ /dev/null @@ -1,7 +0,0 @@ -nitpick.plugins.setup\_cfg module -================================= - -.. automodule:: nitpick.plugins.setup_cfg - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/targets.rst b/docs/targets.rst index 1e6b6d49..ba9f62e9 100644 --- a/docs/targets.rst +++ b/docs/targets.rst @@ -3,6 +3,7 @@ .. _commitlint: https://commitlint.js.org/ .. _default style file: https://raw.githubusercontent.com/andreoliwa/nitpick/v0.24.1/nitpick-style.toml .. _Django: https://www.djangoproject.com +.. _EditorConfig: https://editorconfig.org/ .. _flake8: https://gitlab.com/pycqa/flake8/ .. _Flask CLI: https://flask.palletsprojects.com/en/1.1.x/cli/ .. _Invoke: https://github.com/pyinvoke/invoke @@ -19,4 +20,5 @@ .. _Pylint: https://www.pylint.org .. _pyproject-toml-poetry: https://github.com/python-poetry/poetry/blob/master/docs/docs/pyproject.md .. _pytest: https://pytest.org/ +.. _setup-cfg: https://docs.python.org/3/distutils/configfile.html .. _TOML: https://github.com/toml-lang/toml diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index a85c727b..0ed38bed 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -22,3 +22,23 @@ To solve this issue, add this environment variable to ``.bashrc`` (or the initia export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES Thanks to `this StackOverflow answer `_. + +ModuleNotFoundError: No module named 'nitpick.plugins.XXX' +---------------------------------------------------------- + +When upgrading to new versions, old plugins might be renamed in `setuptools entry points `_. + +But they might still be present in the `entry_points.txt plugin metadata `_ in your virtualenv. + +.. code-block:: + + $ rg nitpick.plugins.setup ~/Library/Caches/pypoetry/ + /Users/john.doe/Library/Caches/pypoetry/virtualenvs/nitpick-UU_pZ5zs-py3.6/lib/python3.6/site-packages/nitpick-0.24.1.dist-info/entry_points.txt + 11:setup_cfg=nitpick.plugins.setup_cfg + +Remove and recreate the virtualenv; this should fix it. + +During development, you can run ``invoke clean --venv install --dry``. +It will display the commands that would be executed; remove ``--dry`` to actually run them. + +:ref:`Read this page on how to install Invoke `. diff --git a/poetry.lock b/poetry.lock index 051be48c..c02085d1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -160,7 +160,7 @@ immutables = ">=0.9" [[package]] name = "coverage" -version = "5.4" +version = "5.5" description = "Code coverage measurement for Python" category = "main" optional = true @@ -316,6 +316,17 @@ python-versions = ">=2.7" [package.dependencies] ipython = {version = ">=5.1.0", markers = "python_version >= \"3.4\""} +[[package]] +name = "ipdb" +version = "0.13.5" +description = "IPython-enabled pdb" +category = "dev" +optional = false +python-versions = ">=2.7" + +[package.dependencies] +ipython = {version = ">=7.10.0,<7.17.0", markers = "python_version == \"3.6\""} + [[package]] name = "ipython" version = "7.16.1" @@ -1079,55 +1090,58 @@ contextvars = [ {file = "contextvars-2.4.tar.gz", hash = "sha256:f38c908aaa59c14335eeea12abea5f443646216c4e29380d7bf34d2018e2c39e"}, ] coverage = [ - {file = "coverage-5.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:6d9c88b787638a451f41f97446a1c9fd416e669b4d9717ae4615bd29de1ac135"}, - {file = "coverage-5.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:66a5aae8233d766a877c5ef293ec5ab9520929c2578fd2069308a98b7374ea8c"}, - {file = "coverage-5.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9754a5c265f991317de2bac0c70a746efc2b695cf4d49f5d2cddeac36544fb44"}, - {file = "coverage-5.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:fbb17c0d0822684b7d6c09915677a32319f16ff1115df5ec05bdcaaee40b35f3"}, - {file = "coverage-5.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b7f7421841f8db443855d2854e25914a79a1ff48ae92f70d0a5c2f8907ab98c9"}, - {file = "coverage-5.4-cp27-cp27m-win32.whl", hash = "sha256:4a780807e80479f281d47ee4af2eb2df3e4ccf4723484f77da0bb49d027e40a1"}, - {file = "coverage-5.4-cp27-cp27m-win_amd64.whl", hash = "sha256:87c4b38288f71acd2106f5d94f575bc2136ea2887fdb5dfe18003c881fa6b370"}, - {file = "coverage-5.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6809ebcbf6c1049002b9ac09c127ae43929042ec1f1dbd8bb1615f7cd9f70a0"}, - {file = "coverage-5.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ba7ca81b6d60a9f7a0b4b4e175dcc38e8fef4992673d9d6e6879fd6de00dd9b8"}, - {file = "coverage-5.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:89fc12c6371bf963809abc46cced4a01ca4f99cba17be5e7d416ed7ef1245d19"}, - {file = "coverage-5.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a8eb7785bd23565b542b01fb39115a975fefb4a82f23d407503eee2c0106247"}, - {file = "coverage-5.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:7e40d3f8eb472c1509b12ac2a7e24158ec352fc8567b77ab02c0db053927e339"}, - {file = "coverage-5.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1ccae21a076d3d5f471700f6d30eb486da1626c380b23c70ae32ab823e453337"}, - {file = "coverage-5.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:755c56beeacac6a24c8e1074f89f34f4373abce8b662470d3aa719ae304931f3"}, - {file = "coverage-5.4-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:322549b880b2d746a7672bf6ff9ed3f895e9c9f108b714e7360292aa5c5d7cf4"}, - {file = "coverage-5.4-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:60a3307a84ec60578accd35d7f0c71a3a971430ed7eca6567399d2b50ef37b8c"}, - {file = "coverage-5.4-cp35-cp35m-win32.whl", hash = "sha256:1375bb8b88cb050a2d4e0da901001347a44302aeadb8ceb4b6e5aa373b8ea68f"}, - {file = "coverage-5.4-cp35-cp35m-win_amd64.whl", hash = "sha256:16baa799ec09cc0dcb43a10680573269d407c159325972dd7114ee7649e56c66"}, - {file = "coverage-5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2f2cf7a42d4b7654c9a67b9d091ec24374f7c58794858bff632a2039cb15984d"}, - {file = "coverage-5.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b62046592b44263fa7570f1117d372ae3f310222af1fc1407416f037fb3af21b"}, - {file = "coverage-5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:812eaf4939ef2284d29653bcfee9665f11f013724f07258928f849a2306ea9f9"}, - {file = "coverage-5.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:859f0add98707b182b4867359e12bde806b82483fb12a9ae868a77880fc3b7af"}, - {file = "coverage-5.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:04b14e45d6a8e159c9767ae57ecb34563ad93440fc1b26516a89ceb5b33c1ad5"}, - {file = "coverage-5.4-cp36-cp36m-win32.whl", hash = "sha256:ebfa374067af240d079ef97b8064478f3bf71038b78b017eb6ec93ede1b6bcec"}, - {file = "coverage-5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:84df004223fd0550d0ea7a37882e5c889f3c6d45535c639ce9802293b39cd5c9"}, - {file = "coverage-5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1b811662ecf72eb2d08872731636aee6559cae21862c36f74703be727b45df90"}, - {file = "coverage-5.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6b588b5cf51dc0fd1c9e19f622457cc74b7d26fe295432e434525f1c0fae02bc"}, - {file = "coverage-5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3fe50f1cac369b02d34ad904dfe0771acc483f82a1b54c5e93632916ba847b37"}, - {file = "coverage-5.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:32ab83016c24c5cf3db2943286b85b0a172dae08c58d0f53875235219b676409"}, - {file = "coverage-5.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:68fb816a5dd901c6aff352ce49e2a0ffadacdf9b6fae282a69e7a16a02dad5fb"}, - {file = "coverage-5.4-cp37-cp37m-win32.whl", hash = "sha256:a636160680c6e526b84f85d304e2f0bb4e94f8284dd765a1911de9a40450b10a"}, - {file = "coverage-5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:bb32ca14b4d04e172c541c69eec5f385f9a075b38fb22d765d8b0ce3af3a0c22"}, - {file = "coverage-5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4d7165a4e8f41eca6b990c12ee7f44fef3932fac48ca32cecb3a1b2223c21f"}, - {file = "coverage-5.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a565f48c4aae72d1d3d3f8e8fb7218f5609c964e9c6f68604608e5958b9c60c3"}, - {file = "coverage-5.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fff1f3a586246110f34dc762098b5afd2de88de507559e63553d7da643053786"}, - {file = "coverage-5.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a839e25f07e428a87d17d857d9935dd743130e77ff46524abb992b962eb2076c"}, - {file = "coverage-5.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:6625e52b6f346a283c3d563d1fd8bae8956daafc64bb5bbd2b8f8a07608e3994"}, - {file = "coverage-5.4-cp38-cp38-win32.whl", hash = "sha256:5bee3970617b3d74759b2d2df2f6a327d372f9732f9ccbf03fa591b5f7581e39"}, - {file = "coverage-5.4-cp38-cp38-win_amd64.whl", hash = "sha256:03ed2a641e412e42cc35c244508cf186015c217f0e4d496bf6d7078ebe837ae7"}, - {file = "coverage-5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14a9f1887591684fb59fdba8feef7123a0da2424b0652e1b58dd5b9a7bb1188c"}, - {file = "coverage-5.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9564ac7eb1652c3701ac691ca72934dd3009997c81266807aef924012df2f4b3"}, - {file = "coverage-5.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:0f48fc7dc82ee14aeaedb986e175a429d24129b7eada1b7e94a864e4f0644dde"}, - {file = "coverage-5.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:107d327071061fd4f4a2587d14c389a27e4e5c93c7cba5f1f59987181903902f"}, - {file = "coverage-5.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:0cdde51bfcf6b6bd862ee9be324521ec619b20590787d1655d005c3fb175005f"}, - {file = "coverage-5.4-cp39-cp39-win32.whl", hash = "sha256:c67734cff78383a1f23ceba3b3239c7deefc62ac2b05fa6a47bcd565771e5880"}, - {file = "coverage-5.4-cp39-cp39-win_amd64.whl", hash = "sha256:c669b440ce46ae3abe9b2d44a913b5fd86bb19eb14a8701e88e3918902ecd345"}, - {file = "coverage-5.4-pp36-none-any.whl", hash = "sha256:c0ff1c1b4d13e2240821ef23c1efb1f009207cb3f56e16986f713c2b0e7cd37f"}, - {file = "coverage-5.4-pp37-none-any.whl", hash = "sha256:cd601187476c6bed26a0398353212684c427e10a903aeafa6da40c63309d438b"}, - {file = "coverage-5.4.tar.gz", hash = "sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca"}, + {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, + {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, + {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, + {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, + {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, + {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, + {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, + {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, + {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, + {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, + {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, + {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, + {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, + {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, + {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, + {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, + {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, + {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, + {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, + {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, + {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] dataclasses = [ {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, @@ -1196,6 +1210,7 @@ iniconfig = [ ] ipdb = [ {file = "ipdb-0.13.4.tar.gz", hash = "sha256:c85398b5fb82f82399fc38c44fe3532c0dde1754abee727d8f5cfcc74547b334"}, + {file = "ipdb-0.13.5.tar.gz", hash = "sha256:521e55ade3d3f5e459df6474cfb1d1ef6d44ab4155f829695c7c3dc2a8ce5b2b"}, ] ipython = [ {file = "ipython-7.16.1-py3-none-any.whl", hash = "sha256:2dbcc8c27ca7d3cfe4fcdff7f45b27f9a8d3edfa70ff8024a71c7a8eb5f09d64"}, diff --git a/pyproject.toml b/pyproject.toml index 82c2033a..ddf3bec6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ NIP = "nitpick.flake8:NitpickFlake8Extension" text = "nitpick.plugins.text" json = "nitpick.plugins.json" pre_commit = "nitpick.plugins.pre_commit" -setup_cfg = "nitpick.plugins.setup_cfg" +ini = "nitpick.plugins.ini" pyproject_toml = "nitpick.plugins.pyproject_toml" [tool.poetry.dependencies] diff --git a/src/nitpick/plugins/setup_cfg.py b/src/nitpick/plugins/ini.py similarity index 94% rename from src/nitpick/plugins/setup_cfg.py rename to src/nitpick/plugins/ini.py index 165a3f0e..1b140ade 100644 --- a/src/nitpick/plugins/setup_cfg.py +++ b/src/nitpick/plugins/ini.py @@ -1,4 +1,4 @@ -"""Enforce config on `setup.cfg `.""" +"""INI files.""" from configparser import ConfigParser, DuplicateOptionError, ParsingError from io import StringIO from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Type @@ -6,7 +6,6 @@ import dictdiffer from configupdater import ConfigUpdater -from nitpick.constants import SETUP_CFG from nitpick.plugins import hookimpl from nitpick.plugins.base import NitpickPlugin from nitpick.plugins.info import FileInfo @@ -27,15 +26,20 @@ class Violations(ViolationEnum): PARSING_ERROR = (326, ": parsing error ({cls}): {msg}") -class SetupCfgPlugin(NitpickPlugin): - """Enforce config on `setup.cfg `_. +class IniPlugin(NitpickPlugin): + """Enforce config on INI files. - Example: :ref:`flake8 configuration `. + Examples of ``.ini`` files handled by this plugin: + + - `setup.cfg `_ + - `.editorconfig `_ + + Example of Nitpick styles enforcing values on INI files: :ref:`flake8 configuration `. """ - filename = SETUP_CFG - violation_base_code = 320 can_apply = True + identify_tags = {"ini"} + violation_base_code = 320 updater: ConfigUpdater comma_separated_values: Set[str] @@ -201,12 +205,12 @@ def get_example_cfg(parser: ConfigParser) -> str: @hookimpl def plugin_class() -> Type["NitpickPlugin"]: """You should return your plugin class here.""" - return SetupCfgPlugin + return IniPlugin @hookimpl def can_handle(info: FileInfo) -> Optional[Type["NitpickPlugin"]]: """Handle the setup.cfg file.""" - if info.path_from_root == SETUP_CFG: - return SetupCfgPlugin + if IniPlugin.identify_tags & info.tags: + return IniPlugin return None diff --git a/src/nitpick/plugins/pyproject_toml.py b/src/nitpick/plugins/pyproject_toml.py index f3bdfece..c6601996 100644 --- a/src/nitpick/plugins/pyproject_toml.py +++ b/src/nitpick/plugins/pyproject_toml.py @@ -28,11 +28,12 @@ def change_toml(document: TOMLDocument, dictionary): class PyProjectTomlPlugin(NitpickPlugin): - """Enforce config on `pyproject.toml `_. + """Enforce config on `pyproject.toml (PEP 518) `_. - See also `PEP 518 `_. + See also `the [tool.poetry] section of the pyproject.toml file + `_. - Example: :ref:`the Python 3.7 default `. + Example: :ref:`the Python 3.8 default `. There are many other examples in :ref:`defaults`. """ diff --git a/src/nitpick/schemas.py b/src/nitpick/schemas.py index 192631dc..939eb54b 100644 --- a/src/nitpick/schemas.py +++ b/src/nitpick/schemas.py @@ -43,7 +43,7 @@ class NitpickStylesSectionSchema(BaseNitpickSchema): include = PolyField(deserialization_schema_selector=fields.string_or_list_field) -class SetupCfgSchema(BaseNitpickSchema): +class IniSchema(BaseNitpickSchema): """Validation schema for setup.cfg.""" error_messages = {"unknown": help_message("Unknown configuration", "nitpick_section.html#comma-separated-values")} @@ -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(SetupCfgSchema, data_key="setup.cfg") + setup_cfg = fields.Nested(IniSchema, data_key="setup.cfg") class NitpickSectionSchema(BaseNitpickSchema): diff --git a/tasks.py b/tasks.py index 4d709381..2d283c0a 100644 --- a/tasks.py +++ b/tasks.py @@ -8,6 +8,9 @@ from invoke import Collection, task +COLOR_GREEN = "\x1b[32m" +COLOR_NONE = "\x1b[0m" + @task(help={"deps": "Poetry dependencies", "hooks": "pre-commit hooks"}) def install(c, deps=True, hooks=False): @@ -16,7 +19,7 @@ def install(c, deps=True, hooks=False): Poetry install is needed to create the Nitpick plugin entries on setuptools, used by pluggy. """ if deps: - print("Nitpick runs in Python 3.6 and later, but development is done in 3.6") + print(f"{COLOR_GREEN}Nitpick runs in Python 3.6 and later, but development is done in 3.6{COLOR_NONE}") c.run("poetry env use python3.6") c.run("poetry install -E test -E lint --remove-untracked") if hooks: @@ -82,12 +85,15 @@ def pre_commit(c): c.run("pre-commit run --all-files") -@task(help={"open": "Open the HTML index"}) -def doc(c, open=False): +@task(help={"open": "Open the HTML index", "generate": "Run RST generation only"}) +def doc(c, open=False, generate=False): """Build documentation.""" - c.run("mkdir -p docs/_static") - c.run("rm -rf docs/source") - c.run("tox -e docs") + if generate: + c.run("poetry run python3 docs/generate_rst.py") + else: + c.run("mkdir -p docs/_static") + c.run("rm -rf docs/source") + c.run("tox -e docs") if open: c.run("open .tox/docs_out/index.html") @@ -104,8 +110,8 @@ def ci_build(c, full=False, recreate=False): c.run(f"{tox_cmd} -e clean,lint,py38,docs,report") -@task -def clean(c): +@task(help={"venv": "Remove the Poetry virtualenv"}) +def clean(c, venv=False): """Clean build output and temp files.""" c.run("find . -type f -name '*.py[co]' -print -delete") c.run("find . -type d -name '__pycache__' -print -delete") @@ -114,6 +120,8 @@ def clean(c): "xargs -0 rm -rvf" ) c.run("rm -rvf .cache .mypy_cache docs/_build src/*.egg-info .pytest_cache .coverage htmlcov .tox") + if venv: + c.run("poetry env remove python3.6", warn=True) namespace = Collection(install, update, test, nitpick, pylint, pre_commit, doc, ci_build, clean) diff --git a/tests/helpers.py b/tests/helpers.py index 6fabd4d8..96227a02 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -4,11 +4,11 @@ from pathlib import Path from pprint import pprint from textwrap import dedent -from typing import Dict, Iterable, List, Optional, Set +from typing import Dict, Iterable, List, Optional, Set, Union import pytest from click.testing import CliRunner -from more_itertools.more import always_iterable +from more_itertools.more import always_iterable, windowed from testfixtures import compare from nitpick.cli import nitpick_cli @@ -339,8 +339,10 @@ def cli_ls(self, str_or_lines: StrOrList): _, actual, expected = self._simulate_cli("ls", str_or_lines) compare(actual=actual, expected=expected) - def assert_file_contents(self, filename: PathOrStr, file_contents: str): + def assert_file_contents(self, *name_contents: Union[PathOrStr, str]): """Assert the file has the expected contents.""" - actual = self.read_file(filename) - expected = dedent(file_contents).strip() - compare(actual=actual, expected=expected) + assert len(name_contents) % 2 == 0, "Supply pairs of arguments: filename (PathOrStr) and file contents (str)" + for filename, file_contents in windowed(name_contents, 2, step=2): + actual = self.read_file(filename) + expected = dedent(file_contents).strip() + compare(actual=actual, expected=expected) diff --git a/tests/test_setup_cfg.py b/tests/test_ini.py similarity index 93% rename from tests/test_setup_cfg.py rename to tests/test_ini.py index caa62513..3b800924 100644 --- a/tests/test_setup_cfg.py +++ b/tests/test_ini.py @@ -5,8 +5,8 @@ from configupdater import ConfigUpdater from nitpick.constants import SETUP_CFG -from nitpick.plugins.setup_cfg import SetupCfgPlugin, Violations -from nitpick.violations import Fuss, ProjectViolations, SharedViolations +from nitpick.plugins.ini import IniPlugin, Violations +from nitpick.violations import Fuss, SharedViolations from tests.helpers import XFAIL_ON_WINDOWS, ProjectMock @@ -94,8 +94,8 @@ def test_comma_separated_keys_on_style_file(tmp_path): def test_suggest_initial_contents(tmp_path): - """Suggest contents when setup.cfg does not exist.""" - expected_content = """ + """Suggest contents when INI files do not exist.""" + expected_setup_cfg = """ [flake8] max-line-length = 120 @@ -105,11 +105,13 @@ def test_suggest_initial_contents(tmp_path): [mypy] ignore_missing_imports = True """ + expected_generic_ini = """ + [your-section] + your_number = 123 + your_string = value + """ ProjectMock(tmp_path).style( """ - [nitpick.files.present] - "setup.cfg" = "Do something here" - ["setup.cfg".mypy] ignore_missing_imports = true @@ -118,18 +120,28 @@ def test_suggest_initial_contents(tmp_path): ["setup.cfg".flake8] max-line-length = 120 + + ["generic.ini".your-section] + your_string = "value" + your_number = 123 """ ).api_check_then_apply( Fuss( True, SETUP_CFG, - SharedViolations.CREATE_FILE_WITH_SUGGESTION.code + SetupCfgPlugin.violation_base_code, + SharedViolations.CREATE_FILE_WITH_SUGGESTION.code + IniPlugin.violation_base_code, + " was not found. Create it with this content:", + expected_setup_cfg, + ), + Fuss( + True, + "generic.ini", + SharedViolations.CREATE_FILE_WITH_SUGGESTION.code + IniPlugin.violation_base_code, " was not found. Create it with this content:", - expected_content, + expected_generic_ini, ), - Fuss(False, SETUP_CFG, ProjectViolations.MISSING_FILE.code, " should exist: Do something here"), ).assert_file_contents( - SETUP_CFG, expected_content + SETUP_CFG, expected_setup_cfg, "generic.ini", expected_generic_ini ) diff --git a/tests/test_pre_commit.py b/tests/test_pre_commit.py index 49778a28..c9ebce36 100644 --- a/tests/test_pre_commit.py +++ b/tests/test_pre_commit.py @@ -397,16 +397,6 @@ def test_missing_different_values(tmp_path): [tool.nitpick] style = ["root", "mypy", "pre-commit/python", "pre-commit/bash"] """ - ).setup_cfg( - """ - [mypy] - follow_imports = skip - ignore_missing_imports = True - strict_optional = True - warn_no_return = True - warn_redundant_casts = True - warn_unused_ignores = True - """ ).pre_commit( """ repos: @@ -502,6 +492,7 @@ def test_missing_different_values(tmp_path): ": hook 'rst-backticks' (rev: v1.1.0) has different values. Use this:", "rev: v1.8.0", ), + partial_names=[PRE_COMMIT_CONFIG_YAML], )