Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<!-- Changes to how Black is packaged, such as dependency requirements -->

- Upgrade version of mypyc used to 1.11.2 (#4450)
- `blackd` now requires a newer version of aiohttp. (#4451)

### Parser

Expand Down
23 changes: 2 additions & 21 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ dynamic = ["readme", "version"]
[project.optional-dependencies]
colorama = ["colorama>=0.4.3"]
uvloop = ["uvloop>=0.15.2"]
d = [
"aiohttp>=3.7.4; sys_platform != 'win32' or implementation_name != 'pypy'",
"aiohttp>=3.7.4, !=3.9.0; sys_platform == 'win32' and implementation_name == 'pypy'",
]
d = ["aiohttp>=3.10"]
jupyter = [
"ipython>=7.8.0",
"tokenize-rt>=3.2.0",
Expand Down Expand Up @@ -219,23 +216,7 @@ markers = [
"incompatible_with_mypyc: run when testing mypyc compiled black"
]
xfail_strict = true
filterwarnings = [
"error",
# this is mitigated by a try/catch in https://github.com/psf/black/pull/2974/
# this ignore can be removed when support for aiohttp 3.7 is dropped.
'''ignore:Decorator `@unittest_run_loop` is no longer needed in aiohttp 3\.8\+:DeprecationWarning''',
# 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''',
# 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",
]
filterwarnings = ["error"]
[tool.coverage.report]
omit = [
"src/blib2to3/*",
Expand Down
23 changes: 3 additions & 20 deletions src/blackd/middlewares.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Iterable, TypeVar
from typing import Awaitable, Callable, Iterable

from aiohttp.typedefs import Middleware
from aiohttp.web_middlewares import middleware
from aiohttp.web_request import Request
from aiohttp.web_response import StreamResponse

Handler = Callable[[Request], Awaitable[StreamResponse]]

if TYPE_CHECKING:
from aiohttp.typedefs import Middleware

F = TypeVar("F", bound=Callable[..., Any])
middleware: Callable[[F], F]
else:
try:
# Available in aiohttp 3.9 and newer
from aiohttp.typedefs import Middleware
except ImportError:
Middleware = Callable[[Request, Handler], Awaitable[StreamResponse]]

try:
from aiohttp.web_middlewares import middleware
except ImportError:
# @middleware is deprecated and its behaviour is the default since aiohttp 4.0
# so if it doesn't exist anymore, define a no-op for forward compatibility.
middleware = lambda x: x # noqa: E731


def cors(allow_headers: Iterable[str]) -> Middleware:
@middleware
Expand Down
34 changes: 0 additions & 34 deletions tests/test_blackd.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import re
from typing import TYPE_CHECKING, Any, Callable, TypeVar
from unittest.mock import patch

import pytest
Expand All @@ -15,20 +14,6 @@
except ImportError as e:
raise RuntimeError("Please install Black with the 'd' extra") from e

if TYPE_CHECKING:
F = TypeVar("F", bound=Callable[..., Any])

unittest_run_loop: Callable[[F], F] = lambda x: x
else:
try:
from aiohttp.test_utils import unittest_run_loop
except ImportError:
# unittest_run_loop is unnecessary and a no-op since aiohttp 3.8, and
# aiohttp 4 removed it. To maintain compatibility we can make our own
# no-op decorator.
def unittest_run_loop(func, *args, **kwargs):
return func


@pytest.mark.blackd
class BlackDTestCase(AioHTTPTestCase):
Expand All @@ -42,20 +27,17 @@ def test_blackd_main(self) -> None:
async def get_application(self) -> web.Application:
return blackd.make_app()

@unittest_run_loop
async def test_blackd_request_needs_formatting(self) -> None:
response = await self.client.post("/", data=b"print('hello world')")
self.assertEqual(response.status, 200)
self.assertEqual(response.charset, "utf8")
self.assertEqual(await response.read(), b'print("hello world")\n')

@unittest_run_loop
async def test_blackd_request_no_change(self) -> None:
response = await self.client.post("/", data=b'print("hello world")\n')
self.assertEqual(response.status, 204)
self.assertEqual(await response.read(), b"")

@unittest_run_loop
async def test_blackd_request_syntax_error(self) -> None:
response = await self.client.post("/", data=b"what even ( is")
self.assertEqual(response.status, 400)
Expand All @@ -65,21 +47,18 @@ async def test_blackd_request_syntax_error(self) -> None:
msg=f"Expected error to start with 'Cannot parse', got {repr(content)}",
)

@unittest_run_loop
async def test_blackd_unsupported_version(self) -> None:
response = await self.client.post(
"/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "2"}
)
self.assertEqual(response.status, 501)

@unittest_run_loop
async def test_blackd_supported_version(self) -> None:
response = await self.client.post(
"/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "1"}
)
self.assertEqual(response.status, 200)

@unittest_run_loop
async def test_blackd_invalid_python_variant(self) -> None:
async def check(header_value: str, expected_status: int = 400) -> None:
response = await self.client.post(
Expand All @@ -102,7 +81,6 @@ async def check(header_value: str, expected_status: int = 400) -> None:
await check("pypy3.0")
await check("jython3.4")

@unittest_run_loop
async def test_blackd_pyi(self) -> None:
source, expected = read_data("cases", "stub.py")
response = await self.client.post(
Expand All @@ -111,7 +89,6 @@ async def test_blackd_pyi(self) -> None:
self.assertEqual(response.status, 200)
self.assertEqual(await response.text(), expected)

@unittest_run_loop
async def test_blackd_diff(self) -> None:
diff_header = re.compile(
r"(In|Out)\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d\+\d\d:\d\d"
Expand All @@ -129,7 +106,6 @@ async def test_blackd_diff(self) -> None:
actual = diff_header.sub(DETERMINISTIC_HEADER, actual)
self.assertEqual(actual, expected)

@unittest_run_loop
async def test_blackd_python_variant(self) -> None:
code = (
"def f(\n"
Expand Down Expand Up @@ -161,14 +137,12 @@ async def check(header_value: str, expected_status: int) -> None:
await check("py34,py36", 204)
await check("34", 204)

@unittest_run_loop
async def test_blackd_line_length(self) -> None:
response = await self.client.post(
"/", data=b'print("hello")\n', headers={blackd.LINE_LENGTH_HEADER: "7"}
)
self.assertEqual(response.status, 200)

@unittest_run_loop
async def test_blackd_invalid_line_length(self) -> None:
response = await self.client.post(
"/",
Expand All @@ -177,7 +151,6 @@ async def test_blackd_invalid_line_length(self) -> None:
)
self.assertEqual(response.status, 400)

@unittest_run_loop
async def test_blackd_skip_first_source_line(self) -> None:
invalid_first_line = b"Header will be skipped\r\ni = [1,2,3]\nj = [1,2,3]\n"
expected_result = b"Header will be skipped\r\ni = [1, 2, 3]\nj = [1, 2, 3]\n"
Expand All @@ -191,19 +164,16 @@ async def test_blackd_skip_first_source_line(self) -> None:
self.assertEqual(response.status, 200)
self.assertEqual(await response.read(), expected_result)

@unittest_run_loop
async def test_blackd_preview(self) -> None:
response = await self.client.post(
"/", data=b'print("hello")\n', headers={blackd.PREVIEW: "true"}
)
self.assertEqual(response.status, 204)

@unittest_run_loop
async def test_blackd_response_black_version_header(self) -> None:
response = await self.client.post("/")
self.assertIsNotNone(response.headers.get(blackd.BLACK_VERSION_HEADER))

@unittest_run_loop
async def test_cors_preflight(self) -> None:
response = await self.client.options(
"/",
Expand All @@ -218,13 +188,11 @@ async def test_cors_preflight(self) -> None:
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Headers"))
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Methods"))

@unittest_run_loop
async def test_cors_headers_present(self) -> None:
response = await self.client.post("/", headers={"Origin": "*"})
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Origin"))
self.assertIsNotNone(response.headers.get("Access-Control-Expose-Headers"))

@unittest_run_loop
async def test_preserves_line_endings(self) -> None:
for data in (b"c\r\nc\r\n", b"l\nl\n"):
# test preserved newlines when reformatted
Expand All @@ -234,14 +202,12 @@ async def test_preserves_line_endings(self) -> None:
response = await self.client.post("/", data=data)
self.assertEqual(response.status, 204)

@unittest_run_loop
async def test_normalizes_line_endings(self) -> None:
for data, expected in ((b"c\r\nc\n", "c\r\nc\r\n"), (b"l\nl\r\n", "l\nl\n")):
response = await self.client.post("/", data=data)
self.assertEqual(await response.text(), expected)
self.assertEqual(response.status, 200)

@unittest_run_loop
async def test_single_character(self) -> None:
response = await self.client.post("/", data="1")
self.assertEqual(await response.text(), "1\n")
Expand Down