Repository: colour-science/flask-compress

Issue:
Enable compression per view
Hello,

It would be fantastic if this design only allows compression to be enabled for selected views. This could be done with a decorator.
https://github.com/apache/airflow/blob/master/airflow/www/decorators.py#L67
This will allow this library to be used in my project - Apache Airflow.

Yours faithfully.

Discussion:

Patch:
diff --git a/README.md b/README.md
index 270ab6a..f8560c2 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,8 @@ $ 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
@@ -75,6 +77,25 @@ def start_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
 
diff --git a/flask_compress.py b/flask_compress.py
index 9770dda..38cca65 100644
--- a/flask_compress.py
+++ b/flask_compress.py
@@ -4,6 +4,7 @@
 # License: The MIT License (MIT)
 
 import sys
+import functools
 from gzip import GzipFile
 import zlib
 from io import BytesIO
@@ -11,7 +12,7 @@ from io import BytesIO
 from collections import defaultdict
 
 import brotli
-from flask import request, current_app
+from flask import request, after_this_request, current_app
 
 
 if sys.version_info[:2] == (2, 6):
@@ -196,6 +197,17 @@ class Compress(object):
 
         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()


Test patch:
diff --git a/tests/test_flask_compress.py b/tests/test_flask_compress.py
index 287118a..fca0c41 100644
--- a/tests/test_flask_compress.py
+++ b/tests/test_flask_compress.py
@@ -297,5 +297,36 @@ class CompressionAlgoTests(unittest.TestCase):
         self.assertEqual(response_deflate.headers.get('Content-Encoding'), 'deflate')
 
 
+class CompressionPerViewTests(unittest.TestCase):
+    def setUp(self):
+        self.app = Flask(__name__)
+        self.app.testing = True
+        self.app.config["COMPRESS_REGISTER"] = False
+        compress = Compress()
+        compress.init_app(self.app)
+
+        @self.app.route('/route1/')
+        def view_1():
+            return render_template('large.html')
+
+        @self.app.route('/route2/')
+        @compress.compressed()
+        def view_2():
+            return render_template('large.html')
+
+    def test_compression(self):
+        client = self.app.test_client()
+        headers = [('Accept-Encoding', 'deflate')]
+
+        response = client.get('/route1/', headers=headers)
+        self.assertEqual(response.status_code, 200)
+        self.assertNotIn('Content-Encoding', response.headers)
+
+        response = client.get('/route2/', headers=headers)
+        self.assertEqual(response.status_code, 200)
+        self.assertIn('Content-Encoding', response.headers)
+        self.assertEqual(response.headers.get('Content-Encoding'), 'deflate')
+
+
 if __name__ == '__main__':
     unittest.main()