diff --git a/.github/workflows/do-lint.yml b/.github/workflows/do-lint.yml index 2be4268..a33baf6 100644 --- a/.github/workflows/do-lint.yml +++ b/.github/workflows/do-lint.yml @@ -22,4 +22,4 @@ jobs: with: fetch-depth: 0 - name: Lint code base - run: tox -e style + run: tox -e pre-commit diff --git a/.github/workflows/do-update-authors.yml b/.github/workflows/do-update-authors.yml index 4c4c67d..9fffbf3 100644 --- a/.github/workflows/do-update-authors.yml +++ b/.github/workflows/do-update-authors.yml @@ -81,4 +81,4 @@ jobs: author_email: action@github.com committer_name: GitHub Actions committer_email: actions@github.com - push: true \ No newline at end of file + push: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6920374..dc441de 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,4 @@ +exclude: 'tests/' repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 @@ -25,16 +26,16 @@ repos: - id: isort args: [--settings-file, ./pyproject.toml] - repo: https://github.com/PyCQA/docformatter - rev: v1.7.6 + rev: v1.7.7 hooks: - id: docformatter additional_dependencies: [tomli] args: [--in-place, --config, ./pyproject.toml] - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: 'v0.11.9' + rev: 'v0.12.4' hooks: - id: ruff - args: [ --select, "PL", --select, "F" ] + args: [ --config, ./pyproject.toml ] - repo: https://github.com/pycqa/pydocstyle rev: 6.3.0 hooks: @@ -42,18 +43,18 @@ repos: additional_dependencies: [toml] args: [--config, ./pyproject.toml] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.15.0 + rev: v1.17.0 hooks: - id: mypy additional_dependencies: [types-python-dateutil] args: [--config-file, ./pyproject.toml] - repo: https://github.com/myint/eradicate - rev: '2.3.0' + rev: '3.0.0' hooks: - id: eradicate args: [] - repo: https://github.com/rstcheck/rstcheck - rev: 'v6.2.4' + rev: 'v6.2.5' hooks: - id: rstcheck additional_dependencies: [tomli] diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f8928d..bb86107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -150,6 +150,3 @@ Bug Fixes ## [v1.4](https://github.com/PyCQA/docformatter/tree/v1.4) (2020-12-27) [Full Changelog](https://github.com/PyCQA/docformatter/compare/v1.3.1...v1.4) - - - diff --git a/docs/source/authors.rst b/docs/source/authors.rst index f3e9708..e9799a9 100644 --- a/docs/source/authors.rst +++ b/docs/source/authors.rst @@ -1,4 +1,4 @@ Authors ======= -.. include:: ../../AUTHORS.rst \ No newline at end of file +.. include:: ../../AUTHORS.rst diff --git a/docs/source/license.rst b/docs/source/license.rst index 40a7f6a..4261100 100644 --- a/docs/source/license.rst +++ b/docs/source/license.rst @@ -1,4 +1,4 @@ License ======= -.. literalinclude:: ../../LICENSE \ No newline at end of file +.. literalinclude:: ../../LICENSE diff --git a/pyproject.toml b/pyproject.toml index da8ee40..025b88f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -178,114 +178,58 @@ line_length = 88 report = "warning" ignore_directives = [ "automodule", + "literalinclude", "tabularcolumns", "toctree", ] +ignore_messages = [ + "Possible title underline" +] ignore_roles = [ "numref", + "ref", ] -[tool.tox] -legacy_tox_ini = """ -[tox] -envlist = - py39 - py310 - py311 - py312 - py313 - pypy3 - coverage - style -isolated_build = true -skip_missing_interpreters = true -skipsdist = true - -[gh-actions] -python = - 3.9: py39 - 3.10: py310 - 3.11: py311 - 3.12: py312 - 3.13: py313 - pypy-3.9: pypy3 - -[testenv] -description = run the test suite using pytest under {basepython} -deps = - charset_normalizer - coverage[toml] - mock - pytest - pytest-cov - pytest-order - tomli - untokenize -setenv = - COVERAGE_FILE = {toxworkdir}/.coverage.{envname} -commands = - pip install -U pip - pip install --prefix={toxworkdir}/{envname} -e .[tomli] - pytest -s -x -c {toxinidir}/pyproject.toml \ - -m unit \ - --cache-clear \ - --cov=docformatter \ - --cov-config={toxinidir}/pyproject.toml \ - --cov-branch \ - {toxinidir}/tests/ - pytest -s -x -c {toxinidir}/pyproject.toml \ - -m integration \ - --cache-clear \ - --cov=docformatter \ - --cov-config={toxinidir}/pyproject.toml \ - --cov-branch \ - {toxinidir}/tests/ - pytest -s -x -c {toxinidir}/pyproject.toml \ - -m system \ - --cache-clear \ - --cov=docformatter \ - --cov-config={toxinidir}/pyproject.toml \ - --cov-branch \ - --cov-append \ - {toxinidir}/tests/ - -[testenv:coverage] -description = combine coverage data and create report -setenv = - COVERAGE_FILE = {toxworkdir}/.coverage -skip_install = true -deps = - coverage[toml] -parallel_show_output = true -commands = - coverage combine - coverage report -m - coverage xml -o {toxworkdir}/coverage.xml -depends = py39, py310, py311, py312, py313, pypy3 - -[testenv:style] -description = run autoformatters and style checkers -deps = - charset_normalizer - pycodestyle - pydocstyle - ruff==0.0.269 - rstcheck - toml - untokenize -commands = - pip install -U pip - pip install . - docformatter --black --recursive {toxinidir}/src/docformatter - pycodestyle --exclude=.git,.tox,*.pyc,*.pyo,build,dist,*.egg-info,config,docs,locale,tests,tools --ignore=C326,C330,E121,E123,E126,E133,E203,E242,E265,E402,W503,W504 --format=pylint --max-line-length=88 {toxinidir}/src/docformatter - pydocstyle {toxinidir}/src/docformatter - ruff check --select "PL" --select "F" {toxinidir}/src/docformatter - rstcheck --report-level=1 {toxinidir}/README.rst - -[testenv:docs] -description = build docformatter documentation -allowlist_externals = make -changedir = docs -commands = - make html -""" +[tool.ruff] +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", + "tests/", +] +line-length = 88 +indent-width = 4 +target-version = "py39" + +[tool.ruff.lint] +select = ["E", "F", "PL"] +ignore = [] + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" diff --git a/src/docformatter/configuration.py b/src/docformatter/configuration.py index 6910636..d773594 100644 --- a/src/docformatter/configuration.py +++ b/src/docformatter/configuration.py @@ -33,7 +33,7 @@ import os import sys from configparser import ConfigParser -from typing import Dict, List, Union +from typing import Dict, Sequence, Union with contextlib.suppress(ImportError): if sys.version_info >= (3, 11): @@ -65,7 +65,7 @@ class Configurater: args: argparse.Namespace = argparse.Namespace() - def __init__(self, args: List[Union[bool, int, str]]) -> None: + def __init__(self, args: Union[Sequence[str], None]) -> None: """Initialize a Configurater class instance. Parameters @@ -73,7 +73,7 @@ def __init__(self, args: List[Union[bool, int, str]]) -> None: args : list Any command line arguments passed during invocation. """ - self.args_lst = args + self.args_lst: Union[Sequence[str], None] = args self.config_file = "" self.parser = argparse.ArgumentParser( description=__doc__, @@ -81,7 +81,10 @@ def __init__(self, args: List[Union[bool, int, str]]) -> None: ) try: - self.config_file = self.args_lst[self.args_lst.index("--config") + 1] + if self.args_lst is not None: + self.config_file = str( + self.args_lst[self.args_lst.index("--config") + 1] + ) except ValueError: for _configuration_file in self.configuration_file_lst: if os.path.isfile(_configuration_file): @@ -98,21 +101,21 @@ def do_parse_arguments(self) -> None: "-i", "--in-place", action="store_true", - default=self.flargs.get("in-place", "false").lower() == "true", + default=str(self.flargs.get("in-place", "false")).lower() == "true", help="make changes to files instead of printing diffs", ) changes.add_argument( "-c", "--check", action="store_true", - default=self.flargs.get("check", "false").lower() == "true", + default=str(self.flargs.get("check", "false")).lower() == "true", help="only check and report incorrectly formatted files", ) self.parser.add_argument( "-d", "--diff", action="store_true", - default=self.flargs.get("diff", "false").lower() == "true", + default=str(self.flargs.get("diff", "false")).lower() == "true", help="when used with `--check` or `--in-place`, also what changes " "would be made", ) @@ -120,7 +123,7 @@ def do_parse_arguments(self) -> None: "-r", "--recursive", action="store_true", - default=self.flargs.get("recursive", "false").lower() == "true", + default=str(self.flargs.get("recursive", "false")).lower() == "true", help="drill down directories recursively", ) self.parser.add_argument( @@ -142,12 +145,13 @@ def do_parse_arguments(self) -> None: self.parser.add_argument( "--black", action="store_true", - default=self.flargs.get("black", "false").lower() == "true", + default=str(self.flargs.get("black", "false")).lower() == "true", help="make formatting compatible with standard black options " "(default: False)", ) - self.args = self.parser.parse_known_args(self.args_lst[1:])[0] + if self.args_lst is not None: + self.args = self.parser.parse_known_args(self.args_lst[1:])[0] # Default black line length is 88, so use this when not specified # otherwise use PEP-8 defaults @@ -199,7 +203,7 @@ def do_parse_arguments(self) -> None: self.parser.add_argument( "--force-wrap", action="store_true", - default=self.flargs.get("force-wrap", "false").lower() == "true", + default=str(self.flargs.get("force-wrap", "false")).lower() == "true", help="force descriptions to be wrapped even if it may " "result in a mess (default: False)", ) @@ -216,21 +220,22 @@ def do_parse_arguments(self) -> None: "--blank", dest="post_description_blank", action="store_true", - default=self.flargs.get("blank", "false").lower() == "true", + default=str(self.flargs.get("blank", "false")).lower() == "true", help="add blank line after description (default: False)", ) self.parser.add_argument( "--pre-summary-newline", action="store_true", - default=self.flargs.get("pre-summary-newline", "false").lower() == "true", + default=str(self.flargs.get("pre-summary-newline", "false")).lower() + == "true", help="add a newline before the summary of a multi-line docstring " "(default: False)", ) self.parser.add_argument( "--pre-summary-space", action="store_true", - default=self.flargs.get( - "pre-summary-space", _default_pre_summary_space + default=str( + self.flargs.get("pre-summary-space", _default_pre_summary_space) ).lower() == "true", help="add a space after the opening triple quotes (default: False)", @@ -238,7 +243,7 @@ def do_parse_arguments(self) -> None: self.parser.add_argument( "--make-summary-multi-line", action="store_true", - default=self.flargs.get("make-summary-multi-line", "false").lower() + default=str(self.flargs.get("make-summary-multi-line", "false")).lower() == "true", help="add a newline before and after the summary of a one-line " "docstring (default: False)", @@ -246,7 +251,7 @@ def do_parse_arguments(self) -> None: self.parser.add_argument( "--close-quotes-on-newline", action="store_true", - default=self.flargs.get("close-quotes-on-newline", "false").lower() + default=str(self.flargs.get("close-quotes-on-newline", "false")).lower() == "true", help="place closing triple quotes on a new-line when a " "one-line docstring wraps to two or more lines " @@ -275,7 +280,7 @@ def do_parse_arguments(self) -> None: self.parser.add_argument( "--non-strict", action="store_true", - default=self.flargs.get("non-strict", "false").lower() == "true", + default=str(self.flargs.get("non-strict", "false")).lower() == "true", help="don't strictly follow reST syntax to identify lists (see " "issue #67) (default: False)", ) @@ -295,7 +300,8 @@ def do_parse_arguments(self) -> None: help="files to format or '-' for standard in", ) - self.args = self.parser.parse_args(self.args_lst[1:]) + if self.args_lst is not None: + self.args = self.parser.parse_args(self.args_lst[1:]) if self.args.line_range: if self.args.line_range[0] <= 0: @@ -341,7 +347,7 @@ def _do_read_toml_configuration(self) -> None: result = config.get("tool", {}).get("docformatter", None) if result is not None: self.flargs = { - k: v if isinstance(v, list) else str(v) for k, v in result.items() + k: v if isinstance(v, list) else str(v) for k, v in result.items() # type: ignore } def _do_read_parser_configuration(self) -> None: diff --git a/src/docformatter/format.py b/src/docformatter/format.py index 25837d0..78c4bc0 100644 --- a/src/docformatter/format.py +++ b/src/docformatter/format.py @@ -31,6 +31,7 @@ import argparse import collections import contextlib +import difflib import io import tokenize from typing import TextIO, Union @@ -755,9 +756,6 @@ def _do_format_file(self, filename: str) -> int: show_diff = True if show_diff: - # Standard Library Imports - import difflib - diff = difflib.unified_diff( source.splitlines(), formatted_source.splitlines(), diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..30cce43 --- /dev/null +++ b/tox.ini @@ -0,0 +1,92 @@ +[tox] +env_list = + py39 + py310 + py311 + py312 + py313 + pypy3 + coverage + pre-commit +isolated_build = true +skip_missing_interpreters = true +skipsdist = true + +[gh-actions] +python = + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 + 3.13: py313 + pypy-3.9: pypy3 + +[testenv] +description = Run the test suite using pytest under {basepython} +deps = + charset_normalizer + coverage[toml] + mock + pytest + pytest-cov + pytest-order + tomli + untokenize +setenv = + COVERAGE_FILE = {toxworkdir}/.coverage.{envname} +commands = + pip install -U pip + pip install --prefix={toxworkdir}/{envname} -e .[tomli] + pytest -s -x -c {toxinidir}/pyproject.toml \ + -m unit \ + --cache-clear \ + --cov=docformatter \ + --cov-config={toxinidir}/pyproject.toml \ + --cov-branch \ + {toxinidir}/tests/ + pytest -s -x -c {toxinidir}/pyproject.toml \ + -m integration \ + --cache-clear \ + --cov=docformatter \ + --cov-config={toxinidir}/pyproject.toml \ + --cov-branch \ + {toxinidir}/tests/ + pytest -s -x -c {toxinidir}/pyproject.toml \ + -m system \ + --cache-clear \ + --cov=docformatter \ + --cov-config={toxinidir}/pyproject.toml \ + --cov-branch \ + --cov-append \ + {toxinidir}/tests/ + +[testenv:coverage] +description = combine coverage data and create report +setenv = + COVERAGE_FILE = {toxworkdir}/.coverage +skip_install = true +deps = + coverage[toml] +parallel_show_output = true +commands = + coverage combine + coverage report -m + coverage xml -o {toxworkdir}/coverage.xml +depends = py39, py310, py311, py312, py313, pypy3 + +[testenv:pre-commit] +description = Run autoformatters and quality assurance tools under {basepython}. +deps = + pre-commit +commands = + {envpython} -m pre_commit run \ + --color=always \ + --show-diff-on-failure \ + {posargs:--all-files} + +[testenv:docs] +description = build docformatter documentation +allowlist_externals = make +changedir = docs +commands = + make html