From ecd7c258c024b9d7dfb7b461d584e53d44965a39 Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sat, 25 Mar 2023 20:24:28 +0200 Subject: [PATCH 1/4] Hide Flynt ERROR log output It produces those e.g. when `.format()` contains backslashes. The process still finishes and converts other parts of the code, so we can just ignore these. --- src/darker/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/darker/__main__.py b/src/darker/__main__.py index 3af26d35a..937343124 100644 --- a/src/darker/__main__.py +++ b/src/darker/__main__.py @@ -488,8 +488,9 @@ def main( # pylint: disable=too-many-locals,too-many-branches,too-many-statemen validate_config_output_mode(config) setup_logging(args.log_level) - # Make sure we don't get excessive debug log output from Black + # Make sure we don't get excessive debug log output from Black and Flynt logging.getLogger("blib2to3.pgen2.driver").setLevel(logging.WARNING) + logging.getLogger("flynt.transform.transform").setLevel(logging.CRITICAL) show_config_if_debug(config, config_nondefault, args.log_level) From d801dcaaee2144424f08d1168ef81ecaf1168c2f Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sat, 25 Mar 2023 20:25:58 +0200 Subject: [PATCH 2/4] Read Flynt>=0.78 config from `pyproject.toml` --- src/darker/fstring.py | 61 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/darker/fstring.py b/src/darker/fstring.py index 233500a2a..48d2a03fc 100644 --- a/src/darker/fstring.py +++ b/src/darker/fstring.py @@ -2,7 +2,7 @@ import logging from pathlib import Path -from typing import Any +from typing import Any, Optional from darker.exceptions import MissingPackageError from darker.git import EditedLinenumsDiffer @@ -10,11 +10,17 @@ try: import flynt + from flynt.pyproject_finder import find_pyproject_toml, parse_pyproject_toml flynt_fstringify_code_by_line = flynt.process.fstringify_code_by_line + if hasattr(flynt.state, "State"): + State = flynt.state.State + else: + State = None except ImportError: # `flynt` is an optional dependency. Prevent the `ImportError` if it's missing. flynt = None + State = None def flynt_fstringify_code_by_line( # type: ignore[misc] *args: Any, **kwargs: Any @@ -42,9 +48,9 @@ def apply_flynt( responsibility of the caller to filter output to modified lines only. :param content: The contents of the Python source code file to sort imports in - :param src: The relative path to the file. This must be the actual path in the - repository, which may differ from the path given on the command line in - case of VSCode temporary files. + :param src: The path to the file relative to the repository root. This must be the + actual path in the repository, which may differ from the path given on + the command line in case of VSCode temporary files. :param edited_linenums_differ: Helper for finding out which lines were edited :return: Original Python source file contents with modifications from ``flynt`` @@ -56,18 +62,59 @@ def apply_flynt( ) if not edited_linenums: return content - return _call_flynt_fstringify(content) + state = _get_flynt_configuration(edited_linenums_differ.root / src) + return _call_flynt_fstringify(content, state) -def _call_flynt_fstringify(content: TextDocument) -> TextDocument: +def _get_flynt_configuration(src: Path) -> Optional[State]: + """Read ``pyproject.toml`` Flynt configuration for the given Python file + + :param src: The absolute path to the Python file to run Flynt on. This must be the + actual path in the repository, which may differ from the path given on + the command line in case of VSCode temporary files. + :return: A ``flynt`` configuration, or ``None`` for Flynt versions <0.78 + + """ + if State is None: # flynt<0.78 + return None + state = State(quiet=True) + toml_file = find_pyproject_toml((str(src),)) + if toml_file: + cfg = parse_pyproject_toml(toml_file) + mapping = { + # (state attribute name, `pyproject.toml` option) + ("aggressive", "aggressive"), + ("len_limit", "line_length"), + ("multiline", "not no_multiline"), + ("transform_concat", "transform_concats"), + ("transform_format", "transform_format"), + ("transform_join", "transform_joins"), + ("transform_percent", "transform_percent"), + } + for state_attr, cfg_option in mapping: + if cfg_option not in cfg: + continue + if cfg_option.startswith("not "): + value = not cfg[cfg_option[4:]] + else: + value = cfg[cfg_option] + setattr(state, state_attr, value) + return state + + +def _call_flynt_fstringify( + content: TextDocument, state: Optional[State] +) -> TextDocument: """Call ``flynt.process.fstringify_code_by_line()``, return result `TextDocument` :param content: The contents of the Python source code file to fstringify + :param state: The ``flynt`` configuration to use, or ``None`` for ``flynt<0.78`` :return: Original Python source code contents with modifications from ``flynt`` """ logger.debug("flynt.process.fstringify_code_by_line(code=...)") - result, _ = flynt_fstringify_code_by_line(content.string) + args = () if state is None else (state,) # `()` for flynt<0.78, (state,) for >=0.78 + result, _ = flynt_fstringify_code_by_line(content.string, *args) return TextDocument.from_str( result, encoding=content.encoding, From d41630b5c22b1e1444ac780805751a22cbbe1d4d Mon Sep 17 00:00:00 2001 From: Bao Trinh Date: Wed, 19 Jul 2023 06:36:09 -0500 Subject: [PATCH 3/4] flynt-v1.0.0 compatibility --- setup.cfg | 4 ++-- src/darker/fstring.py | 30 ++++++++++++++++++------------ src/darker/tests/helpers.py | 5 +++-- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/setup.cfg b/setup.cfg index f0cee3ed6..f946af3e2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,7 +44,7 @@ console_scripts = [options.extras_require] flynt = - flynt>=0.76,<0.78 + flynt>=0.76 isort = isort>=5.0.1 color = @@ -55,7 +55,7 @@ test = black>=22.3.0 cryptography>=3.3.2 # through twine, fixes CVE-2020-36242 defusedxml>=0.7.1 - flynt>=0.76,<0.78 + flynt>=0.76 isort>=5.0.1 mypy>=0.990 pathspec # to test `gen_python_files` in `test_black_diff.py` diff --git a/src/darker/fstring.py b/src/darker/fstring.py index 48d2a03fc..8e0cb2ade 100644 --- a/src/darker/fstring.py +++ b/src/darker/fstring.py @@ -10,21 +10,27 @@ try: import flynt - from flynt.pyproject_finder import find_pyproject_toml, parse_pyproject_toml - flynt_fstringify_code_by_line = flynt.process.fstringify_code_by_line - if hasattr(flynt.state, "State"): - State = flynt.state.State + flynt_version = tuple(map(int, flynt.__version__.split("."))) + if flynt_version >= (0, 78): + from flynt.state import State else: State = None + if flynt_version < (1, 0, 0): + from flynt.process import fstringify_code_by_line + from flynt.pyproject_finder import find_pyproject_toml, parse_pyproject_toml + else: + from flynt.code_editor import fstringify_code_by_line + from flynt.utils.pyproject_finder import ( + find_pyproject_toml, + parse_pyproject_toml, + ) except ImportError: # `flynt` is an optional dependency. Prevent the `ImportError` if it's missing. flynt = None State = None - def flynt_fstringify_code_by_line( # type: ignore[misc] - *args: Any, **kwargs: Any - ) -> str: + def fstringify_code_by_line(*args: Any, **kwargs: Any) -> str: # type: ignore[misc] """Fake `flynt.fstringify_code_by_line()` to use when `flynt` isn't installed""" raise MissingPackageError( "No module named 'flynt'. Please install the 'flynt' package before using" @@ -66,7 +72,7 @@ def apply_flynt( return _call_flynt_fstringify(content, state) -def _get_flynt_configuration(src: Path) -> Optional[State]: +def _get_flynt_configuration(src: Path) -> Optional[State]: # type: ignore[no-any-unimported] """Read ``pyproject.toml`` Flynt configuration for the given Python file :param src: The absolute path to the Python file to run Flynt on. This must be the @@ -102,19 +108,19 @@ def _get_flynt_configuration(src: Path) -> Optional[State]: return state -def _call_flynt_fstringify( +def _call_flynt_fstringify( # type: ignore[no-any-unimported] content: TextDocument, state: Optional[State] ) -> TextDocument: - """Call ``flynt.process.fstringify_code_by_line()``, return result `TextDocument` + """Call ``flynt.code_editor.fstringify_code_by_line()``, return result `TextDocument` :param content: The contents of the Python source code file to fstringify :param state: The ``flynt`` configuration to use, or ``None`` for ``flynt<0.78`` :return: Original Python source code contents with modifications from ``flynt`` """ - logger.debug("flynt.process.fstringify_code_by_line(code=...)") + logger.debug("flynt.code_editor.fstringify_code_by_line(code=...)") args = () if state is None else (state,) # `()` for flynt<0.78, (state,) for >=0.78 - result, _ = flynt_fstringify_code_by_line(content.string, *args) + result, _ = fstringify_code_by_line(content.string, *args) return TextDocument.from_str( result, encoding=content.encoding, diff --git a/src/darker/tests/helpers.py b/src/darker/tests/helpers.py index be10b29fa..39fbcc314 100644 --- a/src/darker/tests/helpers.py +++ b/src/darker/tests/helpers.py @@ -39,6 +39,7 @@ def flynt_present(present: bool) -> Generator[None, None, None]: if present: # dummy module and function required by `fstring`: # pylint: disable=no-member - fake_flynt_module.process = ModuleType("process") # type: ignore - fake_flynt_module.process.fstringify_code_by_line = None # type: ignore + fake_flynt_module.__version__ = "1.0.0" # type: ignore + fake_flynt_module.code_editor = ModuleType("process") # type: ignore + fake_flynt_module.code_editor.fstringify_code_by_line = None # type: ignore yield From c358893f1d214554614f50e4494cc21ad39b50a7 Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sat, 5 Aug 2023 22:27:29 +0300 Subject: [PATCH 4/4] Satisfy linters --- src/darker/fstring.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/darker/fstring.py b/src/darker/fstring.py index 8e0cb2ade..867cac4ec 100644 --- a/src/darker/fstring.py +++ b/src/darker/fstring.py @@ -15,7 +15,7 @@ if flynt_version >= (0, 78): from flynt.state import State else: - State = None + State = None # pylint: disable=invalid-name if flynt_version < (1, 0, 0): from flynt.process import fstringify_code_by_line from flynt.pyproject_finder import find_pyproject_toml, parse_pyproject_toml @@ -72,7 +72,9 @@ def apply_flynt( return _call_flynt_fstringify(content, state) -def _get_flynt_configuration(src: Path) -> Optional[State]: # type: ignore[no-any-unimported] +def _get_flynt_configuration( # type: ignore[no-any-unimported] + src: Path, +) -> Optional[State]: """Read ``pyproject.toml`` Flynt configuration for the given Python file :param src: The absolute path to the Python file to run Flynt on. This must be the @@ -111,7 +113,7 @@ def _get_flynt_configuration(src: Path) -> Optional[State]: # type: ignore[no-a def _call_flynt_fstringify( # type: ignore[no-any-unimported] content: TextDocument, state: Optional[State] ) -> TextDocument: - """Call ``flynt.code_editor.fstringify_code_by_line()``, return result `TextDocument` + """Call ``flynt.code_editor.fstringify_code_by_line()``, return ``TextDocument`` :param content: The contents of the Python source code file to fstringify :param state: The ``flynt`` configuration to use, or ``None`` for ``flynt<0.78``