From ac018c16cae526eabbd7df5e3c0376ae27a1a0cc Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sun, 15 Sep 2024 18:05:23 -0700 Subject: [PATCH] Require newer aiohttp for blackd (#4451) --- CHANGES.md | 1 + pyproject.toml | 23 ++--------------------- src/blackd/middlewares.py | 23 +++-------------------- tests/test_blackd.py | 34 ---------------------------------- 4 files changed, 6 insertions(+), 75 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b04a12b586d..e5d931a50bb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -34,6 +34,7 @@ - Upgrade version of mypyc used to 1.11.2 (#4450) +- `blackd` now requires a newer version of aiohttp. (#4451) ### Parser diff --git a/pyproject.toml b/pyproject.toml index e9c0823c82a..f04118a8674 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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", @@ -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/*", diff --git a/src/blackd/middlewares.py b/src/blackd/middlewares.py index 4a795d0aec2..75ec9267bd0 100644 --- a/src/blackd/middlewares.py +++ b/src/blackd/middlewares.py @@ -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 diff --git a/tests/test_blackd.py b/tests/test_blackd.py index 59703036dc0..3a9851a8b93 100644 --- a/tests/test_blackd.py +++ b/tests/test_blackd.py @@ -1,5 +1,4 @@ import re -from typing import TYPE_CHECKING, Any, Callable, TypeVar from unittest.mock import patch import pytest @@ -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): @@ -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) @@ -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( @@ -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( @@ -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" @@ -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" @@ -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( "/", @@ -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" @@ -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( "/", @@ -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 @@ -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")