import asyncio
-from json.decoder import JSONDecodeError
-import json
-from contextlib import contextmanager
-from datetime import datetime
-from enum import Enum
import io
-from multiprocessing import Manager, freeze_support
+import json
import os
-from pathlib import Path
-from pathspec.patterns.gitwildmatch import GitWildMatchPatternError
import platform
import re
import signal
import sys
import tokenize
import traceback
+from contextlib import contextmanager
+from dataclasses import replace
+from datetime import datetime
+from enum import Enum
+from json.decoder import JSONDecodeError
+from multiprocessing import Manager, freeze_support
+from pathlib import Path
from typing import (
TYPE_CHECKING,
Any,
import click
from click.core import ParameterSource
-from dataclasses import replace
from mypy_extensions import mypyc_attr
+from pathspec.patterns.gitwildmatch import GitWildMatchPatternError
-from black.const import DEFAULT_LINE_LENGTH, DEFAULT_INCLUDES, DEFAULT_EXCLUDES
-from black.const import STDIN_PLACEHOLDER
-from black.nodes import STARS, syms, is_simple_decorator_expression
-from black.nodes import is_string_token
-from black.lines import Line, EmptyLineTracker
-from black.linegen import transform_line, LineGenerator, LN
+from _black_version import version as __version__
+from black.cache import Cache, filter_cached, get_cache_info, read_cache, write_cache
from black.comments import normalize_fmt_off
-from black.mode import FUTURE_FLAG_TO_FEATURE, Mode, TargetVersion
-from black.mode import Feature, supports_feature, VERSION_TO_FEATURES
-from black.cache import read_cache, write_cache, get_cache_info, filter_cached, Cache
-from black.concurrency import cancel, shutdown, maybe_install_uvloop
-from black.output import dump_to_file, ipynb_diff, diff, color_diff, out, err
-from black.report import Report, Changed, NothingChanged
+from black.concurrency import cancel, maybe_install_uvloop, shutdown
+from black.const import (
+ DEFAULT_EXCLUDES,
+ DEFAULT_INCLUDES,
+ DEFAULT_LINE_LENGTH,
+ STDIN_PLACEHOLDER,
+)
from black.files import (
find_project_root,
find_pyproject_toml,
- parse_pyproject_toml,
find_user_pyproject_toml,
+ gen_python_files,
+ get_gitignore,
+ normalize_path_maybe_ignore,
+ parse_pyproject_toml,
+ wrap_stream_for_windows,
)
-from black.files import gen_python_files, get_gitignore, normalize_path_maybe_ignore
-from black.files import wrap_stream_for_windows
-from black.parsing import InvalidInput # noqa F401
-from black.parsing import lib2to3_parse, parse_ast, stringify_ast
from black.handle_ipynb_magics import (
- mask_cell,
- unmask_cell,
- remove_trailing_semicolon,
- put_trailing_semicolon_back,
- TRANSFORMED_MAGICS,
PYTHON_CELL_MAGICS,
+ TRANSFORMED_MAGICS,
jupyter_dependencies_are_installed,
+ mask_cell,
+ put_trailing_semicolon_back,
+ remove_trailing_semicolon,
+ unmask_cell,
)
-
-
-# lib2to3 fork
-from blib2to3.pytree import Node, Leaf
+from black.linegen import LN, LineGenerator, transform_line
+from black.lines import EmptyLineTracker, Line
+from black.mode import (
+ FUTURE_FLAG_TO_FEATURE,
+ VERSION_TO_FEATURES,
+ Feature,
+ Mode,
+ TargetVersion,
+ supports_feature,
+)
+from black.nodes import (
+ STARS,
+ is_number_token,
+ is_simple_decorator_expression,
+ is_string_token,
+ syms,
+)
+from black.output import color_diff, diff, dump_to_file, err, ipynb_diff, out
+from black.parsing import InvalidInput # noqa F401
+from black.parsing import lib2to3_parse, parse_ast, stringify_ast
+from black.report import Changed, NothingChanged, Report
+from black.trans import iter_fexpr_spans
from blib2to3.pgen2 import token
-
-from _black_version import version as __version__
+from blib2to3.pytree import Leaf, Node
if TYPE_CHECKING:
from concurrent.futures import Executor
workers: Optional[int],
) -> None:
"""Reformat multiple files using a ProcessPoolExecutor."""
- from concurrent.futures import Executor, ThreadPoolExecutor, ProcessPoolExecutor
+ from concurrent.futures import Executor, ProcessPoolExecutor, ThreadPoolExecutor
executor: Executor
- loop = asyncio.get_event_loop()
worker_count = workers if workers is not None else DEFAULT_WORKERS
if sys.platform == "win32":
# Work around https://bugs.python.org/issue26903
# any good due to the Global Interpreter Lock)
executor = ThreadPoolExecutor(max_workers=1)
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
try:
loop.run_until_complete(
schedule_formatting(
)
)
finally:
- shutdown(loop)
+ try:
+ shutdown(loop)
+ finally:
+ asyncio.set_event_loop(None)
if executor is not None:
executor.shutdown()
def _format_str_once(src_contents: str, *, mode: Mode) -> str:
src_node = lib2to3_parse(src_contents.lstrip(), mode.target_versions)
dst_contents = []
- future_imports = get_future_imports(src_node)
if mode.target_versions:
versions = mode.target_versions
else:
+ future_imports = get_future_imports(src_node)
versions = detect_target_versions(src_node, future_imports=future_imports)
normalize_fmt_off(src_node, preview=mode.preview)
Currently looking for:
- f-strings;
+ - self-documenting expressions in f-strings (f"{x=}");
- underscores in numeric literals;
- trailing commas after * or ** in function signatures and calls;
- positional only arguments in function signatures and lambdas;
value_head = n.value[:2]
if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
features.add(Feature.F_STRINGS)
+ if Feature.DEBUG_F_STRINGS not in features:
+ for span_beg, span_end in iter_fexpr_spans(n.value):
+ if n.value[span_beg : span_end - 1].rstrip().endswith("="):
+ features.add(Feature.DEBUG_F_STRINGS)
+ break
- elif n.type == token.NUMBER:
- assert isinstance(n, Leaf)
+ elif is_number_token(n):
if "_" in n.value:
features.add(Feature.NUMERIC_UNDERSCORES)