Allow install under pypy (#2559)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com>
This commit is contained in:
parent
1e0ec543ff
commit
eb9d0396cd
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
|
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.7"]
|
||||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -41,9 +41,15 @@ jobs:
|
|||||||
python -m pip install --upgrade tox
|
python -m pip install --upgrade tox
|
||||||
|
|
||||||
- name: Unit tests
|
- name: Unit tests
|
||||||
|
if: "!startsWith(matrix.python-version, 'pypy')"
|
||||||
run: |
|
run: |
|
||||||
tox -e ci-py -- -v --color=yes
|
tox -e ci-py -- -v --color=yes
|
||||||
|
|
||||||
|
- name: Unit tests pypy
|
||||||
|
if: "startsWith(matrix.python-version, 'pypy')"
|
||||||
|
run: |
|
||||||
|
tox -e ci-pypy3 -- -v --color=yes
|
||||||
|
|
||||||
- name: Publish coverage to Coveralls
|
- name: Publish coverage to Coveralls
|
||||||
# If pushed / is a pull request against main repo AND
|
# If pushed / is a pull request against main repo AND
|
||||||
# we're running on Linux (this action only supports Linux)
|
# we're running on Linux (this action only supports Linux)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
- Warn about Python 2 deprecation in more cases by improving Python 2 only syntax
|
- Warn about Python 2 deprecation in more cases by improving Python 2 only syntax
|
||||||
detection (#2592)
|
detection (#2592)
|
||||||
|
- Add experimental PyPy support (#2559)
|
||||||
- Add partial support for the match statement. As it's experimental, it's only enabled
|
- Add partial support for the match statement. As it's experimental, it's only enabled
|
||||||
when `--target-version py310` is explicitly specified (#2586)
|
when `--target-version py310` is explicitly specified (#2586)
|
||||||
- Add support for parenthesized with (#2586)
|
- Add support for parenthesized with (#2586)
|
||||||
|
@ -92,3 +92,8 @@ influence their behavior. While Black does its best to recognize such comments a
|
|||||||
them in the right place, this detection is not and cannot be perfect. Therefore, you'll
|
them in the right place, this detection is not and cannot be perfect. Therefore, you'll
|
||||||
sometimes have to manually move these comments to the right place after you format your
|
sometimes have to manually move these comments to the right place after you format your
|
||||||
codebase with _Black_.
|
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.
|
||||||
|
2
setup.py
2
setup.py
@ -75,7 +75,7 @@ def get_long_description() -> str:
|
|||||||
"click>=7.1.2",
|
"click>=7.1.2",
|
||||||
"platformdirs>=2",
|
"platformdirs>=2",
|
||||||
"tomli>=0.2.6,<2.0.0",
|
"tomli>=0.2.6,<2.0.0",
|
||||||
"typed-ast>=1.4.2; python_version < '3.8'",
|
"typed-ast>=1.4.2; python_version < '3.8' and implementation_name == 'cpython'",
|
||||||
"regex>=2020.1.8",
|
"regex>=2020.1.8",
|
||||||
"pathspec>=0.9.0, <1",
|
"pathspec>=0.9.0, <1",
|
||||||
"dataclasses>=0.6; python_version < '3.7'",
|
"dataclasses>=0.6; python_version < '3.7'",
|
||||||
|
@ -35,7 +35,7 @@ def read_cache(mode: Mode) -> Cache:
|
|||||||
with cache_file.open("rb") as fobj:
|
with cache_file.open("rb") as fobj:
|
||||||
try:
|
try:
|
||||||
cache: Cache = pickle.load(fobj)
|
cache: Cache = pickle.load(fobj)
|
||||||
except (pickle.UnpicklingError, ValueError):
|
except (pickle.UnpicklingError, ValueError, IndexError):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
return cache
|
return cache
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
Parse Python code and perform AST validation.
|
Parse Python code and perform AST validation.
|
||||||
"""
|
"""
|
||||||
import ast
|
import ast
|
||||||
|
import platform
|
||||||
import sys
|
import sys
|
||||||
from typing import Iterable, Iterator, List, Set, Union, Tuple
|
from typing import Iterable, Iterator, List, Set, Union, Tuple
|
||||||
|
|
||||||
@ -15,10 +16,13 @@
|
|||||||
from black.mode import TargetVersion, Feature, supports_feature
|
from black.mode import TargetVersion, Feature, supports_feature
|
||||||
from black.nodes import syms
|
from black.nodes import syms
|
||||||
|
|
||||||
|
_IS_PYPY = platform.python_implementation() == "PyPy"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typed_ast import ast3, ast27
|
from typed_ast import ast3, ast27
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if sys.version_info < (3, 8):
|
# Either our python version is too low, or we're on pypy
|
||||||
|
if sys.version_info < (3, 7) or (sys.version_info < (3, 8) and not _IS_PYPY):
|
||||||
print(
|
print(
|
||||||
"The typed_ast package is required but not installed.\n"
|
"The typed_ast package is required but not installed.\n"
|
||||||
"You can upgrade to Python 3.8+ or install typed_ast with\n"
|
"You can upgrade to Python 3.8+ or install typed_ast with\n"
|
||||||
@ -117,7 +121,10 @@ def parse_single_version(
|
|||||||
if sys.version_info >= (3, 8) and version >= (3,):
|
if sys.version_info >= (3, 8) and version >= (3,):
|
||||||
return ast.parse(src, filename, feature_version=version)
|
return ast.parse(src, filename, feature_version=version)
|
||||||
elif version >= (3,):
|
elif version >= (3,):
|
||||||
return ast3.parse(src, filename, feature_version=version[1])
|
if _IS_PYPY:
|
||||||
|
return ast3.parse(src, filename)
|
||||||
|
else:
|
||||||
|
return ast3.parse(src, filename, feature_version=version[1])
|
||||||
elif version == (2, 7):
|
elif version == (2, 7):
|
||||||
return ast27.parse(src)
|
return ast27.parse(src)
|
||||||
raise AssertionError("INTERNAL ERROR: Tried parsing unsupported Python version!")
|
raise AssertionError("INTERNAL ERROR: Tried parsing unsupported Python version!")
|
||||||
@ -151,12 +158,14 @@ def stringify_ast(
|
|||||||
yield f"{' ' * depth}{node.__class__.__name__}("
|
yield f"{' ' * depth}{node.__class__.__name__}("
|
||||||
|
|
||||||
for field in sorted(node._fields): # noqa: F402
|
for field in sorted(node._fields): # noqa: F402
|
||||||
# TypeIgnore has only one field 'lineno' which breaks this comparison
|
# TypeIgnore will not be present using pypy < 3.8, so need for this
|
||||||
type_ignore_classes = (ast3.TypeIgnore, ast27.TypeIgnore)
|
if not (_IS_PYPY and sys.version_info < (3, 8)):
|
||||||
if sys.version_info >= (3, 8):
|
# TypeIgnore has only one field 'lineno' which breaks this comparison
|
||||||
type_ignore_classes += (ast.TypeIgnore,)
|
type_ignore_classes = (ast3.TypeIgnore, ast27.TypeIgnore)
|
||||||
if isinstance(node, type_ignore_classes):
|
if sys.version_info >= (3, 8):
|
||||||
break
|
type_ignore_classes += (ast.TypeIgnore,)
|
||||||
|
if isinstance(node, type_ignore_classes):
|
||||||
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
value = getattr(node, field)
|
value = getattr(node, field)
|
||||||
|
@ -944,7 +944,7 @@ def test_broken_symlink(self) -> None:
|
|||||||
symlink = workspace / "broken_link.py"
|
symlink = workspace / "broken_link.py"
|
||||||
try:
|
try:
|
||||||
symlink.symlink_to("nonexistent.py")
|
symlink.symlink_to("nonexistent.py")
|
||||||
except OSError as e:
|
except (OSError, NotImplementedError) as e:
|
||||||
self.skipTest(f"Can't create symlinks: {e}")
|
self.skipTest(f"Can't create symlinks: {e}")
|
||||||
self.invokeBlack([str(workspace.resolve())])
|
self.invokeBlack([str(workspace.resolve())])
|
||||||
|
|
||||||
|
27
tox.ini
27
tox.ini
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = {,ci-}py{36,37,38,39,310},fuzz
|
envlist = {,ci-}py{36,37,38,39,310,py3},fuzz
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv = PYTHONPATH = {toxinidir}/src
|
setenv = PYTHONPATH = {toxinidir}/src
|
||||||
@ -31,6 +31,31 @@ commands =
|
|||||||
--cov --cov-append {posargs}
|
--cov --cov-append {posargs}
|
||||||
coverage report
|
coverage report
|
||||||
|
|
||||||
|
[testenv:{,ci-}pypy3]
|
||||||
|
setenv = PYTHONPATH = {toxinidir}/src
|
||||||
|
skip_install = True
|
||||||
|
recreate = True
|
||||||
|
deps =
|
||||||
|
-r{toxinidir}/test_requirements.txt
|
||||||
|
; a separate worker is required in ci due to https://foss.heptapod.net/pypy/pypy/-/issues/3317
|
||||||
|
; this seems to cause tox to wait forever
|
||||||
|
; remove this when pypy releases the bugfix
|
||||||
|
commands =
|
||||||
|
pip install -e .[d]
|
||||||
|
coverage erase
|
||||||
|
pytest tests --run-optional no_python2 \
|
||||||
|
--run-optional no_jupyter \
|
||||||
|
!ci: --numprocesses auto \
|
||||||
|
ci: --numprocesses 1 \
|
||||||
|
--cov {posargs}
|
||||||
|
pip install -e .[jupyter]
|
||||||
|
pytest tests --run-optional jupyter \
|
||||||
|
-m jupyter \
|
||||||
|
!ci: --numprocesses auto \
|
||||||
|
ci: --numprocesses 1 \
|
||||||
|
--cov --cov-append {posargs}
|
||||||
|
coverage report
|
||||||
|
|
||||||
[testenv:fuzz]
|
[testenv:fuzz]
|
||||||
skip_install = True
|
skip_install = True
|
||||||
deps =
|
deps =
|
||||||
|
Loading…
Reference in New Issue
Block a user