# starlette-cramjam
<p align="center">
<em>Cramjam integration for Starlette ASGI framework.</em>
</p>
<p align="center">
<a href="https://github.com/developmentseed/starlette-cramjam/actions?query=workflow%3ACI" target="_blank">
<img src="https://github.com/developmentseed/starlette-cramjam/workflows/CI/badge.svg" alt="Test">
</a>
<a href="https://codecov.io/gh/developmentseed/starlette-cramjam" target="_blank">
<img src="https://codecov.io/gh/developmentseed/starlette-cramjam/branch/master/graph/badge.svg" alt="Coverage">
</a>
<a href="https://pypi.org/project/starlette-cramjam" target="_blank">
<img src="https://img.shields.io/pypi/v/starlette-cramjam?color=%2334D058&label=pypi%20package" alt="Package version">
</a>
<a href="https://pypistats.org/packages/starlette-cramjam" target="_blank">
<img src="https://img.shields.io/pypi/dm/starlette-cramjam.svg" alt="Downloads">
</a>
<a href="https://github.com/developmentseed/starlette-cramjam/blob/master/LICENSE" target="_blank">
<img src="https://img.shields.io/github/license/developmentseed/starlette-cramjam.svg" alt="Downloads">
</a>
</p>
---
**Source Code**: <a href="https://github.com/developmentseed/starlette-cramjam" target="_blank">https://github.com/developmentseed/starlette-cramjam</a>
---
The `starlette-cramjam` middleware aims to provide a unique Compression middleware to support **Brotli**, **GZip** and **Deflate** compression algorithms with a minimal requirement.
The middleware will compress responses for any request that includes "br", "gzip" or "deflate" in the Accept-Encoding header.
As for the official `Starlette` middleware, the one provided by `starlette-cramjam` will handle both standard and streaming responses.
`stralette-cramjam` is built on top of [pyrus-cramjam](https://github.com/milesgranger/pyrus-cramjam) an *Extremely thin Python bindings to de/compression algorithms in Rust*.
## Installation
You can install `starlette-cramjam` from pypi
```python
$ pip install -U pip
$ pip install starlette-cramjam
```
or install from source:
```bash
$ pip install -U pip
$ pip install https://github.com/developmentseed/starlette-cramjam.git
```
## Usage
The following arguments are supported:
- **compression** (List of Compression) - List of available compression algorithm. **This list also defines the order of preference**. Defaults to `[Compression.gzip, Compression.deflate, Compression.br]`,
- **compression_level** (Integer) - Compression level to use, form `0` (None) to `11` (High). Defaults to cramjam internal defaults for each compression backend.
- **minimum_size** (Integer) - Do not compress responses that are smaller than this minimum size in bytes. Defaults to `500`.
- **exclude_path** (Set of string) - Do not compress responses in response to specific `path` requests. Entries have to be valid regex expressions. Defaults to `{}`.
- **exclude_mediatype** (Set of string) - Do not compress responses of specific media type (e.g `image/png`). Defaults to `{}`.
#### Minimal (defaults) example
```python
import uvicorn
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.responses import PlainTextResponse
from starlette.routing import Route
from starlette_cramjam.middleware import CompressionMiddleware
def index(request):
return PlainTextResponse("Hello World")
app = Starlette(
routes=[Route("/", endpoint=index)],
middleware=[
Middleware(CompressionMiddleware),
],
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
```
#### Using options
```python
import uvicorn
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.responses import PlainTextResponse, Response
from starlette.routing import Route
from starlette_cramjam.compression import Compression
from starlette_cramjam.middleware import CompressionMiddleware
def index(request):
return PlainTextResponse("Hello World")
def img(request):
return Response(b"This is a fake body", status_code=200, media_type="image/jpeg")
def foo(request):
return PlainTextResponse("Do not compress me.")
app = Starlette(
routes=[
Route("/", endpoint=index),
Route("/image", endpoint=img),
Route("/foo", endpoint=foo),
],
middleware=[
Middleware(
CompressionMiddleware,
compression=[Compression.gzip], # Only support `gzip`
compression_level=6, # Compression level to use
minimum_size=0, # should compress everything
exclude_path={"^/foo$"}, # do not compress response for the `/foo` request
exclude_mediatype={"image/jpeg"}, # do not compress jpeg
),
],
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
```
## Performance
```python
import gzip
import sys
import brotli
import cramjam
import httpx
page = httpx.get("https://github.com/developmentseed/starlette-cramjam").content
len(page)
# 347686
%timeit brotli.compress(page, quality=4)
# 1.77 ms ± 19.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
sys.getsizeof(brotli.compress(page, quality=4))
# 48766
%timeit gzip.compress(page, compresslevel=6)
# 4.62 ms ± 28 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
sys.getsizeof(gzip.compress(page, compresslevel=6))
# 54888
# ------------
# With Cramjam
# ------------
%timeit cramjam.gzip.compress(page, level=6)
# 4.12 ms ± 57.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
cramjam.gzip.compress(page, level=6).len()
# 55221
%timeit cramjam.brotli.compress(page, level=4)
# 2.3 ms ± 48.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
cramjam.brotli.compress(page, level=4).len()
# 48742
```
Ref: https://github.com/fullonic/brotli-asgi?tab=readme-ov-file#performance
## Changes
See [CHANGES.md](https://github.com/developmentseed/starlette-cramjam/blob/master/CHANGES.md).
## Contribution & Development
See [CONTRIBUTING.md](https://github.com/developmentseed/starlette-cramjam/blob/master/CONTRIBUTING.md)
## License
See [LICENSE](https://github.com/developmentseed/starlette-cramjam/blob/master/LICENSE)
## Authors
Created by [Development Seed](<http://developmentseed.org>)
See [contributors](https://github.com/developmentseed/starlette-cramjam/graphs/contributors) for a listing of individual contributors.
Raw data
{
"_id": null,
"home_page": null,
"name": "starlette-cramjam",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "Cramjam, Compression, ASGI, Starlette",
"author": null,
"author_email": "Vincent Sarago <vincent@developmentseed.com>",
"download_url": "https://files.pythonhosted.org/packages/2b/05/4a478b9d43b73496b2f22b9af8239902065f1e1cd39d7f98cf269f776041/starlette_cramjam-0.4.0.tar.gz",
"platform": null,
"description": "# starlette-cramjam\n\n<p align=\"center\">\n <em>Cramjam integration for Starlette ASGI framework.</em>\n</p>\n<p align=\"center\">\n <a href=\"https://github.com/developmentseed/starlette-cramjam/actions?query=workflow%3ACI\" target=\"_blank\">\n <img src=\"https://github.com/developmentseed/starlette-cramjam/workflows/CI/badge.svg\" alt=\"Test\">\n </a>\n <a href=\"https://codecov.io/gh/developmentseed/starlette-cramjam\" target=\"_blank\">\n <img src=\"https://codecov.io/gh/developmentseed/starlette-cramjam/branch/master/graph/badge.svg\" alt=\"Coverage\">\n </a>\n <a href=\"https://pypi.org/project/starlette-cramjam\" target=\"_blank\">\n <img src=\"https://img.shields.io/pypi/v/starlette-cramjam?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n </a>\n <a href=\"https://pypistats.org/packages/starlette-cramjam\" target=\"_blank\">\n <img src=\"https://img.shields.io/pypi/dm/starlette-cramjam.svg\" alt=\"Downloads\">\n </a>\n <a href=\"https://github.com/developmentseed/starlette-cramjam/blob/master/LICENSE\" target=\"_blank\">\n <img src=\"https://img.shields.io/github/license/developmentseed/starlette-cramjam.svg\" alt=\"Downloads\">\n </a>\n</p>\n\n---\n\n**Source Code**: <a href=\"https://github.com/developmentseed/starlette-cramjam\" target=\"_blank\">https://github.com/developmentseed/starlette-cramjam</a>\n\n---\n\nThe `starlette-cramjam` middleware aims to provide a unique Compression middleware to support **Brotli**, **GZip** and **Deflate** compression algorithms with a minimal requirement.\n\nThe middleware will compress responses for any request that includes \"br\", \"gzip\" or \"deflate\" in the Accept-Encoding header.\n\nAs for the official `Starlette` middleware, the one provided by `starlette-cramjam` will handle both standard and streaming responses.\n\n`stralette-cramjam` is built on top of [pyrus-cramjam](https://github.com/milesgranger/pyrus-cramjam) an *Extremely thin Python bindings to de/compression algorithms in Rust*.\n\n## Installation\n\nYou can install `starlette-cramjam` from pypi\n\n```python\n$ pip install -U pip\n$ pip install starlette-cramjam\n```\n\nor install from source:\n\n```bash\n$ pip install -U pip\n$ pip install https://github.com/developmentseed/starlette-cramjam.git\n```\n\n## Usage\n\nThe following arguments are supported:\n\n- **compression** (List of Compression) - List of available compression algorithm. **This list also defines the order of preference**. Defaults to `[Compression.gzip, Compression.deflate, Compression.br]`,\n- **compression_level** (Integer) - Compression level to use, form `0` (None) to `11` (High). Defaults to cramjam internal defaults for each compression backend.\n- **minimum_size** (Integer) - Do not compress responses that are smaller than this minimum size in bytes. Defaults to `500`.\n- **exclude_path** (Set of string) - Do not compress responses in response to specific `path` requests. Entries have to be valid regex expressions. Defaults to `{}`.\n- **exclude_mediatype** (Set of string) - Do not compress responses of specific media type (e.g `image/png`). Defaults to `{}`.\n\n#### Minimal (defaults) example\n\n```python\nimport uvicorn\n\nfrom starlette.applications import Starlette\nfrom starlette.middleware import Middleware\nfrom starlette.responses import PlainTextResponse\nfrom starlette.routing import Route\n\nfrom starlette_cramjam.middleware import CompressionMiddleware\n\ndef index(request):\n return PlainTextResponse(\"Hello World\")\n\n\napp = Starlette(\n routes=[Route(\"/\", endpoint=index)],\n middleware=[\n Middleware(CompressionMiddleware),\n ],\n)\n\nif __name__ == \"__main__\":\n uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n#### Using options\n\n```python\nimport uvicorn\n\nfrom starlette.applications import Starlette\nfrom starlette.middleware import Middleware\nfrom starlette.responses import PlainTextResponse, Response\nfrom starlette.routing import Route\n\nfrom starlette_cramjam.compression import Compression\nfrom starlette_cramjam.middleware import CompressionMiddleware\n\ndef index(request):\n return PlainTextResponse(\"Hello World\")\n\ndef img(request):\n return Response(b\"This is a fake body\", status_code=200, media_type=\"image/jpeg\")\n\ndef foo(request):\n return PlainTextResponse(\"Do not compress me.\")\n\n\napp = Starlette(\n routes=[\n Route(\"/\", endpoint=index),\n Route(\"/image\", endpoint=img),\n Route(\"/foo\", endpoint=foo),\n ],\n middleware=[\n Middleware(\n CompressionMiddleware,\n compression=[Compression.gzip], # Only support `gzip`\n compression_level=6, # Compression level to use\n minimum_size=0, # should compress everything\n exclude_path={\"^/foo$\"}, # do not compress response for the `/foo` request\n exclude_mediatype={\"image/jpeg\"}, # do not compress jpeg\n ),\n ],\n)\n\nif __name__ == \"__main__\":\n uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n## Performance\n\n```python\nimport gzip\nimport sys\n\nimport brotli\nimport cramjam\nimport httpx\n\npage = httpx.get(\"https://github.com/developmentseed/starlette-cramjam\").content\n\nlen(page)\n# 347686\n\n%timeit brotli.compress(page, quality=4)\n# 1.77 ms \u00b1 19.7 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 1000 loops each)\n\nsys.getsizeof(brotli.compress(page, quality=4))\n# 48766\n\n%timeit gzip.compress(page, compresslevel=6)\n# 4.62 ms \u00b1 28 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n\nsys.getsizeof(gzip.compress(page, compresslevel=6))\n# 54888\n\n# ------------\n# With Cramjam\n# ------------\n%timeit cramjam.gzip.compress(page, level=6)\n# 4.12 ms \u00b1 57.3 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n\ncramjam.gzip.compress(page, level=6).len()\n# 55221\n\n%timeit cramjam.brotli.compress(page, level=4)\n# 2.3 ms \u00b1 48.5 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n\ncramjam.brotli.compress(page, level=4).len()\n# 48742\n```\n\nRef: https://github.com/fullonic/brotli-asgi?tab=readme-ov-file#performance\n\n## Changes\n\nSee [CHANGES.md](https://github.com/developmentseed/starlette-cramjam/blob/master/CHANGES.md).\n\n## Contribution & Development\n\nSee [CONTRIBUTING.md](https://github.com/developmentseed/starlette-cramjam/blob/master/CONTRIBUTING.md)\n\n## License\n\nSee [LICENSE](https://github.com/developmentseed/starlette-cramjam/blob/master/LICENSE)\n\n## Authors\n\nCreated by [Development Seed](<http://developmentseed.org>)\n\nSee [contributors](https://github.com/developmentseed/starlette-cramjam/graphs/contributors) for a listing of individual contributors.\n",
"bugtrack_url": null,
"license": null,
"summary": "Cramjam integration for Starlette ASGI framework.",
"version": "0.4.0",
"project_urls": {
"Source": "https://github.com/developmentseed/starlette-cramjam"
},
"split_keywords": [
"cramjam",
" compression",
" asgi",
" starlette"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "ca46de94ca00de3505c2d7b802ac5e581eef1fb0b3039966d7655aa7b53f6821",
"md5": "416ab0dc7720fbe17966e40cb87957ea",
"sha256": "c1943087641c8ed5a08fc166664875a1f44c6f1de4301ed21f23a261df821c1b"
},
"downloads": -1,
"filename": "starlette_cramjam-0.4.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "416ab0dc7720fbe17966e40cb87957ea",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 7201,
"upload_time": "2024-10-17T16:10:51",
"upload_time_iso_8601": "2024-10-17T16:10:51.203570Z",
"url": "https://files.pythonhosted.org/packages/ca/46/de94ca00de3505c2d7b802ac5e581eef1fb0b3039966d7655aa7b53f6821/starlette_cramjam-0.4.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "2b054a478b9d43b73496b2f22b9af8239902065f1e1cd39d7f98cf269f776041",
"md5": "d803984a285661fe1ea1827549dafd2c",
"sha256": "bd36e68109b13c29d1e7aa0ddb7eaf614bfd144be99d8dcb5ece95c96dbcec17"
},
"downloads": -1,
"filename": "starlette_cramjam-0.4.0.tar.gz",
"has_sig": false,
"md5_digest": "d803984a285661fe1ea1827549dafd2c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 7946,
"upload_time": "2024-10-17T16:10:53",
"upload_time_iso_8601": "2024-10-17T16:10:53.844128Z",
"url": "https://files.pythonhosted.org/packages/2b/05/4a478b9d43b73496b2f22b9af8239902065f1e1cd39d7f98cf269f776041/starlette_cramjam-0.4.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-17 16:10:53",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "developmentseed",
"github_project": "starlette-cramjam",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "starlette-cramjam"
}