Drop support for Python 3.7 (#3765)

This commit is contained in:
Shantanu 2023-07-05 10:08:04 -07:00 committed by GitHub
parent cf4cc29819
commit b4dca26c7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 43 additions and 213 deletions

View File

@ -22,7 +22,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3

View File

@ -31,7 +31,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "pypy-3.7", "pypy-3.8"]
python-version: ["3.8", "3.9", "3.10", "3.11", "pypy-3.8"]
os: [ubuntu-latest, macOS-latest, windows-latest]
steps:

View File

@ -6,6 +6,9 @@
<!-- Include any especially major or disruptive changes here -->
- Runtime support for Python 3.7 has been removed. Formatting 3.7 code will still be
supported until further notice (#3765)
### Stable style
<!-- Changes that affect Black's stable style -->

View File

@ -334,60 +334,6 @@ To run _Black_ on a key press (e.g. F9 below), add this:
nnoremap <F9> :Black<CR>
```
#### Troubleshooting
**How to get Vim with Python 3.6?** On Ubuntu 17.10 Vim comes with Python 3.6 by
default. On macOS with Homebrew run: `brew install vim`. When building Vim from source,
use: `./configure --enable-python3interp=yes`. There's many guides online how to do
this.
**I get an import error when using _Black_ from a virtual environment**: If you get an
error message like this:
```text
Traceback (most recent call last):
File "<string>", line 63, in <module>
File "/home/gui/.vim/black/lib/python3.7/site-packages/black.py", line 45, in <module>
from typed_ast import ast3, ast27
File "/home/gui/.vim/black/lib/python3.7/site-packages/typed_ast/ast3.py", line 40, in <module>
from typed_ast import _ast3
ImportError: /home/gui/.vim/black/lib/python3.7/site-packages/typed_ast/_ast3.cpython-37m-x86_64-linux-gnu.so: undefined symbool: PyExc_KeyboardInterrupt
```
Then you need to install `typed_ast` directly from the source code. The error happens
because `pip` will download [Python wheels](https://pythonwheels.com/) if they are
available. Python wheels are a new standard of distributing Python packages and packages
that have Cython and extensions written in C are already compiled, so the installation
is much more faster. The problem here is that somehow the Python environment inside Vim
does not match with those already compiled C extensions and these kind of errors are the
result. Luckily there is an easy fix: installing the packages from the source code.
The package that causes problems is:
- [typed-ast](https://pypi.org/project/typed-ast/)
Now remove those two packages:
```console
$ pip uninstall typed-ast -y
```
And now you can install them with:
```console
$ pip install --no-binary :all: typed-ast
```
The C extensions will be compiled and now Vim's Python environment will match. Note that
you need to have the GCC compiler and the Python development files installed (on
Ubuntu/Debian do `sudo apt-get install build-essential python3-dev`).
If you later want to update _Black_, you should do it like this:
```console
$ pip install -U black --no-binary typed-ast
```
### With ALE
1. Install [`ale`](https://github.com/dense-analysis/ale)

View File

@ -2,7 +2,7 @@
# Specify the target platform details in config, so your developers are
# free to run mypy on Windows, Linux, or macOS and get consistent
# results.
python_version=3.7
python_version=3.8
mypy_path=src

View File

@ -33,7 +33,7 @@ build-backend = "hatchling.build"
name = "black"
description = "The uncompromising code formatter."
license = { text = "MIT" }
requires-python = ">=3.7"
requires-python = ">=3.8"
authors = [
{ name = "Łukasz Langa", email = "lukasz@langa.pl" },
]
@ -69,7 +69,6 @@ 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'",
]
dynamic = ["readme", "version"]
@ -121,8 +120,6 @@ enable-by-default = false
dependencies = [
"hatch-mypyc>=0.16.0",
"mypy==1.3",
# Required stubs to be removed when the packages support PEP 561 themselves
"types-typed-ast>=1.4.2",
]
require-runtime-dependencies = true
exclude = [
@ -145,7 +142,7 @@ options = { debug_level = "0" }
[tool.cibuildwheel]
build-verbosity = 1
# So these are the environments we target:
# - Python: CPython 3.7+ only
# - Python: CPython 3.8+ only
# - Architecture (64-bit only): amd64 / x86_64, universal2, and arm64
# - OS: Linux (no musl), Windows, and macOS
build = "cp3*-*"
@ -208,9 +205,6 @@ 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''',

View File

@ -52,13 +52,7 @@ def main() -> None:
f.write(f"""# Generated by {basename(__file__)}
# wcwidth {wcwidth.__version__}
# Unicode {wcwidth.list_versions()[-1]}
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[List[Tuple[int, int, int]]] = [
""")

View File

@ -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[List[Tuple[int, int, int]]] = [
(0, 0, 0),

View File

@ -1,13 +1,7 @@
"""Builds on top of nodes.py to track brackets."""
import sys
from dataclasses import dataclass, field
from typing import Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union
if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final
from typing import Dict, Final, Iterable, List, Optional, Sequence, Set, Tuple, Union
from black.nodes import (
BRACKET,

View File

@ -1,13 +1,7 @@
import re
import sys
from dataclasses import dataclass
from functools import lru_cache
from typing import Iterator, List, Optional, Union
if sys.version_info >= (3, 8):
from typing import Final
else:
from typing_extensions import Final
from typing import Final, Iterator, List, Optional, Union
from black.nodes import (
CLOSING_BRACKETS,

View File

@ -4,19 +4,13 @@
chosen by the user.
"""
import sys
from dataclasses import dataclass, field
from enum import Enum, auto
from hashlib import sha256
from operator import attrgetter
from typing import Dict, Set
from typing import Dict, Final, Set
from warnings import warn
if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final
from black.const import DEFAULT_LINE_LENGTH

View File

@ -3,12 +3,8 @@
"""
import sys
from typing import Generic, Iterator, List, Optional, Set, Tuple, TypeVar, Union
from typing import Final, Generic, Iterator, List, Optional, Set, Tuple, TypeVar, Union
if sys.version_info >= (3, 8):
from typing import Final
else:
from typing_extensions import Final
if sys.version_info >= (3, 10):
from typing import TypeGuard
else:

View File

@ -2,14 +2,8 @@
Parse Python code and perform AST validation.
"""
import ast
import platform
import sys
from typing import Any, Iterable, Iterator, List, Set, Tuple, Type, Union
if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final
from typing import Final, Iterable, Iterator, List, Set, Tuple
from black.mode import VERSION_TO_FEATURES, Feature, TargetVersion, supports_feature
from black.nodes import syms
@ -20,25 +14,6 @@
from blib2to3.pgen2.tokenize import TokenError
from blib2to3.pytree import Leaf, Node
ast3: Any
_IS_PYPY = platform.python_implementation() == "PyPy"
try:
from typed_ast import ast3
except ImportError:
if sys.version_info < (3, 8) and not _IS_PYPY:
print(
"The typed_ast package is required but not installed.\n"
"You can upgrade to Python 3.8+ or install typed_ast with\n"
"`python3 -m pip install typed-ast`.",
file=sys.stderr,
)
sys.exit(1)
else:
ast3 = ast
PY2_HINT: Final = "Python 2 support was removed in version 22.0."
@ -147,31 +122,14 @@ def lib2to3_unparse(node: Node) -> str:
def parse_single_version(
src: str, version: Tuple[int, int], *, type_comments: bool
) -> Union[ast.AST, ast3.AST]:
) -> ast.AST:
filename = "<unknown>"
# typed-ast is needed because of feature version limitations in the builtin ast 3.8>
if sys.version_info >= (3, 8) and version >= (3,):
return ast.parse(
src, filename, feature_version=version, type_comments=type_comments
)
if _IS_PYPY:
# PyPy 3.7 doesn't support type comment tracking which is not ideal, but there's
# not much we can do as typed-ast won't work either.
if sys.version_info >= (3, 8):
return ast3.parse(src, filename, type_comments=type_comments)
else:
return ast3.parse(src, filename)
else:
if type_comments:
# Typed-ast is guaranteed to be used here and automatically tracks type
# comments separately.
return ast3.parse(src, filename, feature_version=version[1])
else:
return ast.parse(src, filename)
def parse_ast(src: str) -> Union[ast.AST, ast3.AST]:
def parse_ast(src: str) -> ast.AST:
# TODO: support Python 4+ ;)
versions = [(3, minor) for minor in range(3, sys.version_info[1] + 1)]
@ -193,9 +151,6 @@ def parse_ast(src: str) -> Union[ast.AST, ast3.AST]:
raise SyntaxError(first_error)
ast3_AST: Final[Type[ast3.AST]] = ast3.AST
def _normalize(lineend: str, value: str) -> str:
# To normalize, we strip any leading and trailing space from
# each line...
@ -206,22 +161,24 @@ def _normalize(lineend: str, value: str) -> str:
return normalized.strip()
def stringify_ast(node: Union[ast.AST, ast3.AST], depth: int = 0) -> Iterator[str]:
def stringify_ast(node: ast.AST, depth: int = 0) -> Iterator[str]:
"""Simple visitor generating strings to compare ASTs by content."""
node = fixup_ast_constants(node)
if (
isinstance(node, ast.Constant)
and isinstance(node.value, str)
and node.kind == "u"
):
# It's a quirk of history that we strip the u prefix over here. We used to
# rewrite the AST nodes for Python version compatibility and we never copied
# over the kind
node.kind = None
yield f"{' ' * depth}{node.__class__.__name__}("
type_ignore_classes: Tuple[Type[Any], ...]
for field in sorted(node._fields): # noqa: F402
# TypeIgnore will not be present using pypy < 3.8, so need for this
if not (_IS_PYPY and sys.version_info < (3, 8)):
# TypeIgnore has only one field 'lineno' which breaks this comparison
type_ignore_classes = (ast3.TypeIgnore,)
if sys.version_info >= (3, 8):
type_ignore_classes += (ast.TypeIgnore,)
if isinstance(node, type_ignore_classes):
if isinstance(node, ast.TypeIgnore):
break
try:
@ -237,22 +194,16 @@ def stringify_ast(node: Union[ast.AST, ast3.AST], depth: int = 0) -> Iterator[st
# parentheses and they change the AST.
if (
field == "targets"
and isinstance(node, (ast.Delete, ast3.Delete))
and isinstance(item, (ast.Tuple, ast3.Tuple))
and isinstance(node, ast.Delete)
and isinstance(item, ast.Tuple)
):
for elt in item.elts:
yield from stringify_ast(elt, depth + 2)
elif isinstance(item, (ast.AST, ast3.AST)):
elif isinstance(item, ast.AST):
yield from stringify_ast(item, depth + 2)
# Note that we are referencing the typed-ast ASTs via global variables and not
# direct module attribute accesses because that breaks mypyc. It's probably
# something to do with the ast3 variables being marked as Any leading
# mypy to think this branch is always taken, leaving the rest of the code
# unanalyzed. Tighting up the types for the typed-ast AST types avoids the
# mypyc crash.
elif isinstance(value, (ast.AST, ast3_AST)):
elif isinstance(value, ast.AST):
yield from stringify_ast(value, depth + 2)
else:
@ -271,17 +222,3 @@ def stringify_ast(node: Union[ast.AST, ast3.AST], depth: int = 0) -> Iterator[st
yield f"{' ' * (depth+2)}{normalized!r}, # {value.__class__.__name__}"
yield f"{' ' * depth}) # /{node.__class__.__name__}"
def fixup_ast_constants(node: Union[ast.AST, ast3.AST]) -> Union[ast.AST, ast3.AST]:
"""Map ast nodes deprecated in 3.8 to Constant."""
if isinstance(node, (ast.Str, ast3.Str, ast.Bytes, ast3.Bytes)):
return ast.Constant(value=node.s)
if isinstance(node, (ast.Num, ast3.Num)):
return ast.Constant(value=node.n)
if isinstance(node, (ast.NameConstant, ast3.NameConstant)):
return ast.Constant(value=node.value)
return node

View File

@ -5,16 +5,10 @@
import re
import sys
from functools import lru_cache
from typing import List, Match, Pattern
from blib2to3.pytree import Leaf
if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final
from typing import Final, List, Match, Pattern
from black._width_table import WIDTH_TABLE
from blib2to3.pytree import Leaf
STRING_PREFIX_CHARS: Final = "furbFURB" # All possible string prefix characters.
STRING_PREFIX_RE: Final = re.compile(

View File

@ -2,7 +2,6 @@
String transformers that can split and merge strings.
"""
import re
import sys
from abc import ABC, abstractmethod
from collections import defaultdict
from dataclasses import dataclass
@ -12,9 +11,11 @@
ClassVar,
Collection,
Dict,
Final,
Iterable,
Iterator,
List,
Literal,
Optional,
Sequence,
Set,
@ -23,11 +24,6 @@
Union,
)
if sys.version_info < (3, 8):
from typing_extensions import Final, Literal
else:
from typing import Literal, Final
from mypy_extensions import trait
from black.comments import contains_pragma_comment

View File

@ -3,9 +3,6 @@
import sys
from typing import Dict
if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final
# Taken from Python (r53757) and modified to include some tokens

View File

@ -42,10 +42,7 @@
cast,
)
if sys.version_info >= (3, 8):
from typing import Final
else:
from typing_extensions import Final
from blib2to3.pgen2.token import *
from blib2to3.pgen2.grammar import Grammar