Skip to content

Commit

Permalink
Merge 9fe7ce2 into 8a84beb
Browse files Browse the repository at this point in the history
  • Loading branch information
ichard26 committed Jan 6, 2022
2 parents 8a84beb + 9fe7ce2 commit 0a60792
Show file tree
Hide file tree
Showing 27 changed files with 86 additions and 403 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ current development version. To confirm this, you have three options:
3. Or run _Black_ on your machine:
- create a new virtualenv (make sure it's the same Python version);
- clone this repository;
- run `pip install -e .[d,python2]`;
- run `pip install -e .[d]`;
- run `pip install -r test_requirements.txt`
- make sure it's sane by running `python -m pytest`; and
- run `black` like you did last time.
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### _Black_

- **Remove Python 2 support** (#2740)
- Do not accept bare carriage return line endings in pyproject.toml (#2408)
- Improve error message for invalid regular expression (#2678)
- Improve error message when parsing fails during AST safety check by embedding the
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ Try it out now using the [Black Playground](https://black.vercel.app). Watch the
### Installation

_Black_ can be installed by running `pip install black`. It requires Python 3.6.2+ to
run. If you want to format Python 2 code as well, install with
`pip install black[python2]`. If you want to format Jupyter Notebooks, install with
`pip install black[jupyter]`.
run. If you want to format Jupyter Notebooks, install with `pip install black[jupyter]`.

If you can't wait for the latest _hotness_ and want to install from GitHub, use:

Expand Down
2 changes: 1 addition & 1 deletion action/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

run([sys.executable, "-m", "venv", str(ENV_PATH)], check=True)

req = "black[colorama,python2]"
req = "black[colorama]"
if VERSION:
req += f"=={VERSION}"
pip_proc = run(
Expand Down
15 changes: 3 additions & 12 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,8 @@ disabled-by-default counterpart W504. E203 should be disabled while changes are

## Does Black support Python 2?

```{warning}
Python 2 support has been deprecated since 21.10b0.
This support will be dropped in the first stable release, expected for January 2022.
See [The Black Code Style](the_black_code_style/index.rst) for details.
```

For formatting, yes! [Install](getting_started.md#installation) with the `python2` extra
to format Python 2 files too! In terms of running _Black_ though, Python 3.6 or newer is
required.
Formatting Python 2 code support was removed in version 22.0. In terms of running
_Black_, Python 3.6 or newer is required.

## Why does my linter or typechecker complain after I format my code?

Expand All @@ -96,8 +88,7 @@ codebase with _Black_.

## Can I run Black with PyPy?

Yes, there is support for PyPy 3.7 and higher. You cannot format Python 2 files under
PyPy, because PyPy's inbuilt ast module does not support this.
Yes, there is support for PyPy 3.7 and higher.

## Why does Black not detect syntax errors in my code?

Expand Down
4 changes: 1 addition & 3 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ Also, you can try out _Black_ online for minimal fuss on the
## Installation

_Black_ can be installed by running `pip install black`. It requires Python 3.6.2+ to
run, but can format Python 2 code too. Python 2 support needs the `typed_ast`
dependency, which be installed with `pip install black[python2]`. If you want to format
Jupyter Notebooks, install with `pip install black[jupyter]`.
run. If you want to format Jupyter Notebooks, install with `pip install black[jupyter]`.

If you can't wait for the latest _hotness_ and want to install from GitHub, use:

Expand Down
4 changes: 2 additions & 2 deletions docs/integrations/github_actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ environment. Great for enforcing that your code matches the _Black_ code style.
This action is known to support all GitHub-hosted runner OSes. In addition, only
published versions of _Black_ are supported (i.e. whatever is available on PyPI).

Finally, this action installs _Black_ with both the `colorama` and `python2` extras so
the `--color` flag and formatting Python 2 code are supported.
Finally, this action installs _Black_ with the `colorama` extra so the `--color` flag
should work fine.

## Usage

Expand Down
3 changes: 1 addition & 2 deletions docs/the_black_code_style/current_style.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,7 @@ removed.

_Black_ standardizes most numeric literals to use lowercase letters for the syntactic
parts and uppercase letters for the digits themselves: `0xAB` instead of `0XAB` and
`1e10` instead of `1E10`. Python 2 long literals are styled as `2L` instead of `2l` to
avoid confusion between `l` and `1`.
`1e10` instead of `1E10`.

### Line breaks & binary operators

Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ build-backend = "setuptools.build_meta"
[tool.pytest.ini_options]
# Option below requires `tests/optional.py`
optional-tests = [
"no_python2: run when `python2` extra NOT installed",
"no_blackd: run when `d` extra NOT installed",
"no_jupyter: run when `jupyter` extra NOT installed",
]
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ def find_python_files(base: Path) -> List[Path]:
extras_require={
"d": ["aiohttp>=3.7.4"],
"colorama": ["colorama>=0.4.3"],
"python2": ["typed-ast>=1.4.3"],
"uvloop": ["uvloop>=0.15.2"],
"jupyter": ["ipython>=7.8.0", "tokenize-rt>=3.2.0"],
},
Expand Down
48 changes: 1 addition & 47 deletions src/black/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1083,20 +1083,8 @@ def f(
else:
versions = detect_target_versions(src_node, future_imports=future_imports)

# TODO: fully drop support and this code hopefully in January 2022 :D
if TargetVersion.PY27 in mode.target_versions or versions == {TargetVersion.PY27}:
msg = (
"DEPRECATION: Python 2 support will be removed in the first stable release "
"expected in January 2022."
)
err(msg, fg="yellow", bold=True)

normalize_fmt_off(src_node)
lines = LineGenerator(
mode=mode,
remove_u_prefix="unicode_literals" in future_imports
or supports_feature(versions, Feature.UNICODE_LITERALS),
)
lines = LineGenerator(mode=mode)
elt = EmptyLineTracker(is_pyi=mode.is_pyi)
empty_line = Line(mode=mode)
after = 0
Expand Down Expand Up @@ -1166,14 +1154,6 @@ def get_features_used( # noqa: C901
assert isinstance(n, Leaf)
if "_" in n.value:
features.add(Feature.NUMERIC_UNDERSCORES)
elif n.value.endswith(("L", "l")):
# Python 2: 10L
features.add(Feature.LONG_INT_LITERAL)
elif len(n.value) >= 2 and n.value[0] == "0" and n.value[1].isdigit():
# Python 2: 0123; 00123; ...
if not all(char == "0" for char in n.value):
# although we don't want to match 0000 or similar
features.add(Feature.OCTAL_INT_LITERAL)

elif n.type == token.SLASH:
if n.parent and n.parent.type in {
Expand Down Expand Up @@ -1226,32 +1206,6 @@ def get_features_used( # noqa: C901
):
features.add(Feature.ANN_ASSIGN_EXTENDED_RHS)

# Python 2 only features (for its deprecation) except for integers, see above
elif n.type == syms.print_stmt:
features.add(Feature.PRINT_STMT)
elif n.type == syms.exec_stmt:
features.add(Feature.EXEC_STMT)
elif n.type == syms.tfpdef:
# def set_position((x, y), value):
# ...
features.add(Feature.AUTOMATIC_PARAMETER_UNPACKING)
elif n.type == syms.except_clause:
# try:
# ...
# except Exception, err:
# ...
if len(n.children) >= 4:
if n.children[-2].type == token.COMMA:
features.add(Feature.COMMA_STYLE_EXCEPT)
elif n.type == syms.raise_stmt:
# raise Exception, "msg"
if len(n.children) >= 4:
if n.children[-2].type == token.COMMA:
features.add(Feature.COMMA_STYLE_RAISE)
elif n.type == token.BACKQUOTE:
# `i'm surprised this ever existed`
features.add(Feature.BACKQUOTE_REPR)

return features


Expand Down
9 changes: 3 additions & 6 deletions src/black/linegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,8 @@ class LineGenerator(Visitor[Line]):
in ways that will no longer stringify to valid Python code on the tree.
"""

def __init__(self, mode: Mode, remove_u_prefix: bool = False) -> None:
def __init__(self, mode: Mode) -> None:
self.mode = mode
self.remove_u_prefix = remove_u_prefix
self.current_line: Line
self.__post_init__()

Expand Down Expand Up @@ -92,9 +91,7 @@ def visit_default(self, node: LN) -> Iterator[Line]:

normalize_prefix(node, inside_brackets=any_open_brackets)
if self.mode.string_normalization and node.type == token.STRING:
node.value = normalize_string_prefix(
node.value, remove_u_prefix=self.remove_u_prefix
)
node.value = normalize_string_prefix(node.value)
node.value = normalize_string_quotes(node.value)
if node.type == token.NUMBER:
normalize_numeric_literal(node)
Expand Down Expand Up @@ -236,7 +233,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
if is_docstring(leaf) and "\\\n" not in leaf.value:
# We're ignoring docstrings with backslash newline escapes because changing
# indentation of those changes the AST representation of the code.
docstring = normalize_string_prefix(leaf.value, self.remove_u_prefix)
docstring = normalize_string_prefix(leaf.value)
prefix = get_string_prefix(docstring)
docstring = docstring[len(prefix) :] # Remove the prefix
quote_char = docstring[0]
Expand Down
66 changes: 15 additions & 51 deletions src/black/mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@


class TargetVersion(Enum):
PY27 = 2
PY33 = 3
PY34 = 4
PY35 = 5
Expand All @@ -30,77 +29,45 @@ class TargetVersion(Enum):
PY39 = 9
PY310 = 10

def is_python2(self) -> bool:
return self is TargetVersion.PY27


class Feature(Enum):
# All string literals are unicode
UNICODE_LITERALS = 1
F_STRINGS = 2
NUMERIC_UNDERSCORES = 3
TRAILING_COMMA_IN_CALL = 4
TRAILING_COMMA_IN_DEF = 5
F_STRINGS = 1
NUMERIC_UNDERSCORES = 2
TRAILING_COMMA_IN_CALL = 3
TRAILING_COMMA_IN_DEF = 4
# The following two feature-flags are mutually exclusive, and exactly one should be
# set for every version of python.
ASYNC_IDENTIFIERS = 6
ASYNC_KEYWORDS = 7
ASSIGNMENT_EXPRESSIONS = 8
POS_ONLY_ARGUMENTS = 9
RELAXED_DECORATORS = 10
PATTERN_MATCHING = 11
UNPACKING_ON_FLOW = 12
ANN_ASSIGN_EXTENDED_RHS = 13
ASYNC_IDENTIFIERS = 5
ASYNC_KEYWORDS = 6
ASSIGNMENT_EXPRESSIONS = 7
POS_ONLY_ARGUMENTS = 8
RELAXED_DECORATORS = 9
PATTERN_MATCHING = 10
UNPACKING_ON_FLOW = 11
ANN_ASSIGN_EXTENDED_RHS = 12
FORCE_OPTIONAL_PARENTHESES = 50

# __future__ flags
FUTURE_ANNOTATIONS = 51

# temporary for Python 2 deprecation
PRINT_STMT = 200
EXEC_STMT = 201
AUTOMATIC_PARAMETER_UNPACKING = 202
COMMA_STYLE_EXCEPT = 203
COMMA_STYLE_RAISE = 204
LONG_INT_LITERAL = 205
OCTAL_INT_LITERAL = 206
BACKQUOTE_REPR = 207


FUTURE_FLAG_TO_FEATURE: Final = {
"annotations": Feature.FUTURE_ANNOTATIONS,
}


VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
TargetVersion.PY27: {
Feature.ASYNC_IDENTIFIERS,
Feature.PRINT_STMT,
Feature.EXEC_STMT,
Feature.AUTOMATIC_PARAMETER_UNPACKING,
Feature.COMMA_STYLE_EXCEPT,
Feature.COMMA_STYLE_RAISE,
Feature.LONG_INT_LITERAL,
Feature.OCTAL_INT_LITERAL,
Feature.BACKQUOTE_REPR,
},
TargetVersion.PY33: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS},
TargetVersion.PY34: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS},
TargetVersion.PY35: {
Feature.UNICODE_LITERALS,
Feature.TRAILING_COMMA_IN_CALL,
Feature.ASYNC_IDENTIFIERS,
},
TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS},
TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS},
TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS},
TargetVersion.PY36: {
Feature.UNICODE_LITERALS,
Feature.F_STRINGS,
Feature.NUMERIC_UNDERSCORES,
Feature.TRAILING_COMMA_IN_CALL,
Feature.TRAILING_COMMA_IN_DEF,
Feature.ASYNC_IDENTIFIERS,
},
TargetVersion.PY37: {
Feature.UNICODE_LITERALS,
Feature.F_STRINGS,
Feature.NUMERIC_UNDERSCORES,
Feature.TRAILING_COMMA_IN_CALL,
Expand All @@ -109,7 +76,6 @@ class Feature(Enum):
Feature.FUTURE_ANNOTATIONS,
},
TargetVersion.PY38: {
Feature.UNICODE_LITERALS,
Feature.F_STRINGS,
Feature.NUMERIC_UNDERSCORES,
Feature.TRAILING_COMMA_IN_CALL,
Expand All @@ -122,7 +88,6 @@ class Feature(Enum):
Feature.ANN_ASSIGN_EXTENDED_RHS,
},
TargetVersion.PY39: {
Feature.UNICODE_LITERALS,
Feature.F_STRINGS,
Feature.NUMERIC_UNDERSCORES,
Feature.TRAILING_COMMA_IN_CALL,
Expand All @@ -136,7 +101,6 @@ class Feature(Enum):
Feature.ANN_ASSIGN_EXTENDED_RHS,
},
TargetVersion.PY310: {
Feature.UNICODE_LITERALS,
Feature.F_STRINGS,
Feature.NUMERIC_UNDERSCORES,
Feature.TRAILING_COMMA_IN_CALL,
Expand Down
10 changes: 0 additions & 10 deletions src/black/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,16 +259,6 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa: C901
):
return NO

elif (
prevp.type == token.RIGHTSHIFT
and prevp.parent
and prevp.parent.type == syms.shift_expr
and prevp.prev_sibling
and is_name_token(prevp.prev_sibling)
and prevp.prev_sibling.value == "print"
):
# Python 2 print chevron
return NO
elif prevp.type == token.AT and p.parent and p.parent.type == syms.decorator:
# no space in decorators
return NO
Expand Down
15 changes: 5 additions & 10 deletions src/black/numerics.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,10 @@ def format_scientific_notation(text: str) -> str:
return f"{before}e{sign}{after}"


def format_long_or_complex_number(text: str) -> str:
"""Formats a long or complex string like `10L` or `10j`"""
def format_complex_number(text: str) -> str:
"""Formats a complex string like `10j`"""
number = text[:-1]
suffix = text[-1]
# Capitalize in "2L" because "l" looks too similar to "1".
if suffix == "l":
suffix = "L"
return f"{format_float_or_int_string(number)}{suffix}"


Expand All @@ -47,9 +44,7 @@ def format_float_or_int_string(text: str) -> str:
def normalize_numeric_literal(leaf: Leaf) -> None:
"""Normalizes numeric (float, int, and complex) literals.
All letters used in the representation are normalized to lowercase (except
in Python 2 long literals).
"""
All letters used in the representation are normalized to lowercase."""
text = leaf.value.lower()
if text.startswith(("0o", "0b")):
# Leave octal and binary literals alone.
Expand All @@ -58,8 +53,8 @@ def normalize_numeric_literal(leaf: Leaf) -> None:
text = format_hex(text)
elif "e" in text:
text = format_scientific_notation(text)
elif text.endswith(("j", "l")):
text = format_long_or_complex_number(text)
elif text.endswith("j"):
text = format_complex_number(text)
else:
text = format_float_or_int_string(text)
leaf.value = text

0 comments on commit 0a60792

Please sign in to comment.