Repository: mrf345/flask_minify

Issue:
DeprecationWarning: `_app_ctx_stack` is deprecated and will be removed in Flask `2.3`. Use `g` to store data, or `app_ctx` to access the current context.
Please address this deprecation warning in next release.

```
/venv/lib/python3.9/site-packages/flask_minify/main.py:122: DeprecationWarning: '_app_ctx_stack' is deprecated and will be removed in Flask 2.3. Use 'g' to store data, or 'app_ctx' to access the current context.
  return self._app or (_app_ctx_stack.top and _app_ctx_stack.top.app)
```

Comments:

Patch:
diff --git a/Makefile b/Makefile
index 608c314..1227923 100644
--- a/Makefile
+++ b/Makefile
@@ -6,9 +6,9 @@ c ?= 1
 test: install
 	test -f .venv/bin/activate && source .venv/bin/activate && python -m bandit -c bandit.yml -r . && python -m pytest --count=$(c)
 lint: install
-	source .venv/bin/activate && python -m isort --profile black --check . && python -m black --check .
+	source .venv/bin/activate && python -m isort -sg "**/.venv*" --profile black --check . && python -m black --check .
 format: install
-	test -f .venv/bin/activate && source .venv/bin/activate && python -m isort --profile black . && python -m black .
+	test -f .venv/bin/activate && source .venv/bin/activate && python -m isort -sg "**/.venv*" --profile black . && python -m black .
 run: install
 	python tests/integration.py
 release: install-dev clean
diff --git a/README.md b/README.md
index 1d17a44..29fdd1b 100644
--- a/README.md
+++ b/README.md
@@ -149,6 +149,10 @@ the **default** parsers are set to `{"html": Html, "script": Jsmin, "style": Rcs
 
 ## Breaking changes
 
+#### `0.40`
+
+Due to a future deprecation in Flask 2.3, the extension is no longer going to fallback to `Flask._app_ctx_stack`, it will raise an exception instead (`flask_minify.exceptions.MissingApp`)
+
 #### `0.33`
 
 introduces a breaking change to the expected output, in this release `lesscpy` will be replaced by `cssmin` as
diff --git a/flask_minify/about.py b/flask_minify/about.py
index 7071428..ef4cfb0 100644
--- a/flask_minify/about.py
+++ b/flask_minify/about.py
@@ -1,4 +1,4 @@
-__version__ = "0.39"
+__version__ = "0.40"
 __doc__ = "Flask extension to minify html, css, js and less."
 __license__ = "MIT"
 __author__ = "Mohamed Feddad"
diff --git a/flask_minify/exceptions.py b/flask_minify/exceptions.py
new file mode 100644
index 0000000..3c99cd0
--- /dev/null
+++ b/flask_minify/exceptions.py
@@ -0,0 +1,10 @@
+class FlaskMinifyException(Exception):
+    """FlaskMinify base exception"""
+
+    pass
+
+
+class MissingApp(FlaskMinifyException):
+    """Raised when the flask app is accessed before it's set"""
+
+    pass
diff --git a/flask_minify/main.py b/flask_minify/main.py
index 9dba299..8fc30fe 100644
--- a/flask_minify/main.py
+++ b/flask_minify/main.py
@@ -1,9 +1,10 @@
 from itertools import tee
 from re import compile as compile_re
 
-from flask import _app_ctx_stack, request
+from flask import request
 
 from flask_minify.cache import MemoryCache
+from flask_minify.exceptions import MissingApp
 from flask_minify.parsers import Parser
 from flask_minify.utils import does_content_type_match
 
@@ -112,14 +113,24 @@ class Minify:
 
     @property
     def app(self):
-        """If app was passed take it, if not get the one on top.
+        """If app was passed take it, otherwise raise an exception.
 
         Returns
         -------
         Flask App
             The current Flask application.
+
+        Raises
+        ------
+        MissingApp
         """
-        return self._app or (_app_ctx_stack.top and _app_ctx_stack.top.app)
+        if not self._app:
+            raise MissingApp(
+                "Flask app has not been passed to the extension `Minify(app=None)`, "
+                "nor lazy initialized with `.init_app(app)`"
+            )
+
+        return self._app
 
     def init_app(self, app):
         """Handle initiation of multiple apps NOTE:Factory Method"""


Test patch:
diff --git a/tests/units.py b/tests/units.py
index ddd1aa5..97606da 100644
--- a/tests/units.py
+++ b/tests/units.py
@@ -1,8 +1,10 @@
-from random import randint
 from unittest import mock
 
+import pytest
+
 from flask_minify import minify, parsers
 from flask_minify.cache import MemoryCache
+from flask_minify.exceptions import MissingApp
 from flask_minify.utils import does_content_type_match, is_empty
 
 from .constants import (
@@ -87,6 +89,14 @@ class TestMinifyRequest:
 
         assert (list(matches), exists) == ([], False)
 
+    def test_access_missing_app_raises_exception(self):
+        """test accessing a missing flask app raises an exception"""
+        self.mock_app = None
+        ext = self.minify_defaults
+
+        with pytest.raises(MissingApp):
+            ext.app
+
 
 class TestParsers:
     def test_css_edge_cases_with_rcssmin(self):