Skip to content

Commit

Permalink
FEAT: automatically update black configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
redeboer authored and Remco de Boer committed Jul 1, 2023
1 parent deb8222 commit c63697a
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 183 deletions.
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ exclude = '''
include = '\.pyi?$'
preview = true
target-version = [
'py310',
'py311',
'py36',
'py37',
'py38',
'py39',
"py310",
"py311",
"py36",
"py37",
"py38",
"py39",
]

[tool.isort]
Expand Down
104 changes: 44 additions & 60 deletions src/repoma/check_dev_files/black.py
Original file line number Diff line number Diff line change
@@ -1,92 +1,76 @@
"""Check :file:`pyproject.toml` black config."""
from textwrap import dedent
from typing import Optional
"""Update :file:`pyproject.toml` black configuration."""

from ruamel.yaml.comments import CommentedMap
from tomlkit.items import Table

from repoma.errors import PrecommitError
from repoma.utilities import CONFIG_PATH, natural_sorting
from repoma.utilities import CONFIG_PATH
from repoma.utilities.executor import Executor
from repoma.utilities.precommit import (
find_repo,
load_round_trip_precommit_config,
update_precommit_hook,
update_single_hook_precommit_repo,
)
from repoma.utilities.pyproject import get_sub_table, load_pyproject, write_pyproject
from repoma.utilities.pyproject import (
get_sub_table,
load_pyproject,
to_toml_array,
write_pyproject,
)
from repoma.utilities.setup_cfg import get_supported_python_versions


def main() -> None:
if not CONFIG_PATH.pyproject.exists():
return
config = _load_black_config()
executor = Executor()
executor(_check_line_length, config)
executor(_check_activate_preview, config)
executor(_check_option_ordering, config)
executor(_check_target_versions, config)
executor(_remove_outdated_settings)
executor(_update_black_settings)
executor(_update_nbqa_settings)
executor(_update_precommit_repo)
executor(_update_precommit_nbqa_hook)
executor.finalize()


def _load_black_config(content: Optional[str] = None) -> Table:
config = load_pyproject(content)
return config.get("tool", {}).get("black", {})


def _check_activate_preview(config: dict) -> None:
expected_option = "preview"
if config.get(expected_option) is not True:
raise PrecommitError(dedent(f"""
An option in pyproject.toml is wrong or missing. Should be:
[tool.black]
{expected_option} = true
""").strip())


def _check_line_length(config: dict) -> None:
if config.get("line-length") is not None:
raise PrecommitError(
"pyproject.toml should not specify a line-length (default to 88)."
def _remove_outdated_settings() -> None:
pyproject = load_pyproject()
settings = get_sub_table(pyproject, "tool.black", create=True)
forbidden_options = ("line-length",)
removed_options = set()
for option in forbidden_options:
if option in settings:
removed_options.add(option)
settings.remove(option)
if removed_options:
write_pyproject(pyproject)
msg = (
f"Removed {', '.join(sorted(removed_options))} option from black"
f" configuration in {CONFIG_PATH.pyproject}"
)
raise PrecommitError(msg)


def _check_option_ordering(config: dict) -> None:
options = list(config)
sorted_options = sorted(config, key=natural_sorting)
if sorted_options != options:
error_message = dedent("""
Options in pyproject.toml should be alphabetically sorted:
[tool.black]
""").strip()
for option in sorted_options:
error_message += f"\n{option} = ..."
raise PrecommitError(error_message)
def _update_black_settings() -> None:
pyproject = load_pyproject()
settings = get_sub_table(pyproject, "tool.black", create=True)
versions = get_supported_python_versions()
target_version = to_toml_array(sorted("py" + v.replace(".", "") for v in versions))
minimal_settings = {
"preview": True,
"target-version": target_version,
}
if not __complies(settings, minimal_settings):
settings.update(minimal_settings)
write_pyproject(pyproject)
msg = f"Updated black configuration in {CONFIG_PATH.pyproject}"
raise PrecommitError(msg)


def _check_target_versions(config: dict) -> None:
target_versions = config.get("target-version", [])
supported_python_versions = get_supported_python_versions()
expected_target_versions = sorted(
"py" + s.replace(".", "") for s in supported_python_versions
)
if target_versions != expected_target_versions:
error_message = dedent("""
Black target versions in pyproject.toml should be as follows:
[tool.black]
target-version = [
""").strip()
for version in expected_target_versions:
error_message += f"\n '{version}',"
error_message += "\n]"
raise PrecommitError(error_message)
def __complies(settings: dict, minimal_settings: dict) -> bool:
for key, value in minimal_settings.items():
if settings.get(key) != value:
return False
return True


def _update_precommit_repo() -> None:
Expand Down
12 changes: 10 additions & 2 deletions src/repoma/utilities/pyproject.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Tools for loading, inspecting, and updating :code:`pyproject.toml`."""
import os
from typing import Any, Optional
from typing import Any, Iterable, Optional

import tomlkit
from tomlkit.container import Container
from tomlkit.items import Table
from tomlkit.items import Array, Table
from tomlkit.toml_document import TOMLDocument

from repoma.utilities import CONFIG_PATH
Expand Down Expand Up @@ -36,3 +36,11 @@ def write_pyproject(config: TOMLDocument) -> None:
src = tomlkit.dumps(config, sort_keys=True)
with open(CONFIG_PATH.pyproject, "w") as stream:
stream.write(src)


def to_toml_array(items: Iterable[Any]) -> Array:
array = tomlkit.array()
array.extend(items)
if len(array) > 1:
array.multiline(True)
return array
115 changes: 0 additions & 115 deletions tests/check_dev_files/test_black.py

This file was deleted.

0 comments on commit c63697a

Please sign in to comment.