Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use tomllib for Python 3.11+ #208

Merged
merged 3 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-docstring-first
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
Expand Down
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ From pip::

$ pip install --upgrade docformatter

Or, if you want to use pyproject.toml to configure docformatter::
Or, if you want to use pyproject.toml to configure docformatter and you're using
Python < 3.11::

$ pip install --upgrade docformatter[tomli]

Expand Down
3 changes: 3 additions & 0 deletions docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ to install with TOML support:

$ pip install --upgrade docformatter[tomli]

This is only necessary if you are using Python < 3.11. Beginning with Python 3.11,
docformatter will utilize ``tomllib`` from the standard library.

Install from GitHub
-------------------

Expand Down
11 changes: 6 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ include = ["LICENSE"]
[tool.poetry.dependencies]
python = "^3.7"
charset_normalizer = "^3.0.0"
tomli = {version = "^2.0.0", optional = true}
tomli = {version = "^2.0.0", python = "<3.11", optional = true}
untokenize = "^0.1.1"

[tool.poetry.dev-dependencies]
Expand All @@ -52,6 +52,7 @@ pylint = [
]
pytest = "^7.1.0"
pytest-cov = "^4.0.0"
ruff = "^0.0.267"
rstcheck = "^6.1.0"
tox = "<4.0.0"
Sphinx = [
Expand Down Expand Up @@ -134,7 +135,7 @@ show_missing = true
output = 'coverage.xml'

[tool.black]
line-length = 79
line-length = 88
target-version = ['py37', 'py38', 'py39', 'py310', 'py311']
include = '\.pyi?$'
exclude = '''
Expand Down Expand Up @@ -164,7 +165,7 @@ include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
line_length = 79
line_length = 88

[tool.tox]
legacy_tox_ini = """
Expand Down Expand Up @@ -242,7 +243,7 @@ deps =
charset_normalizer
pycodestyle
pydocstyle
pylint
ruff
rstcheck
toml
untokenize
Expand All @@ -252,6 +253,6 @@ commands =
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
pylint --rcfile={toxinidir}/pyproject.toml {toxinidir}/src/docformatter
ruff check --select "PL" --select "F" {toxinidir}/src/docformatter
rstcheck --report-level=1 {toxinidir}/README.rst
"""
12 changes: 6 additions & 6 deletions src/docformatter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@

# docformatter Local Imports
from .__pkginfo__ import __version__
from .strings import *
from .syntax import *
from .util import *
from .strings import * # noqa F403
from .syntax import * # noqa F403
from .util import * # noqa F403

# Have isort skip these they require the functions above.
from .configuration import Configurater # isort: skip
from .encode import Encoder # isort: skip
from .format import Formatter, FormatResult # isort: skip
from .configuration import Configurater # isort: skip # noqa F401
from .encode import Encoder # isort: skip # noqa F401
from .format import Formatter, FormatResult # isort: skip # noqa F401
77 changes: 38 additions & 39 deletions src/docformatter/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,28 @@
# SOFTWARE.
"""This module provides docformatter's Configurater class."""


# Standard Library Imports
import argparse
import contextlib
import os
import sys
from configparser import ConfigParser
from typing import Dict, List, Union

try:
# Third Party Imports
import tomli
TOMLLIB_INSTALLED = False
TOMLI_INSTALLED = False
with contextlib.suppress(ImportError):
if sys.version_info >= (3, 11):
# Standard Library Imports
import tomllib

TOMLLIB_INSTALLED = True
else:
# Third Party Imports
import tomli

TOMLI_INSTALLED = True
except ImportError:
TOMLI_INSTALLED = False
TOMLI_INSTALLED = True

# docformatter Package Imports
from docformatter import __pkginfo__
Expand All @@ -44,7 +53,7 @@
class Configurater:
"""Read and store all the docformatter configuration information."""

parser = None
parser: argparse.ArgumentParser = argparse.ArgumentParser()
"""Parser object."""

flargs_dct: Dict[str, Union[bool, float, int, str]] = {}
Expand All @@ -57,7 +66,7 @@ class Configurater:
]
"""List of supported configuration files."""

args: argparse.Namespace = None
args: argparse.Namespace = argparse.Namespace()

def __init__(self, args: List[Union[bool, int, str]]) -> None:
"""Initialize a Configurater class instance.
Expand All @@ -75,9 +84,7 @@ def __init__(self, args: List[Union[bool, int, str]]) -> None:
)

try:
self.config_file = self.args_lst[
self.args_lst.index("--config") + 1
]
self.config_file = 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):
Expand Down Expand Up @@ -116,8 +123,7 @@ def do_parse_arguments(self) -> None:
"-r",
"--recursive",
action="store_true",
default=self.flargs_dct.get("recursive", "false").lower()
== "true",
default=self.flargs_dct.get("recursive", "false").lower() == "true",
help="drill down directories recursively",
)
self.parser.add_argument(
Expand Down Expand Up @@ -163,13 +169,11 @@ def do_parse_arguments(self) -> None:
"--style",
default=self.flargs_dct.get("style", "sphinx"),
help="name of the docstring style to use when formatting "
"parameter lists (default: sphinx)",
"parameter lists (default: sphinx)",
)
self.parser.add_argument(
"--wrap-summaries",
default=int(
self.flargs_dct.get("wrap-summaries", _default_wrap_summaries)
),
default=int(self.flargs_dct.get("wrap-summaries", _default_wrap_summaries)),
type=int,
metavar="length",
help="wrap long summary lines at this length; "
Expand All @@ -179,9 +183,7 @@ def do_parse_arguments(self) -> None:
self.parser.add_argument(
"--wrap-descriptions",
default=int(
self.flargs_dct.get(
"wrap-descriptions", _default_wrap_descriptions
)
self.flargs_dct.get("wrap-descriptions", _default_wrap_descriptions)
),
type=int,
metavar="length",
Expand All @@ -192,8 +194,7 @@ def do_parse_arguments(self) -> None:
self.parser.add_argument(
"--force-wrap",
action="store_true",
default=self.flargs_dct.get("force-wrap", "false").lower()
== "true",
default=self.flargs_dct.get("force-wrap", "false").lower() == "true",
help="force descriptions to be wrapped even if it may "
"result in a mess (default: False)",
)
Expand Down Expand Up @@ -228,25 +229,20 @@ def do_parse_arguments(self) -> None:
"pre-summary-space", _default_pre_summary_space
).lower()
== "true",
help="add a space after the opening triple quotes "
"(default: False)",
help="add a space after the opening triple quotes " "(default: False)",
)
self.parser.add_argument(
"--make-summary-multi-line",
action="store_true",
default=self.flargs_dct.get(
"make-summary-multi-line", "false"
).lower()
default=self.flargs_dct.get("make-summary-multi-line", "false").lower()
== "true",
help="add a newline before and after the summary of a one-line "
"docstring (default: False)",
)
self.parser.add_argument(
"--close-quotes-on-newline",
action="store_true",
default=self.flargs_dct.get(
"close-quotes-on-newline", "false"
).lower()
default=self.flargs_dct.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 "
Expand Down Expand Up @@ -275,8 +271,7 @@ def do_parse_arguments(self) -> None:
self.parser.add_argument(
"--non-strict",
action="store_true",
default=self.flargs_dct.get("non-strict", "false").lower()
== "true",
default=self.flargs_dct.get("non-strict", "false").lower() == "true",
help="don't strictly follow reST syntax to identify lists (see "
"issue #67) (default: False)",
)
Expand Down Expand Up @@ -309,9 +304,7 @@ def do_parse_arguments(self) -> None:

if self.args.length_range:
if self.args.length_range[0] <= 0:
self.parser.error(
"--docstring-length must be positive numbers"
)
self.parser.error("--docstring-length must be positive numbers")
if self.args.length_range[0] > self.args.length_range[1]:
self.parser.error(
"First value of --docstring-length should be less "
Expand All @@ -328,7 +321,11 @@ def _do_read_configuration_file(self) -> None:
fullpath, ext = os.path.splitext(self.config_file)
filename = os.path.basename(fullpath)

if ext == ".toml" and TOMLI_INSTALLED and filename == "pyproject":
if (
ext == ".toml"
and (TOMLI_INSTALLED or TOMLLIB_INSTALLED)
and filename == "pyproject"
):
self._do_read_toml_configuration()

if (ext == ".cfg" and filename == "setup") or (
Expand All @@ -339,13 +336,15 @@ def _do_read_configuration_file(self) -> None:
def _do_read_toml_configuration(self) -> None:
"""Load configuration information from a *.toml file."""
with open(self.config_file, "rb") as f:
config = tomli.load(f)
if TOMLI_INSTALLED:
config = tomli.load(f)
elif TOMLLIB_INSTALLED:
config = tomllib.load(f)

result = config.get("tool", {}).get("docformatter", None)
if result is not None:
self.flargs_dct = {
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()
}

def _do_read_parser_configuration(self) -> None:
Expand Down
Loading