Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-Flask-Compress for openSUSE:Factory checked in at 2021-07-23 23:41:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Flask-Compress (Old) and /work/SRC/openSUSE:Factory/.python-Flask-Compress.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Flask-Compress" Fri Jul 23 23:41:12 2021 rev:6 rq:907904 version:1.10.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Flask-Compress/python-Flask-Compress.changes 2021-06-01 10:41:45.081251235 +0200 +++ /work/SRC/openSUSE:Factory/.python-Flask-Compress.new.1899/python-Flask-Compress.changes 2021-07-23 23:41:30.773808249 +0200 @@ -1,0 +2,17 @@ +Thu Jul 22 01:46:11 UTC 2021 - Arun Persaud <a...@gmx.de> + +- specfile: + * update copyright year + * include setuptools_scm, importlib-metadata + * updated %files section + +- update to version 1.10.1: + * no changelog available at the moment + +- changes from version 1.10.0 : + * Automate the release process with GitHub Actions + * Use setuptools_scm to manage package versions + * The layout is now an actual package rather than a single module + * Clean up unused files + +------------------------------------------------------------------- Old: ---- Flask-Compress-1.8.0.tar.gz New: ---- Flask-Compress-1.10.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Flask-Compress.spec ++++++ --- /var/tmp/diff_new_pack.MBKOJd/_old 2021-07-23 23:41:31.189807717 +0200 +++ /var/tmp/diff_new_pack.MBKOJd/_new 2021-07-23 23:41:31.189807717 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-Flask-Compress # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # Copyright (c) 2016, Martin Hauke <mar...@gmx.de> # # All modifications and additions to the file contributed by third parties @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-Flask-Compress -Version: 1.8.0 +Version: 1.10.1 Release: 0 Summary: Compress responses in Flask apps with gzip License: MIT @@ -27,6 +27,8 @@ URL: https://github.com/colour-science/flask-compress Source: https://files.pythonhosted.org/packages/source/F/Flask-Compress/Flask-Compress-%{version}.tar.gz BuildRequires: %{python_module Brotli} +BuildRequires: %{python_module importlib-metadata} +BuildRequires: %{python_module setuptools_scm} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros @@ -62,8 +64,8 @@ %files %{python_files} %doc README.md %license LICENSE.txt -%{python_sitelib}/flask_compress.py* +%{python_sitelib}/flask_compress %{python_sitelib}/Flask_Compress-%{version}-py*.egg-info -%pycache_only %{python_sitelib}/__pycache__ +%pycache_only %{python_sitelib}/flask_compress/__pycache__ %changelog ++++++ Flask-Compress-1.8.0.tar.gz -> Flask-Compress-1.10.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/.github/workflows/ci.yaml new/Flask-Compress-1.10.1/.github/workflows/ci.yaml --- old/Flask-Compress-1.8.0/.github/workflows/ci.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/.github/workflows/ci.yaml 2021-06-16 10:22:32.000000000 +0200 @@ -0,0 +1,91 @@ +name: Unit tests + +on: + pull_request: + push: + branches: + - master + tags: + - "v*" + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, pypy2, pypy3] + + name: Python ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v2 + - name: Get history and tags for SCM versioning to work + run: | + git fetch --prune --unshallow + git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Test with tox + run: tox -e py + + dist: + runs-on: ubuntu-latest + needs: [test] + name: Build Python packages + steps: + - uses: actions/checkout@v2 + - name: Get history and tags for SCM versioning to work + run: | + git fetch --prune --unshallow + git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - uses: actions/setup-python@v2 + with: + python-version: "3.8" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade wheel setuptools build + - name: Build package + run: python -m build -s -w -o dist/ + - uses: actions/upload-artifact@v2 + with: + name: dist + path: dist + + dist_check: + runs-on: ubuntu-latest + needs: [dist] + name: Twine check + steps: + - uses: actions/setup-python@v2 + with: + python-version: "3.8" + - name: Install dependencies + run: pip install twine + - uses: actions/download-artifact@v2 + with: + name: dist + path: dist + - run: twine check dist/* + + dist_upload: + runs-on: ubuntu-latest + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') + needs: [dist_check] + name: PyPI upload + steps: + - uses: actions/download-artifact@v2 + with: + name: dist + path: dist + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/.gitignore new/Flask-Compress-1.10.1/.gitignore --- old/Flask-Compress-1.8.0/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/.gitignore 2021-06-16 10:22:32.000000000 +0200 @@ -0,0 +1,25 @@ +*~ +# vim +*.sw[klmnop] +# python +*.py[co~] +# Ignoring build dir +/build +/dist +/*.egg-info/ +# Virtual environments +venv* +.env* +# Coverage reports +/cover/ +/.coverage +/htmlcov +# Ignoring profiling reports +*.prof +*.lprof +# Tox and pytest +/.tox +/.cache +/.pytest_cache +# Generated by setuptools_scm +flask_compress/_version.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/CHANGELOG.md new/Flask-Compress-1.10.1/CHANGELOG.md --- old/Flask-Compress-1.8.0/CHANGELOG.md 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/CHANGELOG.md 2021-06-16 10:22:32.000000000 +0200 @@ -0,0 +1,38 @@ +# Changelog + +All notable changes to `flask-compress` will be documented in this file. + +## 1.10.0 (2021-06-15) + +- Automate the release process with GitHub Actions +- Use `setuptools_scm` to manage package versions +- The layout is now an actual package rather than a single module +- Clean up unused files + +## 1.9.0 (2021-02-12) + +- Add support for the `identity` value in *accept-encoding*, fixes [#19](https://github.com/colour-science/flask-compress/issues/19) + +## 1.8.0 (2020-11-03) + +- Support ETag header as defined in *RFC7232* [#17](https://github.com/colour-science/flask-compress/pull/17) +- Implement per-view compression [#14](https://github.com/colour-science/flask-compress/pull/14) + +## 1.7.0 (2020-10-09) + +- The following parameters to control Brotli compression are now available: [#10](https://github.com/colour-science/flask-compress/pull/10) + - `COMPRESS_BR_MODE` + - `COMPRESS_BR_LEVEL` + - `COMPRESS_BR_WINDOW` + - `COMPRESS_BR_BLOCK` +- Add deflate support, with `COMPRESS_DEFLATE_LEVEL` to control compression level (default is `-1`) [#8](https://github.com/colour-science/flask-compress/pull/8) +- The default quality level for Brotli is now `4`, which provides compression comparable to `gzip` at the default setting, while reducing the time required versus the Brotli default of `11` + +## 1.6.0 (2020-10-05) + +- Support for multiple compression algorithms and quality factors [#7](https://github.com/colour-science/flask-compress/pull/7) +- Modified default compression settings to use Brotli when available before `gzip` + +## 1.5.0 (2020-05-09) + +- Add Brotli support [#1](https://github.com/colour-science/flask-compress/pull/1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/Flask_Compress.egg-info/PKG-INFO new/Flask-Compress-1.10.1/Flask_Compress.egg-info/PKG-INFO --- old/Flask-Compress-1.8.0/Flask_Compress.egg-info/PKG-INFO 2020-11-03 14:25:41.000000000 +0100 +++ new/Flask-Compress-1.10.1/Flask_Compress.egg-info/PKG-INFO 2021-06-16 10:22:44.000000000 +0200 @@ -1,129 +1,11 @@ Metadata-Version: 2.1 Name: Flask-Compress -Version: 1.8.0 +Version: 1.10.1 Summary: Compress responses in your Flask app with gzip, deflate or brotli. Home-page: https://github.com/colour-science/flask-compress Author: Thomas Mansencal Author-email: thomas.mansen...@gmail.com License: MIT -Description: # Flask-Compress - - [](https://pypi.python.org/pypi/Flask-Compress) - [](https://travis-ci.org/libwilliam/flask-compress) - [](https://coveralls.io/github/libwilliam/flask-compress) - [](https://github.com/libwilliam/flask-compress/blob/master/LICENSE.txt) - - Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. - - The preferred solution is to have a server (like [Nginx](http://wiki.nginx.org/Main)) automatically compress the static files for you. If you don't have that option Flask-Compress will solve the problem for you. - - - ## How it works - - Flask-Compress both adds the various headers required for a compressed response and compresses the response data. - This makes serving compressed static files extremely easy. - - Internally, every time a request is made the extension will check if it matches one of the compressible MIME types - and whether the client and the server use some common compression algorithm, and will automatically attach the - appropriate headers. - - To determine the compression algorithm, the `Accept-Encoding` request header is inspected, respecting the - quality factor as described in [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding). - If no requested compression algorithm is supported by the server, we don't compress the response. If, on the other - hand, multiple suitable algorithms are found and are requested with the same quality factor, we choose the first one - defined in the `COMPRESS_ALGORITHM` option (see below). - - - ## Installation - - If you use pip then installation is simply: - - ```shell - $ pip install flask-compress - ``` - - or, if you want the latest github version: - - ```shell - $ pip install git+git://github.com/colour-science/flask-compress.git - ``` - - You can also install Flask-Compress via Easy Install: - - ```shell - $ easy_install flask-compress - ``` - - - ## Using Flask-Compress - - ### Globally - - Flask-Compress is incredibly simple to use. In order to start compressing your Flask application's assets, the first thing to do is let Flask-Compress know about your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) application object. - - ```python - from flask import Flask - from flask_compress import Compress - - app = Flask(__name__) - Compress(app) - ``` - - In many cases, however, one cannot expect a Flask instance to be ready at import time, and a common pattern is to return a Flask instance from within a function only after other configuration details have been taken care of. In these cases, Flask-Compress provides a simple function, `flask_compress.Compress.init_app`, which takes your application as an argument. - - ```python - from flask import Flask - from flask_compress import Compress - - compress = Compress() - - def start_app(): - app = Flask(__name__) - compress.init_app(app) - return app - ``` - - In terms of automatically compressing your assets, passing your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) object to the `flask_compress.Compress` object is all that needs to be done. - - ### Per-view compression - - Compression is possible per view using the `@compress.compressed()` decorator. Make sure to disable global compression first. - - ```python - from flask import Flask - from flask_compress import Compress - - app = Flask(__name__) - app.config["COMPRESS_REGISTER"] = False # disable default compression of all eligible requests - compress = Compress() - compress.init_app(app) - - # Compress this view specifically - @app.route("/test") - @compress.compressed() - def view(): - pass - ``` - - ## Options - - Within your Flask application's settings you can provide the following settings to control the behavior of Flask-Compress. None of the settings are required. - - | Option | Description | Default | - | ------ | ----------- | ------- | - | `COMPRESS_MIMETYPES` | Set the list of mimetypes to compress here. | `[`<br>`'text/html',`<br>`'text/css',`<br>`'text/xml',`<br>`'application/json',`<br>`'application/javascript'`<br>`]` | - | `COMPRESS_LEVEL` | Specifies the gzip compression level. | `6` | - | `COMPRESS_BR_LEVEL` | Specifies the Brotli compression level. Ranges from 0 to 11. | `4` | - | `COMPRESS_BR_MODE` | For Brotli, the compression mode. The options are 0, 1, or 2. These correspond to "generic", "text" (for UTF-8 input), and "font" (for WOFF 2.0). | `0` | - | `COMPRESS_BR_WINDOW` | For Brotli, this specifies the base-2 logarithm of the sliding window size. Ranges from 10 to 24. | `22` | - | `COMPRESS_BR_BLOCK` | For Brotli, this provides the base-2 logarithm of the maximum input block size. If zero is provided, value will be determined based on the quality. Ranges from 16 to 24. | `0` | - | `COMPRESS_DEFLATE_LEVEL` | Specifies the deflate compression level. | `-1` | - | `COMPRESS_MIN_SIZE` | Specifies the minimum file size threshold for compressing files. | `500` | - | `COMPRESS_CACHE_KEY` | Specifies the cache key method for lookup/storage of response data. | `None` | - | `COMPRESS_CACHE_BACKEND` | Specified the backend for storing the cached response data. | `None` | - | `COMPRESS_REGISTER` | Specifies if compression should be automatically registered. | `True` | - | `COMPRESS_ALGORITHM` | Supported compression algorithms. | `['br', 'gzip', 'deflate']` | - Platform: any Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers @@ -140,3 +22,123 @@ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Description-Content-Type: text/markdown +License-File: LICENSE.txt + +# Flask-Compress + +[](https://github.com/colour-science/flask-compress/actions/workflows/ci.yaml) +[](https://pypi.python.org/pypi/Flask-Compress) +[](https://pypi.python.org/pypi/Flask-Compress) + +Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. It originally started as a fork of [Flask-gzip](https://github.com/closeio/Flask-gzip). + +The preferred solution is to have a server (like [Nginx](http://wiki.nginx.org/Main)) automatically compress the static files for you. If you don't have that option Flask-Compress will solve the problem for you. + + +## How it works + +Flask-Compress both adds the various headers required for a compressed response and compresses the response data. +This makes serving compressed static files extremely easy. + +Internally, every time a request is made the extension will check if it matches one of the compressible MIME types +and whether the client and the server use some common compression algorithm, and will automatically attach the +appropriate headers. + +To determine the compression algorithm, the `Accept-Encoding` request header is inspected, respecting the +quality factor as described in [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding). +If no requested compression algorithm is supported by the server, we don't compress the response. If, on the other +hand, multiple suitable algorithms are found and are requested with the same quality factor, we choose the first one +defined in the `COMPRESS_ALGORITHM` option (see below). + + +## Installation + +If you use pip then installation is simply: + +```shell +$ pip install --user flask-compress +``` + +or, if you want the latest github version: + +```shell +$ pip install --user git+git://github.com/colour-science/flask-compress.git +``` + +You can also install Flask-Compress via Easy Install: + +```shell +$ easy_install flask-compress +``` + + +## Using Flask-Compress + +### Globally + +Flask-Compress is incredibly simple to use. In order to start compressing your Flask application's assets, the first thing to do is let Flask-Compress know about your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) application object. + +```python +from flask import Flask +from flask_compress import Compress + +app = Flask(__name__) +Compress(app) +``` + +In many cases, however, one cannot expect a Flask instance to be ready at import time, and a common pattern is to return a Flask instance from within a function only after other configuration details have been taken care of. In these cases, Flask-Compress provides a simple function, `flask_compress.Compress.init_app`, which takes your application as an argument. + +```python +from flask import Flask +from flask_compress import Compress + +compress = Compress() + +def start_app(): + app = Flask(__name__) + compress.init_app(app) + return app +``` + +In terms of automatically compressing your assets, passing your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) object to the `flask_compress.Compress` object is all that needs to be done. + +### Per-view compression + +Compression is possible per view using the `@compress.compressed()` decorator. Make sure to disable global compression first. + +```python +from flask import Flask +from flask_compress import Compress + +app = Flask(__name__) +app.config["COMPRESS_REGISTER"] = False # disable default compression of all eligible requests +compress = Compress() +compress.init_app(app) + +# Compress this view specifically +@app.route("/test") +@compress.compressed() +def view(): + pass +``` + +## Options + +Within your Flask application's settings you can provide the following settings to control the behavior of Flask-Compress. None of the settings are required. + +| Option | Description | Default | +| ------ | ----------- | ------- | +| `COMPRESS_MIMETYPES` | Set the list of mimetypes to compress here. | `[`<br>`'text/html',`<br>`'text/css',`<br>`'text/xml',`<br>`'application/json',`<br>`'application/javascript'`<br>`]` | +| `COMPRESS_LEVEL` | Specifies the gzip compression level. | `6` | +| `COMPRESS_BR_LEVEL` | Specifies the Brotli compression level. Ranges from 0 to 11. | `4` | +| `COMPRESS_BR_MODE` | For Brotli, the compression mode. The options are 0, 1, or 2. These correspond to "generic", "text" (for UTF-8 input), and "font" (for WOFF 2.0). | `0` | +| `COMPRESS_BR_WINDOW` | For Brotli, this specifies the base-2 logarithm of the sliding window size. Ranges from 10 to 24. | `22` | +| `COMPRESS_BR_BLOCK` | For Brotli, this provides the base-2 logarithm of the maximum input block size. If zero is provided, value will be determined based on the quality. Ranges from 16 to 24. | `0` | +| `COMPRESS_DEFLATE_LEVEL` | Specifies the deflate compression level. | `-1` | +| `COMPRESS_MIN_SIZE` | Specifies the minimum file size threshold for compressing files. | `500` | +| `COMPRESS_CACHE_KEY` | Specifies the cache key method for lookup/storage of response data. | `None` | +| `COMPRESS_CACHE_BACKEND` | Specified the backend for storing the cached response data. | `None` | +| `COMPRESS_REGISTER` | Specifies if compression should be automatically registered. | `True` | +| `COMPRESS_ALGORITHM` | Supported compression algorithms. | `['br', 'gzip', 'deflate']` | + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/Flask_Compress.egg-info/SOURCES.txt new/Flask-Compress-1.10.1/Flask_Compress.egg-info/SOURCES.txt --- old/Flask-Compress-1.8.0/Flask_Compress.egg-info/SOURCES.txt 2020-11-03 14:25:41.000000000 +0100 +++ new/Flask-Compress-1.10.1/Flask_Compress.egg-info/SOURCES.txt 2021-06-16 10:22:44.000000000 +0200 @@ -1,15 +1,20 @@ +.gitignore +CHANGELOG.md LICENSE.txt -MANIFEST.in README.md -flask_compress.py +pyproject.toml setup.py +tox.ini +.github/workflows/ci.yaml Flask_Compress.egg-info/PKG-INFO Flask_Compress.egg-info/SOURCES.txt Flask_Compress.egg-info/dependency_links.txt Flask_Compress.egg-info/not-zip-safe Flask_Compress.egg-info/requires.txt Flask_Compress.egg-info/top_level.txt -tests/__init__.py +flask_compress/__init__.py +flask_compress/_version.py +flask_compress/flask_compress.py tests/test_flask_compress.py tests/static/1.png tests/templates/large.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/MANIFEST.in new/Flask-Compress-1.10.1/MANIFEST.in --- old/Flask-Compress-1.8.0/MANIFEST.in 2020-04-21 09:38:27.000000000 +0200 +++ new/Flask-Compress-1.10.1/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +0,0 @@ -include LICENSE.txt -include README.md -recursive-include tests * -recursive-exclude tests *.pyc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/PKG-INFO new/Flask-Compress-1.10.1/PKG-INFO --- old/Flask-Compress-1.8.0/PKG-INFO 2020-11-03 14:25:41.266460700 +0100 +++ new/Flask-Compress-1.10.1/PKG-INFO 2021-06-16 10:22:44.950378200 +0200 @@ -1,129 +1,11 @@ Metadata-Version: 2.1 Name: Flask-Compress -Version: 1.8.0 +Version: 1.10.1 Summary: Compress responses in your Flask app with gzip, deflate or brotli. Home-page: https://github.com/colour-science/flask-compress Author: Thomas Mansencal Author-email: thomas.mansen...@gmail.com License: MIT -Description: # Flask-Compress - - [](https://pypi.python.org/pypi/Flask-Compress) - [](https://travis-ci.org/libwilliam/flask-compress) - [](https://coveralls.io/github/libwilliam/flask-compress) - [](https://github.com/libwilliam/flask-compress/blob/master/LICENSE.txt) - - Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. - - The preferred solution is to have a server (like [Nginx](http://wiki.nginx.org/Main)) automatically compress the static files for you. If you don't have that option Flask-Compress will solve the problem for you. - - - ## How it works - - Flask-Compress both adds the various headers required for a compressed response and compresses the response data. - This makes serving compressed static files extremely easy. - - Internally, every time a request is made the extension will check if it matches one of the compressible MIME types - and whether the client and the server use some common compression algorithm, and will automatically attach the - appropriate headers. - - To determine the compression algorithm, the `Accept-Encoding` request header is inspected, respecting the - quality factor as described in [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding). - If no requested compression algorithm is supported by the server, we don't compress the response. If, on the other - hand, multiple suitable algorithms are found and are requested with the same quality factor, we choose the first one - defined in the `COMPRESS_ALGORITHM` option (see below). - - - ## Installation - - If you use pip then installation is simply: - - ```shell - $ pip install flask-compress - ``` - - or, if you want the latest github version: - - ```shell - $ pip install git+git://github.com/colour-science/flask-compress.git - ``` - - You can also install Flask-Compress via Easy Install: - - ```shell - $ easy_install flask-compress - ``` - - - ## Using Flask-Compress - - ### Globally - - Flask-Compress is incredibly simple to use. In order to start compressing your Flask application's assets, the first thing to do is let Flask-Compress know about your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) application object. - - ```python - from flask import Flask - from flask_compress import Compress - - app = Flask(__name__) - Compress(app) - ``` - - In many cases, however, one cannot expect a Flask instance to be ready at import time, and a common pattern is to return a Flask instance from within a function only after other configuration details have been taken care of. In these cases, Flask-Compress provides a simple function, `flask_compress.Compress.init_app`, which takes your application as an argument. - - ```python - from flask import Flask - from flask_compress import Compress - - compress = Compress() - - def start_app(): - app = Flask(__name__) - compress.init_app(app) - return app - ``` - - In terms of automatically compressing your assets, passing your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) object to the `flask_compress.Compress` object is all that needs to be done. - - ### Per-view compression - - Compression is possible per view using the `@compress.compressed()` decorator. Make sure to disable global compression first. - - ```python - from flask import Flask - from flask_compress import Compress - - app = Flask(__name__) - app.config["COMPRESS_REGISTER"] = False # disable default compression of all eligible requests - compress = Compress() - compress.init_app(app) - - # Compress this view specifically - @app.route("/test") - @compress.compressed() - def view(): - pass - ``` - - ## Options - - Within your Flask application's settings you can provide the following settings to control the behavior of Flask-Compress. None of the settings are required. - - | Option | Description | Default | - | ------ | ----------- | ------- | - | `COMPRESS_MIMETYPES` | Set the list of mimetypes to compress here. | `[`<br>`'text/html',`<br>`'text/css',`<br>`'text/xml',`<br>`'application/json',`<br>`'application/javascript'`<br>`]` | - | `COMPRESS_LEVEL` | Specifies the gzip compression level. | `6` | - | `COMPRESS_BR_LEVEL` | Specifies the Brotli compression level. Ranges from 0 to 11. | `4` | - | `COMPRESS_BR_MODE` | For Brotli, the compression mode. The options are 0, 1, or 2. These correspond to "generic", "text" (for UTF-8 input), and "font" (for WOFF 2.0). | `0` | - | `COMPRESS_BR_WINDOW` | For Brotli, this specifies the base-2 logarithm of the sliding window size. Ranges from 10 to 24. | `22` | - | `COMPRESS_BR_BLOCK` | For Brotli, this provides the base-2 logarithm of the maximum input block size. If zero is provided, value will be determined based on the quality. Ranges from 16 to 24. | `0` | - | `COMPRESS_DEFLATE_LEVEL` | Specifies the deflate compression level. | `-1` | - | `COMPRESS_MIN_SIZE` | Specifies the minimum file size threshold for compressing files. | `500` | - | `COMPRESS_CACHE_KEY` | Specifies the cache key method for lookup/storage of response data. | `None` | - | `COMPRESS_CACHE_BACKEND` | Specified the backend for storing the cached response data. | `None` | - | `COMPRESS_REGISTER` | Specifies if compression should be automatically registered. | `True` | - | `COMPRESS_ALGORITHM` | Supported compression algorithms. | `['br', 'gzip', 'deflate']` | - Platform: any Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers @@ -140,3 +22,123 @@ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Description-Content-Type: text/markdown +License-File: LICENSE.txt + +# Flask-Compress + +[](https://github.com/colour-science/flask-compress/actions/workflows/ci.yaml) +[](https://pypi.python.org/pypi/Flask-Compress) +[](https://pypi.python.org/pypi/Flask-Compress) + +Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. It originally started as a fork of [Flask-gzip](https://github.com/closeio/Flask-gzip). + +The preferred solution is to have a server (like [Nginx](http://wiki.nginx.org/Main)) automatically compress the static files for you. If you don't have that option Flask-Compress will solve the problem for you. + + +## How it works + +Flask-Compress both adds the various headers required for a compressed response and compresses the response data. +This makes serving compressed static files extremely easy. + +Internally, every time a request is made the extension will check if it matches one of the compressible MIME types +and whether the client and the server use some common compression algorithm, and will automatically attach the +appropriate headers. + +To determine the compression algorithm, the `Accept-Encoding` request header is inspected, respecting the +quality factor as described in [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding). +If no requested compression algorithm is supported by the server, we don't compress the response. If, on the other +hand, multiple suitable algorithms are found and are requested with the same quality factor, we choose the first one +defined in the `COMPRESS_ALGORITHM` option (see below). + + +## Installation + +If you use pip then installation is simply: + +```shell +$ pip install --user flask-compress +``` + +or, if you want the latest github version: + +```shell +$ pip install --user git+git://github.com/colour-science/flask-compress.git +``` + +You can also install Flask-Compress via Easy Install: + +```shell +$ easy_install flask-compress +``` + + +## Using Flask-Compress + +### Globally + +Flask-Compress is incredibly simple to use. In order to start compressing your Flask application's assets, the first thing to do is let Flask-Compress know about your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) application object. + +```python +from flask import Flask +from flask_compress import Compress + +app = Flask(__name__) +Compress(app) +``` + +In many cases, however, one cannot expect a Flask instance to be ready at import time, and a common pattern is to return a Flask instance from within a function only after other configuration details have been taken care of. In these cases, Flask-Compress provides a simple function, `flask_compress.Compress.init_app`, which takes your application as an argument. + +```python +from flask import Flask +from flask_compress import Compress + +compress = Compress() + +def start_app(): + app = Flask(__name__) + compress.init_app(app) + return app +``` + +In terms of automatically compressing your assets, passing your [`flask.Flask`](http://flask.pocoo.org/docs/latest/api/#flask.Flask) object to the `flask_compress.Compress` object is all that needs to be done. + +### Per-view compression + +Compression is possible per view using the `@compress.compressed()` decorator. Make sure to disable global compression first. + +```python +from flask import Flask +from flask_compress import Compress + +app = Flask(__name__) +app.config["COMPRESS_REGISTER"] = False # disable default compression of all eligible requests +compress = Compress() +compress.init_app(app) + +# Compress this view specifically +@app.route("/test") +@compress.compressed() +def view(): + pass +``` + +## Options + +Within your Flask application's settings you can provide the following settings to control the behavior of Flask-Compress. None of the settings are required. + +| Option | Description | Default | +| ------ | ----------- | ------- | +| `COMPRESS_MIMETYPES` | Set the list of mimetypes to compress here. | `[`<br>`'text/html',`<br>`'text/css',`<br>`'text/xml',`<br>`'application/json',`<br>`'application/javascript'`<br>`]` | +| `COMPRESS_LEVEL` | Specifies the gzip compression level. | `6` | +| `COMPRESS_BR_LEVEL` | Specifies the Brotli compression level. Ranges from 0 to 11. | `4` | +| `COMPRESS_BR_MODE` | For Brotli, the compression mode. The options are 0, 1, or 2. These correspond to "generic", "text" (for UTF-8 input), and "font" (for WOFF 2.0). | `0` | +| `COMPRESS_BR_WINDOW` | For Brotli, this specifies the base-2 logarithm of the sliding window size. Ranges from 10 to 24. | `22` | +| `COMPRESS_BR_BLOCK` | For Brotli, this provides the base-2 logarithm of the maximum input block size. If zero is provided, value will be determined based on the quality. Ranges from 16 to 24. | `0` | +| `COMPRESS_DEFLATE_LEVEL` | Specifies the deflate compression level. | `-1` | +| `COMPRESS_MIN_SIZE` | Specifies the minimum file size threshold for compressing files. | `500` | +| `COMPRESS_CACHE_KEY` | Specifies the cache key method for lookup/storage of response data. | `None` | +| `COMPRESS_CACHE_BACKEND` | Specified the backend for storing the cached response data. | `None` | +| `COMPRESS_REGISTER` | Specifies if compression should be automatically registered. | `True` | +| `COMPRESS_ALGORITHM` | Supported compression algorithms. | `['br', 'gzip', 'deflate']` | + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/README.md new/Flask-Compress-1.10.1/README.md --- old/Flask-Compress-1.8.0/README.md 2020-11-02 09:38:17.000000000 +0100 +++ new/Flask-Compress-1.10.1/README.md 2021-06-16 10:22:32.000000000 +0200 @@ -1,11 +1,10 @@ # Flask-Compress +[](https://github.com/colour-science/flask-compress/actions/workflows/ci.yaml) [](https://pypi.python.org/pypi/Flask-Compress) -[](https://travis-ci.org/libwilliam/flask-compress) -[](https://coveralls.io/github/libwilliam/flask-compress) -[](https://github.com/libwilliam/flask-compress/blob/master/LICENSE.txt) +[](https://pypi.python.org/pypi/Flask-Compress) -Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. +Flask-Compress allows you to easily compress your [Flask](http://flask.pocoo.org/) application's responses with gzip, deflate or brotli. It originally started as a fork of [Flask-gzip](https://github.com/closeio/Flask-gzip). The preferred solution is to have a server (like [Nginx](http://wiki.nginx.org/Main)) automatically compress the static files for you. If you don't have that option Flask-Compress will solve the problem for you. @@ -31,13 +30,13 @@ If you use pip then installation is simply: ```shell -$ pip install flask-compress +$ pip install --user flask-compress ``` or, if you want the latest github version: ```shell -$ pip install git+git://github.com/colour-science/flask-compress.git +$ pip install --user git+git://github.com/colour-science/flask-compress.git ``` You can also install Flask-Compress via Easy Install: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/flask_compress/__init__.py new/Flask-Compress-1.10.1/flask_compress/__init__.py --- old/Flask-Compress-1.8.0/flask_compress/__init__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/flask_compress/__init__.py 2021-06-16 10:22:32.000000000 +0200 @@ -0,0 +1,9 @@ +from .flask_compress import Compress + +# _version.py is generated by setuptools_scm when building the package, it is not versioned. +# If missing, this means that the imported code was most likely the git repository, that was +# installed without the "editable" mode. +try: + from ._version import __version__ +except ImportError: + __version__ = "0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/flask_compress/_version.py new/Flask-Compress-1.10.1/flask_compress/_version.py --- old/Flask-Compress-1.8.0/flask_compress/_version.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/flask_compress/_version.py 2021-06-16 10:22:44.000000000 +0200 @@ -0,0 +1 @@ +__version__ = "1.10.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/flask_compress/flask_compress.py new/Flask-Compress-1.10.1/flask_compress/flask_compress.py --- old/Flask-Compress-1.8.0/flask_compress/flask_compress.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/flask_compress/flask_compress.py 2021-06-16 10:22:32.000000000 +0200 @@ -0,0 +1,237 @@ + +# Authors: William Fagan +# Copyright (c) 2013-2017 William Fagan +# License: The MIT License (MIT) + +import sys +import functools +from gzip import GzipFile +import zlib +from io import BytesIO + +from collections import defaultdict + +import brotli +from flask import request, after_this_request, current_app + + +if sys.version_info[:2] == (2, 6): + class GzipFile(GzipFile): + """ Backport of context manager support for python 2.6""" + def __enter__(self): + if self.fileobj is None: + raise ValueError("I/O operation on closed GzipFile object") + return self + + def __exit__(self, *args): + self.close() + + +class DictCache(object): + + def __init__(self): + self.data = {} + + def get(self, key): + return self.data.get(key) + + def set(self, key, value): + self.data[key] = value + + +class Compress(object): + """ + The Compress object allows your application to use Flask-Compress. + + When initialising a Compress object you may optionally provide your + :class:`flask.Flask` application object if it is ready. Otherwise, + you may provide it later by using the :meth:`init_app` method. + + :param app: optional :class:`flask.Flask` application object + :type app: :class:`flask.Flask` or None + """ + def __init__(self, app=None): + """ + An alternative way to pass your :class:`flask.Flask` application + object to Flask-Compress. :meth:`init_app` also takes care of some + default `settings`_. + + :param app: the :class:`flask.Flask` application object. + """ + self.app = app + if app is not None: + self.init_app(app) + + def init_app(self, app): + defaults = [ + ('COMPRESS_MIMETYPES', ['text/html', 'text/css', 'text/xml', + 'application/json', + 'application/javascript']), + ('COMPRESS_LEVEL', 6), + ('COMPRESS_BR_LEVEL', 4), + ('COMPRESS_BR_MODE', 0), + ('COMPRESS_BR_WINDOW', 22), + ('COMPRESS_BR_BLOCK', 0), + ('COMPRESS_DEFLATE_LEVEL', -1), + ('COMPRESS_MIN_SIZE', 500), + ('COMPRESS_CACHE_KEY', None), + ('COMPRESS_CACHE_BACKEND', None), + ('COMPRESS_REGISTER', True), + ('COMPRESS_ALGORITHM', ['br', 'gzip', 'deflate']), + ] + + for k, v in defaults: + app.config.setdefault(k, v) + + backend = app.config['COMPRESS_CACHE_BACKEND'] + self.cache = backend() if backend else None + self.cache_key = app.config['COMPRESS_CACHE_KEY'] + + algo = app.config['COMPRESS_ALGORITHM'] + if isinstance(algo, str): + self.enabled_algorithms = [i.strip() for i in algo.split(',')] + else: + self.enabled_algorithms = list(algo) + + if (app.config['COMPRESS_REGISTER'] and + app.config['COMPRESS_MIMETYPES']): + app.after_request(self.after_request) + + def _choose_compress_algorithm(self, accept_encoding_header): + """ + Determine which compression algorithm we're going to use based on the + client request. The `Accept-Encoding` header may list one or more desired + algorithms, together with a "quality factor" for each one (higher quality + means the client prefers that algorithm more). + + :param accept_encoding_header: Content of the `Accept-Encoding` header + :return: name of a compression algorithm (`gzip`, `deflate`, `br`) or `None` if + the client and server don't agree on any. + """ + # A flag denoting that client requested using any (`*`) algorithm, + # in case a specific one is not supported by the server + fallback_to_any = False + + # Map quality factors to requested algorithm names. + algos_by_quality = defaultdict(set) + + # Set of supported algorithms + server_algos_set = set(self.enabled_algorithms) + + for part in accept_encoding_header.lower().split(','): + part = part.strip() + if ';q=' in part: + # If the client associated a quality factor with an algorithm, + # try to parse it. We could do the matching using a regex, but + # the format is so simple that it would be overkill. + algo = part.split(';')[0].strip() + try: + quality = float(part.split('=')[1].strip()) + except ValueError: + quality = 1.0 + else: + # Otherwise, use the default quality + algo = part + quality = 1.0 + + if algo == '*': + if quality > 0: + fallback_to_any = True + elif algo == 'identity': # identity means 'no compression asked' + algos_by_quality[quality].add(None) + elif algo in server_algos_set: + algos_by_quality[quality].add(algo) + + # Choose the algorithm with the highest quality factor that the server supports. + # + # If there are multiple equally good options, choose the first supported algorithm + # from server configuration. + # + # If the server doesn't support any algorithm that the client requested but + # there's a special wildcard algorithm request (`*`), choose the first supported + # algorithm. + for _, viable_algos in sorted(algos_by_quality.items(), reverse=True): + if len(viable_algos) == 1: + return viable_algos.pop() + elif len(viable_algos) > 1: + for server_algo in self.enabled_algorithms: + if server_algo in viable_algos: + return server_algo + + if fallback_to_any: + return self.enabled_algorithms[0] + return None + + def after_request(self, response): + app = self.app or current_app + + accept_encoding = request.headers.get('Accept-Encoding', '') + chosen_algorithm = self._choose_compress_algorithm(accept_encoding) + + if (chosen_algorithm is None or + response.mimetype not in app.config["COMPRESS_MIMETYPES"] or + response.status_code < 200 or + response.status_code >= 300 or + "Content-Encoding" in response.headers or + (response.content_length is not None and + response.content_length < app.config["COMPRESS_MIN_SIZE"])): + return response + + response.direct_passthrough = False + + if self.cache is not None: + key = self.cache_key(request) + compressed_content = self.cache.get(key) + if compressed_content is None: + compressed_content = self.compress(app, response, chosen_algorithm) + self.cache.set(key, compressed_content) + else: + compressed_content = self.compress(app, response, chosen_algorithm) + + response.set_data(compressed_content) + + response.headers['Content-Encoding'] = chosen_algorithm + response.headers['Content-Length'] = response.content_length + + # "123456789" => "123456789:gzip" - A strong ETag validator + # W/"123456789" => W/"123456789:gzip" - A weak ETag validator + etag = response.headers.get('ETag') + if etag: + response.headers['ETag'] = '{0}:{1}"'.format(etag[:-1], chosen_algorithm) + + vary = response.headers.get('Vary') + if not vary: + response.headers['Vary'] = 'Accept-Encoding' + elif 'accept-encoding' not in vary.lower(): + response.headers['Vary'] = '{}, Accept-Encoding'.format(vary) + + return response + + def compressed(self): + def decorator(f): + @functools.wraps(f) + def decorated_function(*args, **kwargs): + @after_this_request + def compressor(response): + return self.after_request(response) + return f(*args, **kwargs) + return decorated_function + return decorator + + def compress(self, app, response, algorithm): + if algorithm == 'gzip': + gzip_buffer = BytesIO() + with GzipFile(mode='wb', + compresslevel=app.config['COMPRESS_LEVEL'], + fileobj=gzip_buffer) as gzip_file: + gzip_file.write(response.get_data()) + return gzip_buffer.getvalue() + elif algorithm == 'deflate': + return zlib.compress(response.get_data(), + app.config['COMPRESS_DEFLATE_LEVEL']) + elif algorithm == 'br': + return brotli.compress(response.get_data(), + mode=app.config['COMPRESS_BR_MODE'], + quality=app.config['COMPRESS_BR_LEVEL'], + lgwin=app.config['COMPRESS_BR_WINDOW'], + lgblock=app.config['COMPRESS_BR_BLOCK']) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/flask_compress.py new/Flask-Compress-1.10.1/flask_compress.py --- old/Flask-Compress-1.8.0/flask_compress.py 2020-11-03 09:34:40.000000000 +0100 +++ new/Flask-Compress-1.10.1/flask_compress.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,233 +0,0 @@ - -# Authors: William Fagan -# Copyright (c) 2013-2017 William Fagan -# License: The MIT License (MIT) - -import sys -import functools -from gzip import GzipFile -import zlib -from io import BytesIO - -from collections import defaultdict - -import brotli -from flask import request, after_this_request, current_app - - -if sys.version_info[:2] == (2, 6): - class GzipFile(GzipFile): - """ Backport of context manager support for python 2.6""" - def __enter__(self): - if self.fileobj is None: - raise ValueError("I/O operation on closed GzipFile object") - return self - - def __exit__(self, *args): - self.close() - - -class DictCache(object): - - def __init__(self): - self.data = {} - - def get(self, key): - return self.data.get(key) - - def set(self, key, value): - self.data[key] = value - - -class Compress(object): - """ - The Compress object allows your application to use Flask-Compress. - - When initialising a Compress object you may optionally provide your - :class:`flask.Flask` application object if it is ready. Otherwise, - you may provide it later by using the :meth:`init_app` method. - - :param app: optional :class:`flask.Flask` application object - :type app: :class:`flask.Flask` or None - """ - def __init__(self, app=None): - """ - An alternative way to pass your :class:`flask.Flask` application - object to Flask-Compress. :meth:`init_app` also takes care of some - default `settings`_. - - :param app: the :class:`flask.Flask` application object. - """ - self.app = app - if app is not None: - self.init_app(app) - - def init_app(self, app): - defaults = [ - ('COMPRESS_MIMETYPES', ['text/html', 'text/css', 'text/xml', - 'application/json', - 'application/javascript']), - ('COMPRESS_LEVEL', 6), - ('COMPRESS_BR_LEVEL', 4), - ('COMPRESS_BR_MODE', 0), - ('COMPRESS_BR_WINDOW', 22), - ('COMPRESS_BR_BLOCK', 0), - ('COMPRESS_DEFLATE_LEVEL', -1), - ('COMPRESS_MIN_SIZE', 500), - ('COMPRESS_CACHE_KEY', None), - ('COMPRESS_CACHE_BACKEND', None), - ('COMPRESS_REGISTER', True), - ('COMPRESS_ALGORITHM', ['br', 'gzip', 'deflate']), - ] - - for k, v in defaults: - app.config.setdefault(k, v) - - backend = app.config['COMPRESS_CACHE_BACKEND'] - self.cache = backend() if backend else None - self.cache_key = app.config['COMPRESS_CACHE_KEY'] - - algo = app.config['COMPRESS_ALGORITHM'] - if isinstance(algo, str): - self.enabled_algorithms = [i.strip() for i in algo.split(',')] - else: - self.enabled_algorithms = algo - - if (app.config['COMPRESS_REGISTER'] and - app.config['COMPRESS_MIMETYPES']): - app.after_request(self.after_request) - - def _choose_compress_algorithm(self, accept_encoding_header): - """ - Determine which compression algorithm we're going to use based on the - client request. The `Accept-Encoding` header may list one or more desired - algorithms, together with a "quality factor" for each one (higher quality - means the client prefers that algorithm more). - - :param accept_encoding_header: Content of the `Accept-Encoding` header - :return: name of a compression algorithm (`gzip`, `deflate`, `br`) or `None` if - the client and server don't agree on any. - """ - # Map quality factors to requested algorithm names. - algos_by_quality = defaultdict(set) - - # A flag denoting that client requested using any (`*`) algorithm, - # in case a specific one is not supported by the server - fallback_to_any = False - - for part in accept_encoding_header.lower().split(','): - part = part.strip() - quality = 1.0 - - if ';q=' in part: - # If the client associated a quality factor with an algorithm, - # try to parse it. We could do the matching using a regex, but - # the format is so simple that it would be overkill. - algo = part.split(';')[0].strip() - try: - quality = float(part.split('=')[1].strip()) - except ValueError: - pass - else: - # Otherwise, use the default quality - algo = part - - algos_by_quality[quality].add(algo) - fallback_to_any = fallback_to_any or (algo == '*') - - # Choose the algorithm with the highest quality factor that the server supports. - # - # If there are multiple equally good options, choose the first supported algorithm - # from server configuration. - # - # If the server doesn't support any algorithm that the client requested but - # there's a special wildcard algorithm request (`*`), choose the first supported - # algorithm. - server_algo_set = set(self.enabled_algorithms) - for _, requested_algo_set in sorted(algos_by_quality.items(), reverse=True): - viable_algos = server_algo_set & requested_algo_set - if len(viable_algos) == 1: - return viable_algos.pop() - elif len(viable_algos) > 1: - for server_algo in self.enabled_algorithms: - if server_algo in viable_algos: - return server_algo - else: - if fallback_to_any: - return self.enabled_algorithms[0] - - return None - - def after_request(self, response): - app = self.app or current_app - - accept_encoding = request.headers.get('Accept-Encoding', '') - chosen_algorithm = self._choose_compress_algorithm(accept_encoding) - - if (chosen_algorithm is None or - response.mimetype not in app.config["COMPRESS_MIMETYPES"] or - response.status_code < 200 or - response.status_code >= 300 or - "Content-Encoding" in response.headers or - (response.content_length is not None and - response.content_length < app.config["COMPRESS_MIN_SIZE"])): - return response - - response.direct_passthrough = False - - if self.cache is not None: - key = self.cache_key(request) - compressed_content = self.cache.get(key) - if compressed_content is None: - compressed_content = self.compress(app, response, chosen_algorithm) - self.cache.set(key, compressed_content) - else: - compressed_content = self.compress(app, response, chosen_algorithm) - - response.set_data(compressed_content) - - response.headers['Content-Encoding'] = chosen_algorithm - response.headers['Content-Length'] = response.content_length - - # "123456789" => "123456789:gzip" - A strong ETag validator - # W/"123456789" => W/"123456789:gzip" - A weak ETag validator - etag = response.headers.get('ETag') - if etag: - response.headers['ETag'] = '{0}:{1}"'.format(etag[:-1], chosen_algorithm) - - vary = response.headers.get('Vary') - if not vary: - response.headers['Vary'] = 'Accept-Encoding' - elif 'accept-encoding' not in vary.lower(): - response.headers['Vary'] = '{}, Accept-Encoding'.format(vary) - - return response - - def compressed(self): - def decorator(f): - @functools.wraps(f) - def decorated_function(*args, **kwargs): - @after_this_request - def compressor(response): - return self.after_request(response) - return f(*args, **kwargs) - return decorated_function - return decorator - - def compress(self, app, response, algorithm): - if algorithm == 'gzip': - gzip_buffer = BytesIO() - with GzipFile(mode='wb', - compresslevel=app.config['COMPRESS_LEVEL'], - fileobj=gzip_buffer) as gzip_file: - gzip_file.write(response.get_data()) - return gzip_buffer.getvalue() - elif algorithm == 'deflate': - return zlib.compress(response.get_data(), - app.config['COMPRESS_DEFLATE_LEVEL']) - elif algorithm == 'br': - return brotli.compress(response.get_data(), - mode=app.config['COMPRESS_BR_MODE'], - quality=app.config['COMPRESS_BR_LEVEL'], - lgwin=app.config['COMPRESS_BR_WINDOW'], - lgblock=app.config['COMPRESS_BR_BLOCK']) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/pyproject.toml new/Flask-Compress-1.10.1/pyproject.toml --- old/Flask-Compress-1.8.0/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/pyproject.toml 2021-06-16 10:22:32.000000000 +0200 @@ -0,0 +1,7 @@ +[build-system] +requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +write_to = "flask_compress/_version.py" +write_to_template = "__version__ = \"{version}\"\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/setup.py new/Flask-Compress-1.10.1/setup.py --- old/Flask-Compress-1.8.0/setup.py 2020-11-03 14:20:11.000000000 +0100 +++ new/Flask-Compress-1.10.1/setup.py 2021-06-16 10:22:32.000000000 +0200 @@ -1,11 +1,11 @@ -import setuptools +from setuptools import setup, find_packages with open('README.md') as fl: LONG_DESCRIPTION = fl.read() -setuptools.setup( +setup( name='Flask-Compress', - version='1.8.0', + use_scm_version=True, url='https://github.com/colour-science/flask-compress', license='MIT', author='Thomas Mansencal', @@ -13,7 +13,7 @@ description='Compress responses in your Flask app with gzip, deflate or brotli.', long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', - py_modules=['flask_compress'], + packages=find_packages(exclude=['tests']), zip_safe=False, include_package_data=True, platforms='any', @@ -21,7 +21,6 @@ 'flask', 'brotli' ], - test_suite='tests', classifiers=[ 'Environment :: Web Environment', 'Intended Audience :: Developers', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/tests/test_flask_compress.py new/Flask-Compress-1.10.1/tests/test_flask_compress.py --- old/Flask-Compress-1.8.0/tests/test_flask_compress.py 2020-11-02 09:38:17.000000000 +0100 +++ new/Flask-Compress-1.10.1/tests/test_flask_compress.py 2021-06-16 10:22:32.000000000 +0200 @@ -273,6 +273,27 @@ c = Compress(self.app) self.assertEqual(c._choose_compress_algorithm(accept_encoding), 'br') + def test_wildcard_quality(self): + """ Tests that a wildcard with q=0 is discarded """ + accept_encoding = '*;q=0' + self.app.config['COMPRESS_ALGORITHM'] = ['gzip', 'br', 'deflate'] + c = Compress(self.app) + self.assertEqual(c._choose_compress_algorithm(accept_encoding), None) + + def test_identity(self): + """ Tests that identity is understood """ + accept_encoding = 'identity;q=1, br;q=0.5, *;q=0' + self.app.config['COMPRESS_ALGORITHM'] = ['gzip', 'br', 'deflate'] + c = Compress(self.app) + self.assertEqual(c._choose_compress_algorithm(accept_encoding), None) + + def test_chrome_ranged_requests(self): + """ Tests that Chrome ranged requests behave as expected """ + accept_encoding = 'identity;q=1, *;q=0' + self.app.config['COMPRESS_ALGORITHM'] = ['gzip', 'br', 'deflate'] + c = Compress(self.app) + self.assertEqual(c._choose_compress_algorithm(accept_encoding), None) + def test_content_encoding_is_correct(self): """ Test that the `Content-Encoding` header matches the compression algorithm """ self.app.config['COMPRESS_ALGORITHM'] = ['br', 'gzip', 'deflate'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-Compress-1.8.0/tox.ini new/Flask-Compress-1.10.1/tox.ini --- old/Flask-Compress-1.8.0/tox.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/Flask-Compress-1.10.1/tox.ini 2021-06-16 10:22:32.000000000 +0200 @@ -0,0 +1,9 @@ +[tox] +isolated_build = True +skip_missing_interpreters = true +envlist = py27,py35,py36,py37,py38,py39,pypy2,pypy3 + +[testenv] +deps = + pytest +commands = py.test {posargs}