Skip to content

Commit

Permalink
Rebase _Pyink_ to _Black_ v23.9.1.
Browse files Browse the repository at this point in the history
Notably the the preview style for "dummy implementations" is disabled in Pyink as it doesn't play well with our linter (yet).

PiperOrigin-RevId: 573023762
  • Loading branch information
yilei authored and copybara-github committed Oct 16, 2023
1 parent a2eadfb commit 3fe4f81
Show file tree
Hide file tree
Showing 40 changed files with 1,347 additions and 776 deletions.
284 changes: 152 additions & 132 deletions patches/pyink.patch

Large diffs are not rendered by default.

17 changes: 9 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ build-backend = "hatchling.build"
name = "pyink"
description = "Pyink is a python formatter, forked from Black with slightly different behavior."
license = { text = "MIT" }
requires-python = ">=3.7"
requires-python = ">=3.8"
readme = "README.md"
authors = [{name = "The Pyink Maintainers", email = "[email protected]"}]
classifiers = [
Expand All @@ -26,11 +26,11 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
]
Expand All @@ -41,9 +41,8 @@ dependencies = [
"pathspec>=0.9.0",
"platformdirs>=2",
"tomli>=1.1.0; python_version < '3.11'",
"typed-ast>=1.4.2; python_version < '3.8' and implementation_name == 'cpython'",
"typing_extensions>=3.10.0.0; python_version < '3.10'",
"black>=23.3.0",
"typing_extensions>=4.0.1; python_version < '3.11'",
"black>=23.9.1",
]
dynamic = ["version"]

Expand Down Expand Up @@ -93,10 +92,12 @@ filterwarnings = [
# this is mitigated by a try/catch in https://github.com/psf/black/pull/3198/
# this ignore can be removed when support for aiohttp 3.x is dropped.
'''ignore:Middleware decorator is deprecated since 4\.0 and its behaviour is default, you can simply remove this decorator:DeprecationWarning''',
# this is mitigated by https://github.com/python/cpython/issues/79071 in python 3.8+
# this ignore can be removed when support for 3.7 is dropped.
'''ignore:Bare functions are deprecated, use async ones:DeprecationWarning''',
# aiohttp is using deprecated cgi modules - Safe to remove when fixed:
# https://github.com/aio-libs/aiohttp/issues/6905
'''ignore:'cgi' is deprecated and slated for removal in Python 3.13:DeprecationWarning''',
# Work around https://github.com/pytest-dev/pytest/issues/10977 for Python 3.12
'''ignore:(Attribute s|Attribute n|ast.Str|ast.Bytes|ast.NameConstant|ast.Num) is deprecated and will be removed in Python 3.14:DeprecationWarning''',
# Will be fixed with aiohttp 3.9.0
# https://github.com/aio-libs/aiohttp/pull/7302
"ignore:datetime.*utcfromtimestamp\\(\\) is deprecated and scheduled for removal:DeprecationWarning",
]
147 changes: 58 additions & 89 deletions src/pyink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import traceback
from contextlib import contextmanager
from dataclasses import replace
from datetime import datetime
from datetime import datetime, timezone
from enum import Enum
from json.decoder import JSONDecodeError
from pathlib import Path
Expand Down Expand Up @@ -35,7 +35,7 @@
from pathspec.patterns.gitwildmatch import GitWildMatchPatternError

