Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove UJSONResponse #1047

Merged
merged 4 commits into from
Nov 8, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ Starlette does not have any hard dependencies, but the following are optional:
* [`itsdangerous`][itsdangerous] - Required for `SessionMiddleware` support.
* [`pyyaml`][pyyaml] - Required for `SchemaGenerator` support.
* [`graphene`][graphene] - Required for `GraphQLApp` support.
* [`ujson`][ujson] - Required if you want to use `UJSONResponse`.

You can install all of these with `pip3 install starlette[full]`.

Expand Down Expand Up @@ -140,7 +139,6 @@ as [one of the fastest Python frameworks available](https://www.techempower.com/

For high throughput loads you should:

* Make sure to install `ujson` and use `UJSONResponse`.
* Run using gunicorn using the `uvicorn` worker class.
* Use one or two workers per-CPU core. (You might need to experiment with this.)
* Disable access logging.
Expand Down Expand Up @@ -178,4 +176,3 @@ gunicorn -k uvicorn.workers.UvicornH11Worker ...
[itsdangerous]: https://pythonhosted.org/itsdangerous/
[sqlalchemy]: https://www.sqlalchemy.org
[pyyaml]: https://pyyaml.org/wiki/PyYAMLDocumentation
[ujson]: https://github.com/esnme/ultrajson
3 changes: 0 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ Starlette does not have any hard dependencies, but the following are optional:
* [`itsdangerous`][itsdangerous] - Required for `SessionMiddleware` support.
* [`pyyaml`][pyyaml] - Required for `SchemaGenerator` support.
* [`graphene`][graphene] - Required for `GraphQLApp` support.
* [`ujson`][ujson] - Required if you want to use `UJSONResponse`.

You can install all of these with `pip3 install starlette[full]`.

Expand Down Expand Up @@ -134,7 +133,6 @@ as [one of the fastest Python frameworks available](https://www.techempower.com/

For high throughput loads you should:

* Make sure to install `ujson` and use `UJSONResponse`.
* Run using Gunicorn using the `uvicorn` worker class.
* Use one or two workers per-CPU core. (You might need to experiment with this.)
* Disable access logging.
Expand Down Expand Up @@ -172,4 +170,3 @@ gunicorn -k uvicorn.workers.UvicornH11Worker ...
[itsdangerous]: https://pythonhosted.org/itsdangerous/
[sqlalchemy]: https://www.sqlalchemy.org
[pyyaml]: https://pyyaml.org/wiki/PyYAMLDocumentation
[ujson]: https://github.com/esnme/ultrajson
28 changes: 16 additions & 12 deletions docs/responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,26 +92,30 @@ async def app(scope, receive, send):
await response(scope, receive, send)
```

### UJSONResponse
#### Custom JSON serialization

A JSON response class that uses the optimised `ujson` library for serialisation.
If you need fine-grained control over JSON serialization, you can subclass
`JSONResponse` and override the `render` method.

Using `ujson` will result in faster JSON serialisation, but is also less careful
than Python's built-in implementation in how it handles some edge-cases.

In general you *probably* want to stick with `JSONResponse` by default unless
you are micro-optimising a particular endpoint.
For example, if you wanted to use a third-party JSON library such as
[orjson](https://pypi.org/project/orjson/):

```python
from starlette.responses import UJSONResponse
from typing import Any

import orjson
from starlette.responses import JSONResponse

async def app(scope, receive, send):
assert scope['type'] == 'http'
response = UJSONResponse({'hello': 'world'})
await response(scope, receive, send)

class OrjsonResponse(JSONResponse):
def render(self, content: Any) -> bytes:
return orjson.dumps(content)
```

In general you *probably* want to stick with `JSONResponse` by default unless
you are micro-optimising a particular endpoint or need to serialize non-standard
object types.

### RedirectResponse

Returns an HTTP redirect. Uses a 307 status code by default.
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ jinja2
python-multipart
pyyaml
requests
ujson

# Testing
autoflake
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def get_packages(package):
"python-multipart",
"pyyaml",
"requests",
"ujson",
]
},
classifiers=[
Expand Down
13 changes: 0 additions & 13 deletions starlette/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@
aiofiles = None # type: ignore
aio_stat = None # type: ignore

try:
import ujson
except ImportError: # pragma: nocover
ujson = None # type: ignore


# Compatibility wrapper for `mimetypes.guess_type` to support `os.PathLike` on <py3.8
def guess_type(
Expand Down Expand Up @@ -172,14 +167,6 @@ def render(self, content: typing.Any) -> bytes:
).encode("utf-8")


class UJSONResponse(JSONResponse):
media_type = "application/json"

def render(self, content: typing.Any) -> bytes:
assert ujson is not None, "ujson must be installed to use UJSONResponse"
return ujson.dumps(content, ensure_ascii=False).encode("utf-8")


class RedirectResponse(Response):
def __init__(
self,
Expand Down
11 changes: 0 additions & 11 deletions tests/test_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
RedirectResponse,
Response,
StreamingResponse,
UJSONResponse,
)
from starlette.testclient import TestClient

Expand All @@ -37,16 +36,6 @@ async def app(scope, receive, send):
assert response.content == b"xxxxx"


def test_ujson_response():
async def app(scope, receive, send):
response = UJSONResponse({"hello": "world"})
await response(scope, receive, send)

client = TestClient(app)
response = client.get("/")
assert response.json() == {"hello": "world"}


def test_json_none_response():
async def app(scope, receive, send):
response = JSONResponse(None)
Expand Down