deadcode 2.2.2__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- black/action/main.py +176 -0
- black/docs/conf.py +218 -0
- black/gallery/gallery.py +294 -0
- black/profiling/dict_big.py +8001 -0
- black/profiling/dict_huge.py +41440 -0
- black/profiling/list_big.py +4000 -0
- black/profiling/list_huge.py +22431 -0
- black/profiling/mix_big.py +1002 -0
- black/profiling/mix_huge.py +7692 -0
- black/profiling/mix_small.py +102 -0
- black/scripts/__init__.py +0 -0
- black/scripts/check_pre_commit_rev_in_example.py +54 -0
- black/scripts/check_version_in_basics_example.py +48 -0
- black/scripts/diff_shades_gha_helper.py +236 -0
- black/scripts/fuzz.py +92 -0
- black/scripts/generate_schema.py +74 -0
- black/scripts/make_width_table.py +66 -0
- black/scripts/migrate-black.py +96 -0
- black/scripts/release.py +245 -0
- black/scripts/release_tests.py +69 -0
- black/src/black/__init__.py +1605 -0
- black/src/black/__main__.py +3 -0
- black/src/black/_width_table.py +478 -0
- black/src/black/brackets.py +382 -0
- black/src/black/cache.py +150 -0
- black/src/black/comments.py +415 -0
- black/src/black/concurrency.py +190 -0
- black/src/black/const.py +4 -0
- black/src/black/debug.py +54 -0
- black/src/black/files.py +433 -0
- black/src/black/handle_ipynb_magics.py +452 -0
- black/src/black/linegen.py +1745 -0
- black/src/black/lines.py +1073 -0
- black/src/black/mode.py +265 -0
- black/src/black/nodes.py +1007 -0
- black/src/black/numerics.py +61 -0
- black/src/black/output.py +122 -0
- black/src/black/parsing.py +244 -0
- black/src/black/ranges.py +521 -0
- black/src/black/report.py +107 -0
- black/src/black/resources/__init__.py +0 -0
- black/src/black/rusty.py +28 -0
- black/src/black/schema.py +20 -0
- black/src/black/strings.py +325 -0
- black/src/black/trans.py +2534 -0
- black/src/blackd/__init__.py +259 -0
- black/src/blackd/__main__.py +3 -0
- black/src/blackd/middlewares.py +45 -0
- black/src/blib2to3/__init__.py +1 -0
- black/src/blib2to3/pgen2/__init__.py +4 -0
- black/src/blib2to3/pgen2/conv.py +256 -0
- black/src/blib2to3/pgen2/driver.py +316 -0
- black/src/blib2to3/pgen2/grammar.py +227 -0
- black/src/blib2to3/pgen2/literals.py +66 -0
- black/src/blib2to3/pgen2/parse.py +411 -0
- black/src/blib2to3/pgen2/pgen.py +428 -0
- black/src/blib2to3/pgen2/token.py +88 -0
- black/src/blib2to3/pgen2/tokenize.py +698 -0
- black/src/blib2to3/pygram.py +200 -0
- black/src/blib2to3/pytree.py +986 -0
- black/tests/__init__.py +0 -0
- black/tests/conftest.py +28 -0
- black/tests/data/cases/allow_empty_first_line.py +166 -0
- black/tests/data/cases/async_stmts.py +27 -0
- black/tests/data/cases/attribute_access_on_number_literals.py +47 -0
- black/tests/data/cases/beginning_backslash.py +12 -0
- black/tests/data/cases/bracketmatch.py +15 -0
- black/tests/data/cases/bytes_docstring.py +34 -0
- black/tests/data/cases/class_blank_parentheses.py +59 -0
- black/tests/data/cases/class_methods_new_line.py +270 -0
- black/tests/data/cases/collections.py +174 -0
- black/tests/data/cases/comment_after_escaped_newline.py +18 -0
- black/tests/data/cases/comment_type_hint.py +3 -0
- black/tests/data/cases/comments.py +96 -0
- black/tests/data/cases/comments2.py +344 -0
- black/tests/data/cases/comments3.py +48 -0
- black/tests/data/cases/comments4.py +94 -0
- black/tests/data/cases/comments5.py +70 -0
- black/tests/data/cases/comments6.py +118 -0
- black/tests/data/cases/comments8.py +15 -0
- black/tests/data/cases/comments9.py +305 -0
- black/tests/data/cases/comments_in_blocks.py +111 -0
- black/tests/data/cases/comments_in_double_parens.py +113 -0
- black/tests/data/cases/comments_non_breaking_space.py +44 -0
- black/tests/data/cases/composition.py +181 -0
- black/tests/data/cases/composition_no_trailing_comma.py +367 -0
- black/tests/data/cases/conditional_expression.py +204 -0
- black/tests/data/cases/context_managers_38.py +55 -0
- black/tests/data/cases/context_managers_39.py +175 -0
- black/tests/data/cases/context_managers_autodetect_310.py +36 -0
- black/tests/data/cases/context_managers_autodetect_311.py +38 -0
- black/tests/data/cases/context_managers_autodetect_38.py +46 -0
- black/tests/data/cases/context_managers_autodetect_39.py +35 -0
- black/tests/data/cases/docstring.py +457 -0
- black/tests/data/cases/docstring_newline_preview.py +4 -0
- black/tests/data/cases/docstring_no_extra_empty_line_before_eof.py +4 -0
- black/tests/data/cases/docstring_no_string_normalization.py +250 -0
- black/tests/data/cases/docstring_preview.py +104 -0
- black/tests/data/cases/dummy_implementations.py +144 -0
- black/tests/data/cases/empty_lines.py +187 -0
- black/tests/data/cases/expression.py +630 -0
- black/tests/data/cases/f_docstring.py +20 -0
- black/tests/data/cases/fmtonoff.py +409 -0
- black/tests/data/cases/fmtonoff2.py +40 -0
- black/tests/data/cases/fmtonoff3.py +35 -0
- black/tests/data/cases/fmtonoff4.py +36 -0
- black/tests/data/cases/fmtonoff5.py +175 -0
- black/tests/data/cases/fmtpass_imports.py +19 -0
- black/tests/data/cases/fmtskip.py +3 -0
- black/tests/data/cases/fmtskip2.py +20 -0
- black/tests/data/cases/fmtskip3.py +20 -0
- black/tests/data/cases/fmtskip4.py +13 -0
- black/tests/data/cases/fmtskip5.py +22 -0
- black/tests/data/cases/fmtskip6.py +13 -0
- black/tests/data/cases/fmtskip7.py +11 -0
- black/tests/data/cases/fmtskip8.py +62 -0
- black/tests/data/cases/fmtskip9.py +9 -0
- black/tests/data/cases/form_feeds.py +226 -0
- black/tests/data/cases/fstring.py +25 -0
- black/tests/data/cases/funcdef_return_type_trailing_comma.py +301 -0
- black/tests/data/cases/function.py +244 -0
- black/tests/data/cases/function2.py +121 -0
- black/tests/data/cases/function_trailing_comma.py +178 -0
- black/tests/data/cases/ignore_pyi.py +42 -0
- black/tests/data/cases/import_spacing.py +118 -0
- black/tests/data/cases/is_simple_lookup_for_doublestar_expression.py +14 -0
- black/tests/data/cases/keep_newline_after_match.py +41 -0
- black/tests/data/cases/line_ranges_basic.py +107 -0
- black/tests/data/cases/line_ranges_diff_edge_case.py +28 -0
- black/tests/data/cases/line_ranges_exceeding_end.py +36 -0
- black/tests/data/cases/line_ranges_fmt_off.py +49 -0
- black/tests/data/cases/line_ranges_fmt_off_decorator.py +47 -0
- black/tests/data/cases/line_ranges_fmt_off_overlap.py +37 -0
- black/tests/data/cases/line_ranges_imports.py +9 -0
- black/tests/data/cases/line_ranges_indentation.py +27 -0
- black/tests/data/cases/line_ranges_outside_source.py +7 -0
- black/tests/data/cases/line_ranges_two_passes.py +27 -0
- black/tests/data/cases/line_ranges_unwrapping.py +25 -0
- black/tests/data/cases/linelength6.py +6 -0
- black/tests/data/cases/long_strings_flag_disabled.py +296 -0
- black/tests/data/cases/module_docstring_1.py +25 -0
- black/tests/data/cases/module_docstring_2.py +70 -0
- black/tests/data/cases/module_docstring_3.py +7 -0
- black/tests/data/cases/module_docstring_4.py +8 -0
- black/tests/data/cases/module_docstring_followed_by_class.py +10 -0
- black/tests/data/cases/module_docstring_followed_by_function.py +10 -0
- black/tests/data/cases/multiline_consecutive_open_parentheses_ignore.py +41 -0
- black/tests/data/cases/nested_stub.py +69 -0
- black/tests/data/cases/no_blank_line_before_docstring.py +66 -0
- black/tests/data/cases/numeric_literals.py +39 -0
- black/tests/data/cases/numeric_literals_skip_underscores.py +19 -0
- black/tests/data/cases/one_element_subscript.py +36 -0
- black/tests/data/cases/parenthesized_context_managers.py +46 -0
- black/tests/data/cases/pattern_matching_complex.py +155 -0
- black/tests/data/cases/pattern_matching_extras.py +102 -0
- black/tests/data/cases/pattern_matching_generic.py +108 -0
- black/tests/data/cases/pattern_matching_long.py +34 -0
- black/tests/data/cases/pattern_matching_simple.py +93 -0
- black/tests/data/cases/pattern_matching_style.py +92 -0
- black/tests/data/cases/pattern_matching_trailing_comma.py +39 -0
- black/tests/data/cases/pattern_matching_with_if_stmt.py +72 -0
- black/tests/data/cases/pep604_union_types_line_breaks.py +188 -0
- black/tests/data/cases/pep_570.py +45 -0
- black/tests/data/cases/pep_572.py +48 -0
- black/tests/data/cases/pep_572_do_not_remove_parens.py +26 -0
- black/tests/data/cases/pep_572_py310.py +16 -0
- black/tests/data/cases/pep_572_py39.py +8 -0
- black/tests/data/cases/pep_572_remove_parens.py +142 -0
- black/tests/data/cases/pep_572_slices.py +6 -0
- black/tests/data/cases/pep_604.py +25 -0
- black/tests/data/cases/pep_646.py +195 -0
- black/tests/data/cases/pep_654.py +54 -0
- black/tests/data/cases/pep_654_style.py +112 -0
- black/tests/data/cases/percent_precedence.py +41 -0
- black/tests/data/cases/power_op_newline.py +11 -0
- black/tests/data/cases/power_op_spacing.py +149 -0
- black/tests/data/cases/power_op_spacing_long.py +96 -0
- black/tests/data/cases/prefer_rhs_split.py +106 -0
- black/tests/data/cases/prefer_rhs_split_reformatted.py +38 -0
- black/tests/data/cases/preview_cantfit.py +94 -0
- black/tests/data/cases/preview_cantfit_string.py +18 -0
- black/tests/data/cases/preview_comments7.py +309 -0
- black/tests/data/cases/preview_format_unicode_escape_seq.py +34 -0
- black/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py +347 -0
- black/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets_no_ll1.py +106 -0
- black/tests/data/cases/preview_long_dict_values.py +129 -0
- black/tests/data/cases/preview_long_strings.py +928 -0
- black/tests/data/cases/preview_long_strings__east_asian_width.py +26 -0
- black/tests/data/cases/preview_long_strings__edge_case.py +141 -0
- black/tests/data/cases/preview_long_strings__regression.py +1247 -0
- black/tests/data/cases/preview_long_strings__type_annotations.py +60 -0
- black/tests/data/cases/preview_multiline_strings.py +401 -0
- black/tests/data/cases/preview_return_annotation_brackets_string.py +24 -0
- black/tests/data/cases/py310_pep572.py +13 -0
- black/tests/data/cases/python37.py +62 -0
- black/tests/data/cases/python38.py +42 -0
- black/tests/data/cases/python39.py +30 -0
- black/tests/data/cases/raw_docstring.py +32 -0
- black/tests/data/cases/raw_docstring_no_string_normalization.py +11 -0
- black/tests/data/cases/remove_await_parens.py +195 -0
- black/tests/data/cases/remove_except_parens.py +79 -0
- black/tests/data/cases/remove_for_brackets.py +48 -0
- black/tests/data/cases/remove_newline_after_code_block_open.py +212 -0
- black/tests/data/cases/remove_parens.py +142 -0
- black/tests/data/cases/remove_redundant_parens_in_case_guard.py +114 -0
- black/tests/data/cases/remove_with_brackets.py +120 -0
- black/tests/data/cases/return_annotation_brackets.py +219 -0
- black/tests/data/cases/single_line_format_skip_with_multiple_comments.py +19 -0
- black/tests/data/cases/skip_magic_trailing_comma.py +75 -0
- black/tests/data/cases/slices.py +31 -0
- black/tests/data/cases/split_delimiter_comments.py +51 -0
- black/tests/data/cases/starred_for_target.py +28 -0
- black/tests/data/cases/string_prefixes.py +45 -0
- black/tests/data/cases/stub.py +152 -0
- black/tests/data/cases/torture.py +91 -0
- black/tests/data/cases/trailing_comma.py +55 -0
- black/tests/data/cases/trailing_comma_optional_parens1.py +63 -0
- black/tests/data/cases/trailing_comma_optional_parens2.py +12 -0
- black/tests/data/cases/trailing_comma_optional_parens3.py +21 -0
- black/tests/data/cases/trailing_commas_in_leading_parts.py +88 -0
- black/tests/data/cases/tricky_unicode_symbols.py +9 -0
- black/tests/data/cases/tupleassign.py +23 -0
- black/tests/data/cases/type_aliases.py +30 -0
- black/tests/data/cases/type_comment_syntax_error.py +11 -0
- black/tests/data/cases/type_params.py +58 -0
- black/tests/data/cases/typed_params_trailing_comma.py +24 -0
- black/tests/data/cases/walrus_in_dict.py +9 -0
- black/tests/data/cases/whitespace.py +6 -0
- black/tests/data/gitignore_used_on_multiple_sources/dir1/a.py +0 -0
- black/tests/data/gitignore_used_on_multiple_sources/dir1/b.py +0 -0
- black/tests/data/gitignore_used_on_multiple_sources/dir2/a.py +0 -0
- black/tests/data/gitignore_used_on_multiple_sources/dir2/b.py +0 -0
- black/tests/data/ignore_subfolders_gitignore_tests/a.py +0 -0
- black/tests/data/ignore_subfolders_gitignore_tests/subdir/b.py +0 -0
- black/tests/data/ignore_subfolders_gitignore_tests/subdir/subdir/c.py +0 -0
- black/tests/data/include_exclude_tests/b/.definitely_exclude/a.py +0 -0
- black/tests/data/include_exclude_tests/b/dont_exclude/a.py +0 -0
- black/tests/data/include_exclude_tests/b/exclude/a.py +0 -0
- black/tests/data/invalid_gitignore_tests/a.py +0 -0
- black/tests/data/invalid_nested_gitignore_tests/a/a.py +0 -0
- black/tests/data/invalid_nested_gitignore_tests/a.py +0 -0
- black/tests/data/line_ranges_formatted/basic.py +50 -0
- black/tests/data/line_ranges_formatted/pattern_matching.py +25 -0
- black/tests/data/miscellaneous/async_as_identifier.py +49 -0
- black/tests/data/miscellaneous/blackd_diff.py +6 -0
- black/tests/data/miscellaneous/debug_visitor.py +32 -0
- black/tests/data/miscellaneous/decorators.py +182 -0
- black/tests/data/miscellaneous/force_py36.py +16 -0
- black/tests/data/miscellaneous/force_pyi.py +66 -0
- black/tests/data/miscellaneous/invalid_header.py +2 -0
- black/tests/data/miscellaneous/missing_final_newline.py +3 -0
- black/tests/data/miscellaneous/pattern_matching_invalid.py +18 -0
- black/tests/data/miscellaneous/python2_detection.py +90 -0
- black/tests/data/miscellaneous/string_quotes.py +114 -0
- black/tests/data/nested_gitignore_tests/root/a.py +1 -0
- black/tests/data/nested_gitignore_tests/root/b.py +1 -0
- black/tests/data/nested_gitignore_tests/root/c.py +1 -0
- black/tests/data/nested_gitignore_tests/root/child/a.py +1 -0
- black/tests/data/nested_gitignore_tests/root/child/b.py +1 -0
- black/tests/data/nested_gitignore_tests/root/child/c.py +1 -0
- black/tests/data/nested_gitignore_tests/x.py +0 -0
- black/tests/optional.py +132 -0
- black/tests/test_black.py +2980 -0
- black/tests/test_blackd.py +248 -0
- black/tests/test_docs.py +74 -0
- black/tests/test_format.py +90 -0
- black/tests/test_ipynb.py +517 -0
- black/tests/test_no_ipynb.py +36 -0
- black/tests/test_ranges.py +249 -0
- black/tests/test_schema.py +17 -0
- black/tests/test_trans.py +51 -0
- black/tests/util.py +354 -0
- call_arg_map_to_parameters_poc.py +3 -3
- deadcode/actions/{fix_unused_code.py → fix_or_show_unused_code.py} +25 -4
- deadcode/actions/parse_arguments.py +24 -6
- deadcode/cli.py +5 -4
- deadcode/constants.py +24 -24
- deadcode/data_types.py +1 -0
- deadcode/tests/base.py +2 -2
- deadcode/tests/cli_args/test_dry.py +318 -0
- deadcode/tests/cli_args/test_fix.py +5 -5
- deadcode/tests/cli_args/test_ignore_bodies_if_inherits_from.py +3 -3
- deadcode/tests/cli_args/test_ignore_definitions.py +1 -1
- deadcode/tests/cli_args/test_ignore_definitions_if_inherits_from.py +4 -4
- deadcode/tests/cli_args/test_ignore_names.py +3 -3
- deadcode/tests/cli_args/test_parsing.py +59 -12
- deadcode/tests/fix/test_assign.py +2 -2
- deadcode/tests/fix/test_class_def.py +4 -4
- deadcode/tests/fix/test_empty_files.py +2 -2
- deadcode/tests/nested_scope/test_nested_scope.py +96 -1
- deadcode/tests/noqa/test_noqa_comments.py +28 -28
- deadcode/tests/test_deadcode.py +11 -11
- deadcode/tests/test_imports.py +3 -3
- deadcode/tests/test_output.py +6 -6
- deadcode/tests/utils/test_add_colors_to_diff.py +38 -0
- deadcode/utils/add_colors_to_diff.py +10 -0
- deadcode/utils/nested_scopes.py +51 -15
- deadcode/visitor/code_item.py +3 -0
- deadcode/visitor/dead_code_visitor.py +37 -135
- deadcode/visitor/ignore.py +12 -12
- deadcode/visitor/noqa.py +27 -14
- {deadcode-2.2.2.dist-info → deadcode-2.3.0.dist-info}/METADATA +67 -25
- deadcode-2.3.0.dist-info/RECORD +342 -0
- deadcode-2.2.2.dist-info/RECORD +0 -67
- {deadcode-2.2.2.dist-info → deadcode-2.3.0.dist-info}/WHEEL +0 -0
- {deadcode-2.2.2.dist-info → deadcode-2.3.0.dist-info}/entry_points.txt +0 -0
- {deadcode-2.2.2.dist-info → deadcode-2.3.0.dist-info}/licenses/LICENSE +0 -0
black/action/main.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import shlex
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from subprocess import PIPE, STDOUT, run
|
|
8
|
+
from typing import Union
|
|
9
|
+
|
|
10
|
+
ACTION_PATH = Path(os.environ["GITHUB_ACTION_PATH"])
|
|
11
|
+
ENV_PATH = ACTION_PATH / ".black-env"
|
|
12
|
+
ENV_BIN = ENV_PATH / ("Scripts" if sys.platform == "win32" else "bin")
|
|
13
|
+
OPTIONS = os.getenv("INPUT_OPTIONS", default="")
|
|
14
|
+
SRC = os.getenv("INPUT_SRC", default="")
|
|
15
|
+
JUPYTER = os.getenv("INPUT_JUPYTER") == "true"
|
|
16
|
+
BLACK_ARGS = os.getenv("INPUT_BLACK_ARGS", default="")
|
|
17
|
+
VERSION = os.getenv("INPUT_VERSION", default="")
|
|
18
|
+
USE_PYPROJECT = os.getenv("INPUT_USE_PYPROJECT") == "true"
|
|
19
|
+
|
|
20
|
+
BLACK_VERSION_RE = re.compile(r"^black([^A-Z0-9._-]+.*)$", re.IGNORECASE)
|
|
21
|
+
EXTRAS_RE = re.compile(r"\[.*\]")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def determine_version_specifier() -> str:
|
|
25
|
+
"""Determine the version of Black to install.
|
|
26
|
+
|
|
27
|
+
The version can be specified either via the `with.version` input or via the
|
|
28
|
+
pyproject.toml file if `with.use_pyproject` is set to `true`.
|
|
29
|
+
"""
|
|
30
|
+
if USE_PYPROJECT and VERSION:
|
|
31
|
+
print(
|
|
32
|
+
"::error::'with.version' and 'with.use_pyproject' inputs are "
|
|
33
|
+
"mutually exclusive.",
|
|
34
|
+
file=sys.stderr,
|
|
35
|
+
flush=True,
|
|
36
|
+
)
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
if USE_PYPROJECT:
|
|
39
|
+
return read_version_specifier_from_pyproject()
|
|
40
|
+
elif VERSION and VERSION[0] in "0123456789":
|
|
41
|
+
return f"=={VERSION}"
|
|
42
|
+
else:
|
|
43
|
+
return VERSION
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def read_version_specifier_from_pyproject() -> str:
|
|
47
|
+
if sys.version_info < (3, 11):
|
|
48
|
+
print(
|
|
49
|
+
"::error::'with.use_pyproject' input requires Python 3.11 or later.",
|
|
50
|
+
file=sys.stderr,
|
|
51
|
+
flush=True,
|
|
52
|
+
)
|
|
53
|
+
sys.exit(1)
|
|
54
|
+
|
|
55
|
+
import tomllib # type: ignore[import-not-found,unreachable]
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
with Path("pyproject.toml").open("rb") as fp:
|
|
59
|
+
pyproject = tomllib.load(fp)
|
|
60
|
+
except FileNotFoundError:
|
|
61
|
+
print(
|
|
62
|
+
"::error::'with.use_pyproject' input requires a pyproject.toml file.",
|
|
63
|
+
file=sys.stderr,
|
|
64
|
+
flush=True,
|
|
65
|
+
)
|
|
66
|
+
sys.exit(1)
|
|
67
|
+
|
|
68
|
+
version = pyproject.get("tool", {}).get("black", {}).get("required-version")
|
|
69
|
+
if version is not None:
|
|
70
|
+
return f"=={version}"
|
|
71
|
+
|
|
72
|
+
arrays = [
|
|
73
|
+
pyproject.get("project", {}).get("dependencies"),
|
|
74
|
+
*pyproject.get("project", {}).get("optional-dependencies", {}).values(),
|
|
75
|
+
]
|
|
76
|
+
for array in arrays:
|
|
77
|
+
version = find_black_version_in_array(array)
|
|
78
|
+
if version is not None:
|
|
79
|
+
break
|
|
80
|
+
|
|
81
|
+
if version is None:
|
|
82
|
+
print(
|
|
83
|
+
"::error::'black' dependency missing from pyproject.toml.",
|
|
84
|
+
file=sys.stderr,
|
|
85
|
+
flush=True,
|
|
86
|
+
)
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
return version
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def find_black_version_in_array(array: object) -> Union[str, None]:
|
|
93
|
+
if not isinstance(array, list):
|
|
94
|
+
return None
|
|
95
|
+
try:
|
|
96
|
+
for item in array:
|
|
97
|
+
# Rudimentary PEP 508 parsing.
|
|
98
|
+
item = item.split(";")[0]
|
|
99
|
+
item = EXTRAS_RE.sub("", item).strip()
|
|
100
|
+
if item == "black":
|
|
101
|
+
print(
|
|
102
|
+
"::error::Version specifier missing for 'black' dependency in "
|
|
103
|
+
"pyproject.toml.",
|
|
104
|
+
file=sys.stderr,
|
|
105
|
+
flush=True,
|
|
106
|
+
)
|
|
107
|
+
sys.exit(1)
|
|
108
|
+
elif m := BLACK_VERSION_RE.match(item):
|
|
109
|
+
return m.group(1).strip()
|
|
110
|
+
except TypeError:
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
run([sys.executable, "-m", "venv", str(ENV_PATH)], check=True)
|
|
117
|
+
|
|
118
|
+
version_specifier = determine_version_specifier()
|
|
119
|
+
if JUPYTER:
|
|
120
|
+
extra_deps = "[colorama,jupyter]"
|
|
121
|
+
else:
|
|
122
|
+
extra_deps = "[colorama]"
|
|
123
|
+
if version_specifier:
|
|
124
|
+
req = f"black{extra_deps}{version_specifier}"
|
|
125
|
+
else:
|
|
126
|
+
describe_name = ""
|
|
127
|
+
with open(ACTION_PATH / ".git_archival.txt", encoding="utf-8") as fp:
|
|
128
|
+
for line in fp:
|
|
129
|
+
if line.startswith("describe-name: "):
|
|
130
|
+
describe_name = line[len("describe-name: ") :].rstrip()
|
|
131
|
+
break
|
|
132
|
+
if not describe_name:
|
|
133
|
+
print("::error::Failed to detect action version.", file=sys.stderr, flush=True)
|
|
134
|
+
sys.exit(1)
|
|
135
|
+
# expected format is one of:
|
|
136
|
+
# - 23.1.0
|
|
137
|
+
# - 23.1.0-51-g448bba7
|
|
138
|
+
if describe_name.count("-") < 2:
|
|
139
|
+
# the action's commit matches a tag exactly, install exact version from PyPI
|
|
140
|
+
req = f"black{extra_deps}=={describe_name}"
|
|
141
|
+
else:
|
|
142
|
+
# the action's commit does not match any tag, install from the local git repo
|
|
143
|
+
req = f".{extra_deps}"
|
|
144
|
+
print(f"Installing {req}...", flush=True)
|
|
145
|
+
pip_proc = run(
|
|
146
|
+
[str(ENV_BIN / "python"), "-m", "pip", "install", req],
|
|
147
|
+
stdout=PIPE,
|
|
148
|
+
stderr=STDOUT,
|
|
149
|
+
encoding="utf-8",
|
|
150
|
+
cwd=ACTION_PATH,
|
|
151
|
+
)
|
|
152
|
+
if pip_proc.returncode:
|
|
153
|
+
print(pip_proc.stdout)
|
|
154
|
+
print("::error::Failed to install Black.", file=sys.stderr, flush=True)
|
|
155
|
+
sys.exit(pip_proc.returncode)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
base_cmd = [str(ENV_BIN / "black")]
|
|
159
|
+
if BLACK_ARGS:
|
|
160
|
+
# TODO: remove after a while since this is deprecated in favour of SRC + OPTIONS.
|
|
161
|
+
proc = run(
|
|
162
|
+
[*base_cmd, *shlex.split(BLACK_ARGS)],
|
|
163
|
+
stdout=PIPE,
|
|
164
|
+
stderr=STDOUT,
|
|
165
|
+
encoding="utf-8",
|
|
166
|
+
)
|
|
167
|
+
else:
|
|
168
|
+
proc = run(
|
|
169
|
+
[*base_cmd, *shlex.split(OPTIONS), *shlex.split(SRC)],
|
|
170
|
+
stdout=PIPE,
|
|
171
|
+
stderr=STDOUT,
|
|
172
|
+
encoding="utf-8",
|
|
173
|
+
)
|
|
174
|
+
shutil.rmtree(ENV_PATH, ignore_errors=True)
|
|
175
|
+
print(proc.stdout)
|
|
176
|
+
sys.exit(proc.returncode)
|
black/docs/conf.py
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Configuration file for the Sphinx documentation builder.
|
|
4
|
+
#
|
|
5
|
+
# This file does only contain a selection of the most common options. For a
|
|
6
|
+
# full list see the documentation:
|
|
7
|
+
# http://www.sphinx-doc.org/en/stable/config
|
|
8
|
+
|
|
9
|
+
# -- Path setup --------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
# If extensions (or modules to document with autodoc) are in another directory,
|
|
12
|
+
# add these directories to sys.path here. If the directory is relative to the
|
|
13
|
+
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import string
|
|
18
|
+
from importlib.metadata import version
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
CURRENT_DIR = Path(__file__).parent
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def make_pypi_svg(version: str) -> None:
|
|
25
|
+
template: Path = CURRENT_DIR / "_static" / "pypi_template.svg"
|
|
26
|
+
target: Path = CURRENT_DIR / "_static" / "pypi.svg"
|
|
27
|
+
with open(str(template), "r", encoding="utf8") as f:
|
|
28
|
+
svg: str = string.Template(f.read()).substitute(version=version)
|
|
29
|
+
with open(str(target), "w", encoding="utf8") as f:
|
|
30
|
+
f.write(svg)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Necessary so Click doesn't hit an encode error when called by
|
|
34
|
+
# sphinxcontrib-programoutput on Windows.
|
|
35
|
+
os.putenv("pythonioencoding", "utf-8")
|
|
36
|
+
|
|
37
|
+
# -- Project information -----------------------------------------------------
|
|
38
|
+
|
|
39
|
+
project = "Black"
|
|
40
|
+
copyright = "2018-Present, Łukasz Langa and contributors to Black"
|
|
41
|
+
author = "Łukasz Langa and contributors to Black"
|
|
42
|
+
|
|
43
|
+
# Autopopulate version
|
|
44
|
+
# The version, including alpha/beta/rc tags, but not commit hash and datestamps
|
|
45
|
+
release = version("black").split("+")[0]
|
|
46
|
+
# The short X.Y version.
|
|
47
|
+
version = release
|
|
48
|
+
for sp in "abcfr":
|
|
49
|
+
version = version.split(sp)[0]
|
|
50
|
+
|
|
51
|
+
make_pypi_svg(release)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# -- General configuration ---------------------------------------------------
|
|
55
|
+
|
|
56
|
+
# If your documentation needs a minimal Sphinx version, state it here.
|
|
57
|
+
needs_sphinx = "4.4"
|
|
58
|
+
|
|
59
|
+
# Add any Sphinx extension module names here, as strings. They can be
|
|
60
|
+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
61
|
+
# ones.
|
|
62
|
+
extensions = [
|
|
63
|
+
"sphinx.ext.autodoc",
|
|
64
|
+
"sphinx.ext.intersphinx",
|
|
65
|
+
"sphinx.ext.napoleon",
|
|
66
|
+
"myst_parser",
|
|
67
|
+
"sphinxcontrib.programoutput",
|
|
68
|
+
"sphinx_copybutton",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
# If you need extensions of a certain version or higher, list them here.
|
|
72
|
+
needs_extensions = {"myst_parser": "0.13.7"}
|
|
73
|
+
|
|
74
|
+
# Add any paths that contain templates here, relative to this directory.
|
|
75
|
+
templates_path = ["_templates"]
|
|
76
|
+
|
|
77
|
+
# The suffix(es) of source filenames.
|
|
78
|
+
# You can specify multiple suffix as a list of string:
|
|
79
|
+
source_suffix = [".rst", ".md"]
|
|
80
|
+
|
|
81
|
+
# The master toctree document.
|
|
82
|
+
master_doc = "index"
|
|
83
|
+
|
|
84
|
+
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
85
|
+
# for a list of supported languages.
|
|
86
|
+
#
|
|
87
|
+
# This is also used if you do content translation via gettext catalogs.
|
|
88
|
+
# Usually you set "language" from the command line for these cases.
|
|
89
|
+
language = "en"
|
|
90
|
+
|
|
91
|
+
# List of patterns, relative to source directory, that match files and
|
|
92
|
+
# directories to ignore when looking for source files.
|
|
93
|
+
# This pattern also affects html_static_path and html_extra_path .
|
|
94
|
+
|
|
95
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
96
|
+
|
|
97
|
+
# The name of the Pygments (syntax highlighting) style to use.
|
|
98
|
+
pygments_style = "sphinx"
|
|
99
|
+
|
|
100
|
+
# We need headers to be linkable to so ask MyST-Parser to autogenerate anchor IDs for
|
|
101
|
+
# headers up to and including level 3.
|
|
102
|
+
myst_heading_anchors = 3
|
|
103
|
+
|
|
104
|
+
# Prettier support formatting some MyST syntax but not all, so let's disable the
|
|
105
|
+
# unsupported yet still enabled by default ones.
|
|
106
|
+
myst_disable_syntax = [
|
|
107
|
+
"colon_fence",
|
|
108
|
+
"myst_block_break",
|
|
109
|
+
"myst_line_comment",
|
|
110
|
+
"math_block",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# Optional MyST Syntaxes
|
|
114
|
+
myst_enable_extensions = []
|
|
115
|
+
|
|
116
|
+
# -- Options for HTML output -------------------------------------------------
|
|
117
|
+
|
|
118
|
+
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
119
|
+
# a list of builtin themes.
|
|
120
|
+
#
|
|
121
|
+
html_theme = "furo"
|
|
122
|
+
html_logo = "_static/logo2-readme.png"
|
|
123
|
+
|
|
124
|
+
# Add any paths that contain custom static files (such as style sheets) here,
|
|
125
|
+
# relative to this directory. They are copied after the builtin static files,
|
|
126
|
+
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
127
|
+
html_static_path = ["_static"]
|
|
128
|
+
|
|
129
|
+
# Custom sidebar templates, must be a dictionary that maps document names
|
|
130
|
+
# to template names.
|
|
131
|
+
#
|
|
132
|
+
# The default sidebars (for documents that don't match any pattern) are
|
|
133
|
+
# defined by theme itself. Builtin themes are using these templates by
|
|
134
|
+
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
|
135
|
+
# 'searchbox.html']``.
|
|
136
|
+
#
|
|
137
|
+
# html_sidebars = {}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# -- Options for HTMLHelp output ---------------------------------------------
|
|
141
|
+
|
|
142
|
+
# Output file base name for HTML help builder.
|
|
143
|
+
htmlhelp_basename = "blackdoc"
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# -- Options for LaTeX output ------------------------------------------------
|
|
147
|
+
|
|
148
|
+
# Grouping the document tree into LaTeX files. List of tuples
|
|
149
|
+
# (source start file, target name, title,
|
|
150
|
+
# author, documentclass [howto, manual, or own class]).
|
|
151
|
+
latex_documents = [(
|
|
152
|
+
master_doc,
|
|
153
|
+
"black.tex",
|
|
154
|
+
"Documentation for Black",
|
|
155
|
+
"Łukasz Langa and contributors to Black",
|
|
156
|
+
"manual",
|
|
157
|
+
)]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# -- Options for manual page output ------------------------------------------
|
|
161
|
+
|
|
162
|
+
# One entry per manual page. List of tuples
|
|
163
|
+
# (source start file, name, description, authors, manual section).
|
|
164
|
+
man_pages = [(master_doc, "black", "Documentation for Black", [author], 1)]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# -- Options for Texinfo output ----------------------------------------------
|
|
168
|
+
|
|
169
|
+
# Grouping the document tree into Texinfo files. List of tuples
|
|
170
|
+
# (source start file, target name, title, author,
|
|
171
|
+
# dir menu entry, description, category)
|
|
172
|
+
texinfo_documents = [(
|
|
173
|
+
master_doc,
|
|
174
|
+
"Black",
|
|
175
|
+
"Documentation for Black",
|
|
176
|
+
author,
|
|
177
|
+
"Black",
|
|
178
|
+
"The uncompromising Python code formatter",
|
|
179
|
+
"Miscellaneous",
|
|
180
|
+
)]
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# -- Options for Epub output -------------------------------------------------
|
|
184
|
+
|
|
185
|
+
# Bibliographic Dublin Core info.
|
|
186
|
+
epub_title = project
|
|
187
|
+
epub_author = author
|
|
188
|
+
epub_publisher = author
|
|
189
|
+
epub_copyright = copyright
|
|
190
|
+
|
|
191
|
+
# The unique identifier of the text. This can be a ISBN number
|
|
192
|
+
# or the project homepage.
|
|
193
|
+
#
|
|
194
|
+
# epub_identifier = ''
|
|
195
|
+
|
|
196
|
+
# A unique identification for the text.
|
|
197
|
+
#
|
|
198
|
+
# epub_uid = ''
|
|
199
|
+
|
|
200
|
+
# A list of files that should not be packed into the epub file.
|
|
201
|
+
epub_exclude_files = ["search.html"]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
# -- Extension configuration -------------------------------------------------
|
|
205
|
+
|
|
206
|
+
autodoc_member_order = "bysource"
|
|
207
|
+
|
|
208
|
+
# -- sphinx-copybutton configuration ----------------------------------------
|
|
209
|
+
copybutton_prompt_text = (
|
|
210
|
+
r">>> |\.\.\. |> |\$ |\# | In \[\d*\]: | {2,5}\.\.\.: | {5,8}: "
|
|
211
|
+
)
|
|
212
|
+
copybutton_prompt_is_regexp = True
|
|
213
|
+
copybutton_remove_prompts = True
|
|
214
|
+
|
|
215
|
+
# -- Options for intersphinx extension ---------------------------------------
|
|
216
|
+
|
|
217
|
+
# Example configuration for intersphinx: refer to the Python standard library.
|
|
218
|
+
intersphinx_mapping = {"<name>": ("https://docs.python.org/3/", None)}
|
black/gallery/gallery.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import json
|
|
3
|
+
import subprocess
|
|
4
|
+
import tarfile
|
|
5
|
+
import tempfile
|
|
6
|
+
import traceback
|
|
7
|
+
import venv
|
|
8
|
+
import zipfile
|
|
9
|
+
from argparse import ArgumentParser, Namespace
|
|
10
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
11
|
+
from functools import lru_cache, partial
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Generator, List, NamedTuple, Optional, Tuple, Union, cast
|
|
14
|
+
from urllib.request import urlopen, urlretrieve
|
|
15
|
+
|
|
16
|
+
PYPI_INSTANCE = "https://pypi.org/pypi"
|
|
17
|
+
PYPI_TOP_PACKAGES = (
|
|
18
|
+
"https://hugovk.github.io/top-pypi-packages/top-pypi-packages-30-days.min.json"
|
|
19
|
+
)
|
|
20
|
+
INTERNAL_BLACK_REPO = f"{tempfile.gettempdir()}/__black"
|
|
21
|
+
|
|
22
|
+
ArchiveKind = Union[tarfile.TarFile, zipfile.ZipFile]
|
|
23
|
+
|
|
24
|
+
subprocess.run = partial(subprocess.run, check=True) # type: ignore
|
|
25
|
+
# https://github.com/python/mypy/issues/1484
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class BlackVersion(NamedTuple):
|
|
29
|
+
version: str
|
|
30
|
+
config: Optional[str] = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_pypi_download_url(package: str, version: Optional[str]) -> str:
|
|
34
|
+
with urlopen(PYPI_INSTANCE + f"/{package}/json") as page:
|
|
35
|
+
metadata = json.load(page)
|
|
36
|
+
|
|
37
|
+
if version is None:
|
|
38
|
+
sources = metadata["urls"]
|
|
39
|
+
else:
|
|
40
|
+
if version in metadata["releases"]:
|
|
41
|
+
sources = metadata["releases"][version]
|
|
42
|
+
else:
|
|
43
|
+
raise ValueError(
|
|
44
|
+
f"No releases found with version ('{version}') tag. "
|
|
45
|
+
f"Found releases: {metadata['releases'].keys()}"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
for source in sources:
|
|
49
|
+
if source["python_version"] == "source":
|
|
50
|
+
break
|
|
51
|
+
else:
|
|
52
|
+
raise ValueError(f"Couldn't find any sources for {package}")
|
|
53
|
+
|
|
54
|
+
return cast(str, source["url"])
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_top_packages() -> List[str]:
|
|
58
|
+
with urlopen(PYPI_TOP_PACKAGES) as page:
|
|
59
|
+
result = json.load(page)
|
|
60
|
+
|
|
61
|
+
return [package["project"] for package in result["rows"]]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_package_source(package: str, version: Optional[str]) -> str:
|
|
65
|
+
if package == "cpython":
|
|
66
|
+
if version is None:
|
|
67
|
+
version = "main"
|
|
68
|
+
return f"https://github.com/python/cpython/archive/{version}.zip"
|
|
69
|
+
elif package == "pypy":
|
|
70
|
+
if version is None:
|
|
71
|
+
version = "branch/default"
|
|
72
|
+
return (
|
|
73
|
+
f"https://foss.heptapod.net/pypy/pypy/repository/{version}/archive.tar.bz2"
|
|
74
|
+
)
|
|
75
|
+
else:
|
|
76
|
+
return get_pypi_download_url(package, version)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_archive_manager(local_file: str) -> ArchiveKind:
|
|
80
|
+
if tarfile.is_tarfile(local_file):
|
|
81
|
+
return tarfile.open(local_file)
|
|
82
|
+
elif zipfile.is_zipfile(local_file):
|
|
83
|
+
return zipfile.ZipFile(local_file)
|
|
84
|
+
else:
|
|
85
|
+
raise ValueError("Unknown archive kind.")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_first_archive_member(archive: ArchiveKind) -> str:
|
|
89
|
+
if isinstance(archive, tarfile.TarFile):
|
|
90
|
+
return archive.getnames()[0]
|
|
91
|
+
elif isinstance(archive, zipfile.ZipFile):
|
|
92
|
+
return archive.namelist()[0]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def download_and_extract(package: str, version: Optional[str], directory: Path) -> Path:
|
|
96
|
+
source = get_package_source(package, version)
|
|
97
|
+
|
|
98
|
+
local_file, _ = urlretrieve(source, directory / f"{package}-src")
|
|
99
|
+
with get_archive_manager(local_file) as archive:
|
|
100
|
+
archive.extractall(path=directory)
|
|
101
|
+
result_dir = get_first_archive_member(archive)
|
|
102
|
+
return directory / result_dir
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_package(
|
|
106
|
+
package: str, version: Optional[str], directory: Path
|
|
107
|
+
) -> Optional[Path]:
|
|
108
|
+
try:
|
|
109
|
+
return download_and_extract(package, version, directory)
|
|
110
|
+
except Exception:
|
|
111
|
+
print(f"Caught an exception while downloading {package}.")
|
|
112
|
+
traceback.print_exc()
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
DEFAULT_SLICE = slice(None) # for flake8
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def download_and_extract_top_packages(
|
|
120
|
+
directory: Path,
|
|
121
|
+
workers: int = 8,
|
|
122
|
+
limit: slice = DEFAULT_SLICE,
|
|
123
|
+
) -> Generator[Path, None, None]:
|
|
124
|
+
with ThreadPoolExecutor(max_workers=workers) as executor:
|
|
125
|
+
bound_downloader = partial(get_package, version=None, directory=directory)
|
|
126
|
+
for package in executor.map(bound_downloader, get_top_packages()[limit]):
|
|
127
|
+
if package is not None:
|
|
128
|
+
yield package
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def git_create_repository(repo: Path) -> None:
|
|
132
|
+
subprocess.run(["git", "init"], cwd=repo)
|
|
133
|
+
git_add_and_commit(msg="Initial commit", repo=repo)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def git_add_and_commit(msg: str, repo: Path) -> None:
|
|
137
|
+
subprocess.run(["git", "add", "."], cwd=repo)
|
|
138
|
+
subprocess.run(["git", "commit", "-m", msg, "--allow-empty"], cwd=repo)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def git_switch_branch(
|
|
142
|
+
branch: str, repo: Path, new: bool = False, from_branch: Optional[str] = None
|
|
143
|
+
) -> None:
|
|
144
|
+
args = ["git", "checkout"]
|
|
145
|
+
if new:
|
|
146
|
+
args.append("-b")
|
|
147
|
+
args.append(branch)
|
|
148
|
+
if from_branch:
|
|
149
|
+
args.append(from_branch)
|
|
150
|
+
subprocess.run(args, cwd=repo)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def init_repos(options: Namespace) -> Tuple[Path, ...]:
|
|
154
|
+
options.output.mkdir(exist_ok=True)
|
|
155
|
+
|
|
156
|
+
if options.top_packages:
|
|
157
|
+
source_directories = tuple(
|
|
158
|
+
download_and_extract_top_packages(
|
|
159
|
+
directory=options.output,
|
|
160
|
+
workers=options.workers,
|
|
161
|
+
limit=slice(None, options.top_packages),
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
else:
|
|
165
|
+
source_directories = (
|
|
166
|
+
download_and_extract(
|
|
167
|
+
package=options.pypi_package,
|
|
168
|
+
version=options.version,
|
|
169
|
+
directory=options.output,
|
|
170
|
+
),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
for source_directory in source_directories:
|
|
174
|
+
git_create_repository(source_directory)
|
|
175
|
+
|
|
176
|
+
if options.black_repo is None:
|
|
177
|
+
subprocess.run(
|
|
178
|
+
["git", "clone", "https://github.com/psf/black.git", INTERNAL_BLACK_REPO],
|
|
179
|
+
cwd=options.output,
|
|
180
|
+
)
|
|
181
|
+
options.black_repo = options.output / INTERNAL_BLACK_REPO
|
|
182
|
+
|
|
183
|
+
return source_directories
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@lru_cache(8)
|
|
187
|
+
def black_runner(version: str, black_repo: Path) -> Path:
|
|
188
|
+
directory = tempfile.TemporaryDirectory()
|
|
189
|
+
venv.create(directory.name, with_pip=True)
|
|
190
|
+
|
|
191
|
+
python = Path(directory.name) / "bin" / "python"
|
|
192
|
+
subprocess.run([python, "-m", "pip", "install", "-e", black_repo])
|
|
193
|
+
|
|
194
|
+
atexit.register(directory.cleanup)
|
|
195
|
+
return python
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def format_repo_with_version(
|
|
199
|
+
repo: Path,
|
|
200
|
+
from_branch: Optional[str],
|
|
201
|
+
black_repo: Path,
|
|
202
|
+
black_version: BlackVersion,
|
|
203
|
+
input_directory: Path,
|
|
204
|
+
) -> str:
|
|
205
|
+
current_branch = f"black-{black_version.version}"
|
|
206
|
+
git_switch_branch(black_version.version, repo=black_repo)
|
|
207
|
+
git_switch_branch(current_branch, repo=repo, new=True, from_branch=from_branch)
|
|
208
|
+
|
|
209
|
+
format_cmd: List[Union[Path, str]] = [
|
|
210
|
+
black_runner(black_version.version, black_repo),
|
|
211
|
+
(black_repo / "black.py").resolve(),
|
|
212
|
+
".",
|
|
213
|
+
]
|
|
214
|
+
if black_version.config:
|
|
215
|
+
format_cmd.extend(["--config", input_directory / black_version.config])
|
|
216
|
+
|
|
217
|
+
subprocess.run(format_cmd, cwd=repo, check=False) # ensure the process
|
|
218
|
+
# continuess to run even it can't format some files. Reporting those
|
|
219
|
+
# should be enough
|
|
220
|
+
git_add_and_commit(f"Format with black:{black_version.version}", repo=repo)
|
|
221
|
+
|
|
222
|
+
return current_branch
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def format_repos(repos: Tuple[Path, ...], options: Namespace) -> None:
|
|
226
|
+
black_versions = tuple(
|
|
227
|
+
BlackVersion(*version.split(":")) for version in options.versions
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
for repo in repos:
|
|
231
|
+
from_branch = None
|
|
232
|
+
for black_version in black_versions:
|
|
233
|
+
from_branch = format_repo_with_version(
|
|
234
|
+
repo=repo,
|
|
235
|
+
from_branch=from_branch,
|
|
236
|
+
black_repo=options.black_repo,
|
|
237
|
+
black_version=black_version,
|
|
238
|
+
input_directory=options.input,
|
|
239
|
+
)
|
|
240
|
+
git_switch_branch("main", repo=repo)
|
|
241
|
+
|
|
242
|
+
git_switch_branch("main", repo=options.black_repo)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def main() -> None:
|
|
246
|
+
parser = ArgumentParser(description="""Black Gallery is a script that
|
|
247
|
+
automates the process of applying different Black versions to a selected
|
|
248
|
+
PyPI package and seeing the results between versions.""")
|
|
249
|
+
|
|
250
|
+
group = parser.add_mutually_exclusive_group(required=True)
|
|
251
|
+
group.add_argument("-p", "--pypi-package", help="PyPI package to download.")
|
|
252
|
+
group.add_argument(
|
|
253
|
+
"-t", "--top-packages", help="Top n PyPI packages to download.", type=int
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
parser.add_argument("-b", "--black-repo", help="Black's Git repository.", type=Path)
|
|
257
|
+
parser.add_argument(
|
|
258
|
+
"-v",
|
|
259
|
+
"--version",
|
|
260
|
+
help=(
|
|
261
|
+
"Version for given PyPI package. Will be discarded if used with -t option."
|
|
262
|
+
),
|
|
263
|
+
)
|
|
264
|
+
parser.add_argument(
|
|
265
|
+
"-w",
|
|
266
|
+
"--workers",
|
|
267
|
+
help=(
|
|
268
|
+
"Maximum number of threads to download with at the same time. "
|
|
269
|
+
"Will be discarded if used with -p option."
|
|
270
|
+
),
|
|
271
|
+
)
|
|
272
|
+
parser.add_argument(
|
|
273
|
+
"-i",
|
|
274
|
+
"--input",
|
|
275
|
+
default=Path("/input"),
|
|
276
|
+
type=Path,
|
|
277
|
+
help="Input directory to read configuration.",
|
|
278
|
+
)
|
|
279
|
+
parser.add_argument(
|
|
280
|
+
"-o",
|
|
281
|
+
"--output",
|
|
282
|
+
default=Path("/output"),
|
|
283
|
+
type=Path,
|
|
284
|
+
help="Output directory to download and put result artifacts.",
|
|
285
|
+
)
|
|
286
|
+
parser.add_argument("versions", nargs="*", default=("main",), help="")
|
|
287
|
+
|
|
288
|
+
options = parser.parse_args()
|
|
289
|
+
repos = init_repos(options)
|
|
290
|
+
format_repos(repos, options)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
if __name__ == "__main__":
|
|
294
|
+
main()
|