diff --git a/CHANGES.rst b/CHANGES.rst index 081b82478..2c4a937e1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -18,6 +18,9 @@ Removed ------- - **Backwards incompatible change:** Baseline linting support (``-L``/``--lint`` option) has been removed. Use the Graylint_ tool instead. +- In the Darker configuration file under ``[tool.darker]``, the Black configuration + options ``skip_string_normalization`` and ``skip_magic_trailing_comma`` are no longer + valid. Use ``[tool.black]`` instead. Fixed ----- diff --git a/README.rst b/README.rst index ecf3c331a..7acfc0d10 100644 --- a/README.rst +++ b/README.rst @@ -448,8 +448,9 @@ command line options *New in version 1.7.0:* The ``-f`` / ``--flynt`` command line option -*New in version 2.1.1:* In ``[tool.darker]``, deprecate the the Black options -``skip_string_normalization`` and ``skip_magic_trailing_comma`` +*New in version 3.0.0:* In ``[tool.darker]``, remove the the Black options +``skip_string_normalization`` and ``skip_magic_trailing_comma`` (previously deprecated +in version 2.1.1) *New in version 3.0.0:* Removed the ``-L`` / ``--lint`` functionality and moved it into the Graylint_ package. Also removed ``lint =``, ``skip_string_normalization =`` and diff --git a/constraints-oldest.txt b/constraints-oldest.txt index fc3d5b986..70d16afb2 100644 --- a/constraints-oldest.txt +++ b/constraints-oldest.txt @@ -20,4 +20,5 @@ ruamel.yaml==0.17.21 toml==0.10.0 twine==2.0.0 types-toml==0.10.4 +typing_extensions==4.0.1 wheel==0.21.0 diff --git a/pyproject.toml b/pyproject.toml index 3c30c6d83..4cf7b7edc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,9 +44,14 @@ select = ["ALL"] ignore = [ "A002", # builtin-argument-shadowing "ANN101", # Missing type annotation for `self` in method + "COM812", # Trailing comma missing "D203", # One blank line required before class docstring "D213", # Multi-line docstring summary should start at the second line "D400", # First line should end with a period (duplicates D415) + + # Remove these when support for Python 3.8 is dropped: + "UP006", # Use `xyz` instead of `Xyz` for type annotation + "UP007", # Use `X | Y` for type annotations ] [tool.ruff.lint.per-file-ignores] diff --git a/setup.cfg b/setup.cfg index b2c10bc6a..ca689f2fa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,6 +31,7 @@ install_requires = black>=22.3.0 darkgraylib~=2.0.1 toml>=0.10.0 + typing_extensions>=4.0.1 # NOTE: remember to keep `.github/workflows/python-package.yml` in sync # with the minimum required Python version python_requires = >=3.8 diff --git a/src/darker/__main__.py b/src/darker/__main__.py index 9d598379a..4669a510e 100644 --- a/src/darker/__main__.py +++ b/src/darker/__main__.py @@ -490,7 +490,7 @@ def main( # noqa: C901,PLR0912,PLR0915 # Make sure there aren't invalid option combinations after merging configuration and # command line options. OutputMode.validate_diff_stdout(args.diff, args.stdout) - OutputMode.validate_stdout_src(args.stdout, args.src, args.stdin_filename) + OutputMode.validate_stdout_src(args.src, args.stdin_filename, stdout=args.stdout) validate_config_output_mode(config) setup_logging(args.log_level) diff --git a/src/darker/command_line.py b/src/darker/command_line.py index 77972663d..fc72274c0 100644 --- a/src/darker/command_line.py +++ b/src/darker/command_line.py @@ -9,9 +9,15 @@ import darkgraylib.command_line from darker import help as hlp -from darker.config import DEPRECATED_CONFIG_OPTIONS, DarkerConfig, OutputMode +from darker.config import ( + DEPRECATED_CONFIG_OPTIONS, + REMOVED_CONFIG_OPTIONS, + DarkerConfig, + OutputMode, +) from darker.version import __version__ from darkgraylib.command_line import add_parser_argument +from darkgraylib.config import ConfigurationError def make_argument_parser(require_src: bool) -> ArgumentParser: @@ -82,10 +88,17 @@ def make_argument_parser(require_src: bool) -> ArgumentParser: def show_config_deprecations(config: DarkerConfig) -> None: """Show deprecation warnings for configuration keys from the config file.""" + removal_messages = { + REMOVED_CONFIG_OPTIONS[option] + for option in config + if option in REMOVED_CONFIG_OPTIONS + } + if removal_messages: + raise ConfigurationError(" ".join(sorted(removal_messages))) for option in DEPRECATED_CONFIG_OPTIONS & set(config): warnings.warn( f"The configuration option `{option}` in [tool.darker] is deprecated" - " and will be removed in Darker 3.0.", + " and will be removed in Darker 4.0.", DeprecationWarning, stacklevel=2, ) @@ -123,5 +136,5 @@ def parse_command_line( show_config_deprecations, ) OutputMode.validate_diff_stdout(args.diff, args.stdout) - OutputMode.validate_stdout_src(args.stdout, args.src, args.stdin_filename) + OutputMode.validate_stdout_src(args.src, args.stdin_filename, stdout=args.stdout) return args, effective_cfg, modified_cfg diff --git a/src/darker/config.py b/src/darker/config.py index 1324901b0..125d34c3a 100644 --- a/src/darker/config.py +++ b/src/darker/config.py @@ -1,16 +1,36 @@ """Load and save configuration in TOML format""" -from argparse import Namespace +from __future__ import annotations + +import sys from dataclasses import dataclass, field from pathlib import Path -from typing import Dict, List, Optional, Set, Union +from typing import TYPE_CHECKING, Dict, List, Union from darkgraylib.config import BaseConfig, ConfigurationError -UnvalidatedConfig = Dict[str, Union[List[str], str, bool, int]] +if TYPE_CHECKING: + from argparse import Namespace + +if sys.version_info < (3, 10): + from typing_extensions import TypeAlias +else: + from typing import TypeAlias + +UnvalidatedConfig: TypeAlias = Dict[str, Union[List[str], str, bool, int]] -DEPRECATED_CONFIG_OPTIONS = {"skip_string_normalization", "skip_magic_trailing_comma"} +REMOVED_CONFIG_OPTIONS = { + "skip_string_normalization": ( + "Please move the `skip_string_normalization` option from the [tool.darker]" + " section to the [tool.black] section in your `pyproject.toml` file." + ), + "skip_magic_trailing_comma": ( + "Please move the `skip_magic_trailing_comma` option from the [tool.darker]" + " section to the [tool.black] section in your `pyproject.toml` file." + ), +} +DEPRECATED_CONFIG_OPTIONS: set[str] = set() class DarkerConfig(BaseConfig, total=False): @@ -19,7 +39,7 @@ class DarkerConfig(BaseConfig, total=False): diff: bool check: bool isort: bool - lint: List[str] + lint: list[str] skip_string_normalization: bool skip_magic_trailing_comma: bool line_length: int @@ -53,7 +73,7 @@ def validate_diff_stdout(diff: bool, stdout: bool) -> None: @staticmethod def validate_stdout_src( - stdout: bool, src: List[str], stdin_filename: Optional[str] + src: list[str], stdin_filename: str | None, *, stdout: bool ) -> None: """Raise an exception in ``stdout`` mode if not exactly one input is provided""" if not stdout: @@ -92,6 +112,6 @@ class Exclusions: """ - black: Set[str] = field(default_factory=set) - isort: Set[str] = field(default_factory=set) - flynt: Set[str] = field(default_factory=set) + black: set[str] = field(default_factory=set) + isort: set[str] = field(default_factory=set) + flynt: set[str] = field(default_factory=set) diff --git a/src/darker/tests/test_command_line.py b/src/darker/tests/test_command_line.py index 698a0ba8d..49f9e3f42 100644 --- a/src/darker/tests/test_command_line.py +++ b/src/darker/tests/test_command_line.py @@ -262,20 +262,6 @@ def test_parse_command_line( " `lint =` option from your configuration file.", }, ), - dict( - config={"skip_string_normalization": True}, - expect_warn={ - "The configuration option `skip_string_normalization` in [tool.darker] is" - " deprecated and will be removed in Darker 3.0." - }, - ), - dict( - config={"skip_magic_trailing_comma": True}, - expect_warn={ - "The configuration option `skip_magic_trailing_comma` in [tool.darker] is" - " deprecated and will be removed in Darker 3.0." - }, - ), dict(config={"line_length": 88}, expect_warn=set()), dict(config={"target_version": "py37"}, expect_warn=set()), dict( @@ -285,18 +271,12 @@ def test_parse_command_line( "check": True, "isort": True, "lint": ["dummy"], - "skip_string_normalization": True, - "skip_magic_trailing_comma": True, "line_length": 88, "target_version": "py37", }, expect_warn={ "Baseline linting has been moved to the Graylint package. Please remove the" " `lint =` option from your configuration file.", - "The configuration option `skip_magic_trailing_comma` in [tool.darker] is" - " deprecated and will be removed in Darker 3.0.", - "The configuration option `skip_string_normalization` in [tool.darker] is" - " deprecated and will be removed in Darker 3.0.", }, ), ) @@ -326,6 +306,59 @@ def test_parse_command_line_unknown_conffile_option(tmp_path, monkeypatch): parse_command_line(["-"]) +@pytest.mark.kwparametrize( + dict(config={}), + dict(config={"diff": True}), + dict(config={"stdout": True}), + dict(config={"check": True}), + dict(config={"isort": True}), + dict(config={"lint": ["pylint"]}), + dict( + config={"skip_string_normalization": True}, + expect=ConfigurationError( + "Please move the `skip_string_normalization` option from the [tool.darker]" + " section to the [tool.black] section in your `pyproject.toml` file.", + ), + ), + dict( + config={"skip_magic_trailing_comma": True}, + expect=ConfigurationError( + "Please move the `skip_magic_trailing_comma` option from the [tool.darker]" + " section to the [tool.black] section in your `pyproject.toml` file.", + ), + ), + dict(config={"line_length": 88}), + dict(config={"target_version": "py37"}), + dict( + config={ + "diff": True, + "stdout": False, + "check": True, + "isort": True, + "lint": ["pylint"], + "skip_string_normalization": True, + "skip_magic_trailing_comma": True, + "line_length": 88, + "target_version": "py37", + }, + expect=ConfigurationError( + "Please move the `skip_magic_trailing_comma` option from the [tool.darker]" + " section to the [tool.black] section in your `pyproject.toml` file. Please" + " move the `skip_string_normalization` option from the [tool.darker]" + " section to the [tool.black] section in your `pyproject.toml` file.", + ), + ), + expect=None, +) +def test_parse_command_line_removed_option(tmp_path, monkeypatch, config, expect): + """`parse_command_line` fails if old removed options are used.""" + monkeypatch.chdir(tmp_path) + (tmp_path / "pyproject.toml").write_text(toml.dumps({"tool": {"darker": config}})) + with raises_if_exception(expect): + + parse_command_line(["-"]) + + def test_help_description_without_isort_package(capsys): """``darker --help`` description shows how to add ``isort`` if it's not present""" with isort_present(False): diff --git a/src/darker/tests/test_config.py b/src/darker/tests/test_config.py index 1470193ba..62cb7079c 100644 --- a/src/darker/tests/test_config.py +++ b/src/darker/tests/test_config.py @@ -107,8 +107,7 @@ def test_output_mode_validate_stdout_src( Path("first.py").touch() Path("second.py").touch() with raises_if_exception(expect): - - OutputMode.validate_stdout_src(stdout, src, stdin_filename) + OutputMode.validate_stdout_src(src, stdin_filename, stdout=stdout) @pytest.mark.kwparametrize(