Add black version header to blackd responses (#1046)

This commit is contained in:
Linus Groh 2019-10-13 20:35:31 +02:00 committed by Zsolt Dollenstein
parent 57ab909bde
commit 73bd7038fb
3 changed files with 34 additions and 12 deletions

View File

@ -893,6 +893,9 @@ Apart from the above, `blackd` can produce the following response codes:
- `HTTP 500`: If there was any kind of error while trying to format the input. - `HTTP 500`: If there was any kind of error while trying to format the input.
The response body contains a textual representation of the error. The response body contains a textual representation of the error.
The response headers include a `X-Black-Version` header containing the version
of *Black*.
## Version control integration ## Version control integration
Use [pre-commit](https://pre-commit.com/). Once you [have it Use [pre-commit](https://pre-commit.com/). Once you [have it
@ -1051,6 +1054,8 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
* *Black* is now able to format Python code that uses positional-only * *Black* is now able to format Python code that uses positional-only
arguments (`/` as described in PEP-570) (#946) arguments (`/` as described in PEP-570) (#946)
* `blackd` now returns the version of *Black* in the response headers (#1013)
### 19.3b0 ### 19.3b0

View File

@ -10,23 +10,29 @@
import black import black
import click import click
from _version import version as __version__
# This is used internally by tests to shut down the server prematurely # This is used internally by tests to shut down the server prematurely
_stop_signal = asyncio.Event() _stop_signal = asyncio.Event()
VERSION_HEADER = "X-Protocol-Version" # Request headers
PROTOCOL_VERSION_HEADER = "X-Protocol-Version"
LINE_LENGTH_HEADER = "X-Line-Length" LINE_LENGTH_HEADER = "X-Line-Length"
PYTHON_VARIANT_HEADER = "X-Python-Variant" PYTHON_VARIANT_HEADER = "X-Python-Variant"
SKIP_STRING_NORMALIZATION_HEADER = "X-Skip-String-Normalization" SKIP_STRING_NORMALIZATION_HEADER = "X-Skip-String-Normalization"
FAST_OR_SAFE_HEADER = "X-Fast-Or-Safe" FAST_OR_SAFE_HEADER = "X-Fast-Or-Safe"
BLACK_HEADERS = [ BLACK_HEADERS = [
VERSION_HEADER, PROTOCOL_VERSION_HEADER,
LINE_LENGTH_HEADER, LINE_LENGTH_HEADER,
PYTHON_VARIANT_HEADER, PYTHON_VARIANT_HEADER,
SKIP_STRING_NORMALIZATION_HEADER, SKIP_STRING_NORMALIZATION_HEADER,
FAST_OR_SAFE_HEADER, FAST_OR_SAFE_HEADER,
] ]
# Response headers
BLACK_VERSION_HEADER = "X-Black-Version"
class InvalidVariantHeader(Exception): class InvalidVariantHeader(Exception):
pass pass
@ -65,8 +71,9 @@ def make_app() -> web.Application:
async def handle(request: web.Request, executor: Executor) -> web.Response: async def handle(request: web.Request, executor: Executor) -> web.Response:
headers = {BLACK_VERSION_HEADER: __version__}
try: try:
if request.headers.get(VERSION_HEADER, "1") != "1": if request.headers.get(PROTOCOL_VERSION_HEADER, "1") != "1":
return web.Response( return web.Response(
status=501, text="This server only supports protocol version 1" status=501, text="This server only supports protocol version 1"
) )
@ -110,15 +117,18 @@ async def handle(request: web.Request, executor: Executor) -> web.Response:
executor, partial(black.format_file_contents, req_str, fast=fast, mode=mode) executor, partial(black.format_file_contents, req_str, fast=fast, mode=mode)
) )
return web.Response( return web.Response(
content_type=request.content_type, charset=charset, text=formatted_str content_type=request.content_type,
charset=charset,
headers=headers,
text=formatted_str,
) )
except black.NothingChanged: except black.NothingChanged:
return web.Response(status=204) return web.Response(status=204, headers=headers)
except black.InvalidInput as e: except black.InvalidInput as e:
return web.Response(status=400, text=str(e)) return web.Response(status=400, headers=headers, text=str(e))
except Exception as e: except Exception as e:
logging.exception("Exception during handling a request") logging.exception("Exception during handling a request")
return web.Response(status=500, text=str(e)) return web.Response(status=500, headers=headers, text=str(e))
def parse_python_variant_header(value: str) -> Tuple[bool, Set[black.TargetVersion]]: def parse_python_variant_header(value: str) -> Tuple[bool, Set[black.TargetVersion]]:

View File

@ -1569,7 +1569,7 @@ async def test_blackd_request_syntax_error(self) -> None:
@unittest_run_loop @unittest_run_loop
async def test_blackd_unsupported_version(self) -> None: async def test_blackd_unsupported_version(self) -> None:
response = await self.client.post( response = await self.client.post(
"/", data=b"what", headers={blackd.VERSION_HEADER: "2"} "/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "2"}
) )
self.assertEqual(response.status, 501) self.assertEqual(response.status, 501)
@ -1578,7 +1578,7 @@ async def test_blackd_unsupported_version(self) -> None:
@unittest_run_loop @unittest_run_loop
async def test_blackd_supported_version(self) -> None: async def test_blackd_supported_version(self) -> None:
response = await self.client.post( response = await self.client.post(
"/", data=b"what", headers={blackd.VERSION_HEADER: "1"} "/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "1"}
) )
self.assertEqual(response.status, 200) self.assertEqual(response.status, 200)
@ -1669,6 +1669,13 @@ async def test_blackd_invalid_line_length(self) -> None:
) )
self.assertEqual(response.status, 400) self.assertEqual(response.status, 400)
@skip_if_exception("ClientOSError")
@unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
@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))
if __name__ == "__main__": if __name__ == "__main__":
unittest.main(module="test_black") unittest.main(module="test_black")