from _pyink_version import version as __version__
from pyink.cache import Cache, get_cache_info, read_cache, write_cache
from pyink.cache import Cache
from pyink.comments import normalize_fmt_off
from pyink.const import (
DEFAULT_EXCLUDES,
Expand Down Expand Up @@ -64,15 +64,9 @@
)
from pyink.linegen import LN, LineGenerator, transform_line
from pyink.lines import EmptyLineTracker, LinesBlock
from pyink.mode import (
FUTURE_FLAG_TO_FEATURE,
VERSION_TO_FEATURES,
Feature,
Mode,
QuoteStyle,
TargetVersion,
supports_feature,
)
from pyink.mode import FUTURE_FLAG_TO_FEATURE, VERSION_TO_FEATURES, Feature
from pyink.mode import Mode as Mode # re-exported
from pyink.mode import QuoteStyle, TargetVersion, supports_feature
from pyink.nodes import (
STARS,
is_number_token,
Expand Down Expand Up @@ -131,7 +125,9 @@ def read_pyproject_toml(
otherwise.
"""
if not value:
value = find_pyproject_toml(ctx.params.get("src", ()))
value = find_pyproject_toml(
ctx.params.get("src", ()), ctx.params.get("stdin_filename", None)
)
if value is None:
return None

Expand Down Expand Up @@ -159,6 +155,16 @@ def read_pyproject_toml(
"target-version", "Config key target-version must be a list"
)

exclude = config.get("exclude")
if exclude is not None and not isinstance(exclude, str):
raise click.BadOptionUsage("exclude", "Config key exclude must be a string")

extend_exclude = config.get("extend_exclude")
if extend_exclude is not None and not isinstance(extend_exclude, str):
raise click.BadOptionUsage(
"extend-exclude", "Config key extend-exclude must be a string"
)

default_map: Dict[str, Any] = {}
if ctx.default_map:
default_map.update(ctx.default_map)
Expand Down Expand Up @@ -401,6 +407,7 @@ def validate_regex(
@click.option(
"--stdin-filename",
type=str,
is_eager=True,
help=(
"The name of the file when passing it through stdin. Useful to make "
"sure Black will respect --force-exclude option on some "
Expand All @@ -412,7 +419,10 @@ def validate_regex(
"--workers",
type=click.IntRange(min=1),
default=None,
help="Number of parallel workers [default: number of CPUs in the system]",
help=(
"Number of parallel workers [default: PYINK_NUM_WORKERS environment variable "
"or number of CPUs in the system]"
),
)
@click.option(
"-q",
Expand Down Expand Up @@ -521,26 +531,6 @@ def main( # noqa: C901
fg="blue",
)

normalized = [
(
(source, source)
if source == "-"
else (normalize_path_maybe_ignore(Path(source), root), source)
)
for source in src
]
srcs_string = ", ".join(
[
(
f'"{_norm}"'
if _norm
else f'\033[31m"{source} (skipping - invalid)"\033[34m'
)
for _norm, source in normalized
]
)
out(f"Sources to be formatted: {srcs_string}", fg="blue")

if config:
config_source = ctx.get_parameter_source("config")
user_level_config = str(find_user_pyproject_toml())
Expand Down Expand Up @@ -636,9 +626,10 @@ def main( # noqa: C901
content=code, fast=fast, write_back=write_back, mode=mode, report=report
)
else:
assert root is not None # root is only None if code is not None
try:
sources = get_sources(
ctx=ctx,
root=root,
src=src,
quiet=quiet,
verbose=verbose,
Expand Down Expand Up @@ -692,7 +683,7 @@ def main( # noqa: C901

def get_sources(
*,
ctx: click.Context,
root: Path,
src: Tuple[str, ...],
quiet: bool,
verbose: bool,
Expand All @@ -705,7 +696,6 @@ def get_sources(
) -> Set[Path]:
"""Compute the set of files to be formatted."""
sources: Set[Path] = set()
root = ctx.obj["root"]

using_default_exclude = exclude is None
exclude = re_compile_maybe_verbose(DEFAULT_EXCLUDES) if exclude is None else exclude
Expand All @@ -721,9 +711,15 @@ def get_sources(
is_stdin = False

if is_stdin or p.is_file():
normalized_path = normalize_path_maybe_ignore(p, ctx.obj["root"], report)
normalized_path: Optional[str] = normalize_path_maybe_ignore(
p, root, report
)
if normalized_path is None:
if verbose:
out(f'Skipping invalid source: "{normalized_path}"', fg="red")
continue
if verbose:
out(f'Found input source: "{normalized_path}"', fg="blue")

normalized_path = "/" + normalized_path
# Hard-exclude any files that matches the `--force-exclude` regex.
Expand All @@ -739,13 +735,18 @@ def get_sources(
p = Path(f"{STDIN_PLACEHOLDER}{str(p)}")

if p.suffix == ".ipynb" and not jupyter_dependencies_are_installed(
verbose=verbose, quiet=quiet
warn=verbose or not quiet
):
continue

sources.add(p)
elif p.is_dir():
p = root / normalize_path_maybe_ignore(p, ctx.obj["root"], report)
p_relative = normalize_path_maybe_ignore(p, root, report)
assert p_relative is not None
p = root / p_relative
if verbose:
out(f'Found input source directory: "{p}"', fg="blue")

if using_default_exclude:
gitignore = {
root: root_gitignore,
Expand All @@ -754,7 +755,7 @@ def get_sources(
sources.update(
gen_python_files(
p.iterdir(),
ctx.obj["root"],
root,
include,
exclude,
extend_exclude,
Expand All @@ -766,9 +767,12 @@ def get_sources(
)
)
elif s == "-":
if verbose:
out("Found input source stdin", fg="blue")
sources.add(p)
else:
err(f"invalid path: {s}")

return sources


Expand Down Expand Up @@ -848,12 +852,9 @@ def reformat_one(
):
changed = Changed.YES
else:
cache: Cache = {}
cache = Cache.read(mode)
if write_back not in (WriteBack.DIFF, WriteBack.COLOR_DIFF):
cache = read_cache(mode)
res_src = src.resolve()
res_src_s = str(res_src)
if res_src_s in cache and cache[res_src_s] == get_cache_info(res_src):
if not cache.is_changed(src):
changed = Changed.CACHED
if changed is not Changed.CACHED and format_file_in_place(
src, fast=fast, write_back=write_back, mode=mode, lines=lines
Expand All @@ -862,7 +863,7 @@ def reformat_one(
if (write_back is WriteBack.YES and changed is not Changed.CACHED) or (
write_back is WriteBack.CHECK and changed is Changed.NO
):
write_cache(cache, [src], mode)
cache.write([src])
report.done(src, changed)
except Exception as exc:
if report.verbose:
Expand Down Expand Up @@ -890,7 +891,7 @@ def format_file_in_place(
elif src.suffix == ".ipynb":
mode = replace(mode, is_ipynb=True)

then = datetime.utcfromtimestamp(src.stat().st_mtime)
then = datetime.fromtimestamp(src.stat().st_mtime, timezone.utc)
header = b""
with open(src, "rb") as buf:
if mode.skip_source_first_line:
Expand All @@ -913,9 +914,9 @@ def format_file_in_place(
with open(src, "w", encoding=encoding, newline=newline) as f:
f.write(dst_contents)
elif write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF):
now = datetime.utcnow()
src_name = f"{src}\t{then} +0000"
dst_name = f"{src}\t{now} +0000"
now = datetime.now(timezone.utc)
src_name = f"{src}\t{then}"
dst_name = f"{src}\t{now}"
if mode.is_ipynb:
diff_contents = ipynb_diff(src_contents, dst_contents, src_name, dst_name)
else:
Expand Down Expand Up @@ -954,7 +955,7 @@ def format_stdin_to_stdout(
write a diff to stdout. The `mode` argument is passed to
:func:`format_file_contents`.
"""
then = datetime.utcnow()
then = datetime.now(timezone.utc)

if content is None:
src, encoding, newline = decode_bytes(sys.stdin.buffer.read())
Expand All @@ -979,9 +980,9 @@ def format_stdin_to_stdout(
dst += "\n"
f.write(dst)
elif write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF):
now = datetime.utcnow()
src_name = f"STDIN\t{then} +0000"
dst_name = f"STDOUT\t{now} +0000"
now = datetime.now(timezone.utc)
src_name = f"STDIN\t{then}"
dst_name = f"STDOUT\t{now}"
d = diff(src, dst, src_name, dst_name)
if write_back == WriteBack.COLOR_DIFF:
d = color_diff(d)
Expand Down Expand Up @@ -1396,6 +1397,9 @@ def get_features_used( # noqa: C901
):
features.add(Feature.VARIADIC_GENERICS)

elif n.type in (syms.type_stmt, syms.typeparams):
features.add(Feature.TYPE_PARAMS)

return features


Expand Down Expand Up @@ -1528,40 +1532,6 @@ def nullcontext() -> Iterator[None]:
yield


def patch_click() -> None:
"""Make Click not crash on Python 3.6 with LANG=C.
On certain misconfigured environments, Python 3 selects the ASCII encoding as the
default which restricts paths that it can access during the lifetime of the
application. Click refuses to work in this scenario by raising a RuntimeError.
In case of Black the likelihood that non-ASCII characters are going to be used in
file paths is minimal since it's Python source code. Moreover, this crash was
spurious on Python 3.7 thanks to PEP 538 and PEP 540.
"""
modules: List[Any] = []
try:
from click import core
except ImportError:
pass
else:
modules.append(core)
try:
# Removed in Click 8.1.0 and newer; we keep this around for users who have
# older versions installed.
from click import _unicodefun # type: ignore
except ImportError:
pass
else:
modules.append(_unicodefun)

for module in modules:
if hasattr(module, "_verify_python3_env"):
module._verify_python3_env = lambda: None
if hasattr(module, "_verify_python_env"):
module._verify_python_env = lambda: None


def patched_main() -> None:
# PyInstaller patches multiprocessing to need freeze_support() even in non-Windows
# environments so just assume we always need to call it if frozen.
Expand All @@ -1570,7 +1540,6 @@ def patched_main() -> None:

freeze_support()

patch_click()
main()


Expand Down
8 changes: 1 addition & 7 deletions src/pyink/_width_table.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
# Generated by make_width_table.py
# wcwidth 0.2.6
# Unicode 15.0.0
import sys
from typing import List, Tuple

if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final
from typing import Final, List, Tuple

WIDTH_TABLE: Final[Tuple[Tuple[int, int, int], ...]] = (
(0, 0, 0),
Expand Down
Loading

0 comments on commit 3fe4f81

Please sign in to comment.