Skip to content

Commit f01ed7e

Browse files
committed
Move Minify class to minify.py file
1 parent 70fc901 commit f01ed7e

File tree

4 files changed

+106
-102
lines changed

4 files changed

+106
-102
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ A Quart extension to minify quart response for html, javascript, css and less co
1818

1919
```python
2020
from quart import Quart
21-
from quart_minify import Minify
21+
from quart_minify.minify import Minify
2222

2323
app = Quart(__name__)
2424
Minify(app=app)

quart_minify/__init__.py

Lines changed: 2 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,3 @@
1-
from quart import request
2-
from lesscpy import compile
3-
from jsmin import jsmin
4-
from six import StringIO
5-
from htmlmin import minify as minify_html
6-
from hashlib import md5
1+
from quart_minify.minify import Minify
72

8-
9-
class Minify:
10-
def __init__(
11-
self, app=None, html=True, js=True, cssless=True, cache=True, fail_safe=True, bypass=()
12-
):
13-
"""
14-
A Quart extension to minify flask response for html,
15-
javascript, css and less.
16-
@param: app Quart app instance to be passed (default:None).
17-
@param: js To minify the css output (default:False).
18-
@param: cssless To minify spaces in css (default:True).
19-
@param: cache To cache minifed response with hash (default: True).
20-
@param: fail_safe to avoid raising error while minifying (default True)
21-
@param: bypass a list of the routes to be bypassed by the minifer
22-
"""
23-
self.app = app
24-
self.html = html
25-
self.js = js
26-
self.cssless = cssless
27-
self.cache = cache
28-
self.fail_safe = fail_safe
29-
self.bypass = bypass
30-
self.history = {} # where cache hash and compiled response stored
31-
self.hashes = {} # where the hashes and text will be stored
32-
33-
if self.app is None:
34-
raise (AttributeError("minify(app=) requires Quart app instance"))
35-
36-
for arg in ["cssless", "js", "html", "cache"]:
37-
if not isinstance(eval(arg), bool):
38-
raise (TypeError("minify(" + arg + "=) requires True or False"))
39-
40-
self.app.after_request(self.to_loop_tag)
41-
42-
def get_hashed(self, text):
43-
""" to return text hashed and store it in hashes """
44-
if text in self.hashes.keys():
45-
return self.hashes.get(text)
46-
else:
47-
hashed = md5(text.encode("utf8")).hexdigest()[:9]
48-
self.hashes[text] = hashed
49-
return hashed
50-
51-
def store_minifed(self, css, text, to_replace):
52-
""" to minify and store in history with hash key """
53-
if self.cache and self.get_hashed(text) in self.history.keys():
54-
return self.history[self.get_hashed(text)]
55-
else:
56-
minifed = (
57-
compile(StringIO(to_replace), minify=True, xminify=True)
58-
if css
59-
else jsmin(to_replace).replace("\n", ";")
60-
)
61-
62-
if self.cache and self.get_hashed(text) not in self.history.keys():
63-
self.history[self.get_hashed(text)] = minifed
64-
65-
return minifed
66-
67-
async def to_loop_tag(self, response):
68-
if (
69-
response.content_type == "text/html; charset=utf-8"
70-
and request.url_rule.rule not in self.bypass
71-
):
72-
response.direct_passthrough = False
73-
text = await response.get_data(raw=False)
74-
75-
for tag in [t for t in [(0, "style")[self.cssless], (0, "script")[self.js]] if t != 0]:
76-
if f"<{tag} type=" in text or f"<{tag}>" in text:
77-
for i in range(1, len(text.split(f"<{tag}"))):
78-
to_replace = (
79-
text.split(f"<{tag}", i)[i].split(f"</{tag}>")[0].split(">", 1)[1]
80-
)
81-
82-
result = None
83-
try:
84-
result = (
85-
text.replace(
86-
to_replace, self.store_minifed(tag == "style", text, to_replace)
87-
)
88-
if len(to_replace) > 2
89-
else text
90-
)
91-
text = result
92-
except Exception as e:
93-
if self.fail_safe:
94-
text = result or text
95-
else:
96-
raise e
97-
98-
final_resp = minify_html(text) if self.html else text
99-
response.set_data(final_resp)
100-
101-
return response
3+
__all__ = ["Minify"]

quart_minify/minify.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from hashlib import md5
2+
from io import StringIO
3+
4+
from htmlmin import minify as minify_html
5+
from jsmin import jsmin
6+
from lesscpy import compile
7+
from quart import request
8+
9+
10+
class Minify:
11+
def __init__(
12+
self, app=None, html=True, js=True, cssless=True, cache=True, fail_safe=True, bypass=()
13+
):
14+
"""
15+
A Quart extension to minify flask response for html,
16+
javascript, css and less.
17+
@param: app Quart app instance to be passed (default:None).
18+
@param: js To minify the css output (default:False).
19+
@param: cssless To minify spaces in css (default:True).
20+
@param: cache To cache minifed response with hash (default: True).
21+
@param: fail_safe to avoid raising error while minifying (default True)
22+
@param: bypass a list of the routes to be bypassed by the minifer
23+
"""
24+
self.app = app
25+
self.html = html
26+
self.js = js
27+
self.cssless = cssless
28+
self.cache = cache
29+
self.fail_safe = fail_safe
30+
self.bypass = bypass
31+
self.history = {} # where cache hash and compiled response stored
32+
self.hashes = {} # where the hashes and text will be stored
33+
34+
if self.app is None:
35+
raise (AttributeError("minify(app=) requires Quart app instance"))
36+
37+
for arg in ["cssless", "js", "html", "cache"]:
38+
if not isinstance(eval(arg), bool):
39+
raise (TypeError("minify(" + arg + "=) requires True or False"))
40+
41+
self.app.after_request(self.to_loop_tag)
42+
43+
def get_hashed(self, text):
44+
""" to return text hashed and store it in hashes """
45+
if text in self.hashes.keys():
46+
return self.hashes.get(text)
47+
else:
48+
hashed = md5(text.encode("utf8")).hexdigest()[:9]
49+
self.hashes[text] = hashed
50+
return hashed
51+
52+
def store_minifed(self, css, text, to_replace):
53+
""" to minify and store in history with hash key """
54+
if self.cache and self.get_hashed(text) in self.history.keys():
55+
return self.history[self.get_hashed(text)]
56+
else:
57+
minifed = (
58+
compile(StringIO(to_replace), minify=True, xminify=True)
59+
if css
60+
else jsmin(to_replace).replace("\n", ";")
61+
)
62+
63+
if self.cache and self.get_hashed(text) not in self.history.keys():
64+
self.history[self.get_hashed(text)] = minifed
65+
66+
return minifed
67+
68+
async def to_loop_tag(self, response):
69+
if (
70+
response.content_type == "text/html; charset=utf-8"
71+
and request.url_rule.rule not in self.bypass
72+
):
73+
response.direct_passthrough = False
74+
text = await response.get_data(raw=False)
75+
76+
for tag in [t for t in [(0, "style")[self.cssless], (0, "script")[self.js]] if t != 0]:
77+
if f"<{tag} type=" in text or f"<{tag}>" in text:
78+
for i in range(1, len(text.split(f"<{tag}"))):
79+
to_replace = (
80+
text.split(f"<{tag}", i)[i].split(f"</{tag}>")[0].split(">", 1)[1]
81+
)
82+
83+
result = None
84+
try:
85+
result = (
86+
text.replace(
87+
to_replace, self.store_minifed(tag == "style", text, to_replace)
88+
)
89+
if len(to_replace) > 2
90+
else text
91+
)
92+
text = result
93+
except Exception as e:
94+
if self.fail_safe:
95+
text = result or text
96+
else:
97+
raise e
98+
99+
final_resp = minify_html(text) if self.html else text
100+
response.set_data(final_resp)
101+
102+
return response

tests/test_fm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
from pytest import fixture
33
from quart import Quart
4-
from quart_minify import Minify
4+
from quart_minify.minify import Minify
55

66
app = Quart(__name__)
77

0 commit comments

Comments
 (0)