Merge lp:~thedac/ubuntu/wily/python-django-compressor/debian-merge into lp:ubuntu/wily/python-django-compressor
- Wily (15.10)
- debian-merge
- Merge into wily
Proposed by
David Ames
Status: | Merged |
---|---|
Merge reported by: | Martin Pitt |
Merged at revision: | not available |
Proposed branch: | lp:~thedac/ubuntu/wily/python-django-compressor/debian-merge |
Merge into: | lp:ubuntu/wily/python-django-compressor |
Diff against target: |
2565 lines (+680/-930) 53 files modified
.pc/.quilt_patches (+0/-1) .pc/.quilt_series (+0/-1) .pc/.version (+0/-1) .pc/applied-patches (+0/-2) .pc/disable-coffin-tests.patch/compressor/test_settings.py (+0/-40) .pc/disable-coffin-tests.patch/compressor/tests/test_offline.py (+0/-499) .pc/fix-test_settings.py-for-django-1.7.patch/compressor/test_settings.py (+0/-40) .travis.yml (+15/-10) AUTHORS (+1/-0) README.rst (+10/-7) compressor/__init__.py (+1/-1) compressor/base.py (+8/-2) compressor/cache.py (+13/-3) compressor/conf.py (+2/-0) compressor/css.py (+1/-1) compressor/filters/base.py (+27/-3) compressor/filters/cleancss.py (+10/-0) compressor/filters/css_default.py (+3/-9) compressor/js.py (+32/-4) compressor/management/commands/compress.py (+25/-18) compressor/offline/django.py (+27/-16) compressor/parser/__init__.py (+5/-2) compressor/templates/compressor/js_file.html (+1/-1) compressor/test_settings.py (+19/-2) compressor/tests/precompiler.py (+4/-4) compressor/tests/static/css/filename with spaces.css (+1/-0) compressor/tests/static/css/utf-8_with-BOM.css (+1/-0) compressor/tests/static/js/three.js (+1/-0) compressor/tests/static/js/two.js (+1/-0) compressor/tests/test_base.py (+66/-3) compressor/tests/test_filters.py (+135/-59) compressor/tests/test_jinja2ext.py (+1/-2) compressor/tests/test_offline.py (+20/-19) compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html (+5/-0) compressor/utils/staticfiles.py (+4/-14) debian/changelog (+20/-0) debian/control (+44/-12) debian/gbp.conf (+1/-1) debian/patches/disable-coffin-tests.patch (+6/-6) debian/patches/fix-test_settings.py-for-django-1.7.patch (+0/-16) debian/patches/remove-failed-test.patch (+43/-0) debian/patches/series (+1/-1) debian/rules (+18/-14) debian/watch (+2/-1) docs/changelog.txt (+38/-4) docs/contributing.txt (+5/-4) docs/django-sekizai.txt (+4/-4) docs/jinja2.txt (+5/-6) docs/quickstart.txt (+3/-5) docs/remote-storages.txt (+5/-7) docs/settings.txt (+22/-6) docs/usage.txt (+1/-1) tox.ini (+23/-78) |
To merge this branch: | bzr merge lp:~thedac/ubuntu/wily/python-django-compressor/debian-merge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Corey Bryant | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+268621@code.launchpad.net |
Commit message
Description of the change
Debian Merge
To post a comment you must log in.
Revision history for this message
Corey Bryant (corey.bryant) wrote : | # |
- 8. By David Ames
-
Sync up d/control
- 9. By David Ames
-
Fix d/watch
Revision history for this message
Corey Bryant (corey.bryant) : | # |
review:
Approve
Revision history for this message
Martin Pitt (pitti) wrote : | # |
This was already merged: https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed directory '.pc' | |||
2 | === removed file '.pc/.quilt_patches' | |||
3 | --- .pc/.quilt_patches 2012-10-14 10:51:47 +0000 | |||
4 | +++ .pc/.quilt_patches 1970-01-01 00:00:00 +0000 | |||
5 | @@ -1,1 +0,0 @@ | |||
6 | 1 | debian/patches | ||
7 | 2 | 0 | ||
8 | === removed file '.pc/.quilt_series' | |||
9 | --- .pc/.quilt_series 2012-10-14 10:51:47 +0000 | |||
10 | +++ .pc/.quilt_series 1970-01-01 00:00:00 +0000 | |||
11 | @@ -1,1 +0,0 @@ | |||
12 | 1 | series | ||
13 | 2 | 0 | ||
14 | === removed file '.pc/.version' | |||
15 | --- .pc/.version 2012-10-14 10:51:47 +0000 | |||
16 | +++ .pc/.version 1970-01-01 00:00:00 +0000 | |||
17 | @@ -1,1 +0,0 @@ | |||
18 | 1 | 2 | ||
19 | 2 | 0 | ||
20 | === removed file '.pc/applied-patches' | |||
21 | --- .pc/applied-patches 2015-01-06 12:34:51 +0000 | |||
22 | +++ .pc/applied-patches 1970-01-01 00:00:00 +0000 | |||
23 | @@ -1,2 +0,0 @@ | |||
24 | 1 | fix-test_settings.py-for-django-1.7.patch | ||
25 | 2 | disable-coffin-tests.patch | ||
26 | 3 | 0 | ||
27 | === removed directory '.pc/disable-coffin-tests.patch' | |||
28 | === removed directory '.pc/disable-coffin-tests.patch/compressor' | |||
29 | === removed file '.pc/disable-coffin-tests.patch/compressor/test_settings.py' | |||
30 | --- .pc/disable-coffin-tests.patch/compressor/test_settings.py 2015-01-06 12:34:51 +0000 | |||
31 | +++ .pc/disable-coffin-tests.patch/compressor/test_settings.py 1970-01-01 00:00:00 +0000 | |||
32 | @@ -1,40 +0,0 @@ | |||
33 | 1 | import os | ||
34 | 2 | import django | ||
35 | 3 | |||
36 | 4 | TEST_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'tests') | ||
37 | 5 | |||
38 | 6 | COMPRESS_CACHE_BACKEND = 'django.core.cache.backends.locmem.CacheClass' | ||
39 | 7 | |||
40 | 8 | DATABASES = { | ||
41 | 9 | 'default': { | ||
42 | 10 | 'ENGINE': 'django.db.backends.sqlite3', | ||
43 | 11 | 'NAME': ':memory:', | ||
44 | 12 | } | ||
45 | 13 | } | ||
46 | 14 | |||
47 | 15 | INSTALLED_APPS = [ | ||
48 | 16 | 'compressor', | ||
49 | 17 | 'coffin', | ||
50 | 18 | 'jingo', | ||
51 | 19 | ] | ||
52 | 20 | |||
53 | 21 | STATIC_URL = '/static/' | ||
54 | 22 | |||
55 | 23 | |||
56 | 24 | STATIC_ROOT = os.path.join(TEST_DIR, 'static') | ||
57 | 25 | |||
58 | 26 | TEMPLATE_DIRS = ( | ||
59 | 27 | # Specifically choose a name that will not be considered | ||
60 | 28 | # by app_directories loader, to make sure each test uses | ||
61 | 29 | # a specific template without considering the others. | ||
62 | 30 | os.path.join(TEST_DIR, 'test_templates'), | ||
63 | 31 | ) | ||
64 | 32 | |||
65 | 33 | if django.VERSION[:2] < (1, 6): | ||
66 | 34 | TEST_RUNNER = 'discover_runner.DiscoverRunner' | ||
67 | 35 | |||
68 | 36 | SECRET_KEY = "iufoj=mibkpdz*%bob952x(%49rqgv8gg45k36kjcg76&-y5=!" | ||
69 | 37 | |||
70 | 38 | PASSWORD_HASHERS = ( | ||
71 | 39 | 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', | ||
72 | 40 | ) | ||
73 | 41 | 0 | ||
74 | === removed directory '.pc/disable-coffin-tests.patch/compressor/tests' | |||
75 | === removed file '.pc/disable-coffin-tests.patch/compressor/tests/test_offline.py' | |||
76 | --- .pc/disable-coffin-tests.patch/compressor/tests/test_offline.py 2015-01-06 12:34:51 +0000 | |||
77 | +++ .pc/disable-coffin-tests.patch/compressor/tests/test_offline.py 1970-01-01 00:00:00 +0000 | |||
78 | @@ -1,499 +0,0 @@ | |||
79 | 1 | from __future__ import with_statement, unicode_literals | ||
80 | 2 | import io | ||
81 | 3 | import os | ||
82 | 4 | import sys | ||
83 | 5 | |||
84 | 6 | from django.core.management.base import CommandError | ||
85 | 7 | from django.template import Template, Context | ||
86 | 8 | from django.test import TestCase | ||
87 | 9 | from django.utils import six, unittest | ||
88 | 10 | |||
89 | 11 | from compressor.cache import flush_offline_manifest, get_offline_manifest | ||
90 | 12 | from compressor.conf import settings | ||
91 | 13 | from compressor.exceptions import OfflineGenerationError | ||
92 | 14 | from compressor.management.commands.compress import Command as CompressCommand | ||
93 | 15 | from compressor.storage import default_storage | ||
94 | 16 | |||
95 | 17 | if six.PY3: | ||
96 | 18 | # there is an 'io' module in python 2.6+, but io.StringIO does not | ||
97 | 19 | # accept regular strings, just unicode objects | ||
98 | 20 | from io import StringIO | ||
99 | 21 | else: | ||
100 | 22 | try: | ||
101 | 23 | from cStringIO import StringIO | ||
102 | 24 | except ImportError: | ||
103 | 25 | from StringIO import StringIO | ||
104 | 26 | |||
105 | 27 | # The Jinja2 tests fail on Python 3.2 due to the following: | ||
106 | 28 | # The line in compressor/management/commands/compress.py: | ||
107 | 29 | # compressor_nodes.setdefault(template, []).extend(nodes) | ||
108 | 30 | # causes the error "unhashable type: 'Template'" | ||
109 | 31 | _TEST_JINJA2 = not(sys.version_info[0] == 3 and sys.version_info[1] == 2) | ||
110 | 32 | |||
111 | 33 | |||
112 | 34 | class OfflineTestCaseMixin(object): | ||
113 | 35 | template_name = "test_compressor_offline.html" | ||
114 | 36 | verbosity = 0 | ||
115 | 37 | # Change this for each test class | ||
116 | 38 | templates_dir = "" | ||
117 | 39 | expected_hash = "" | ||
118 | 40 | # Engines to test | ||
119 | 41 | if _TEST_JINJA2: | ||
120 | 42 | engines = ("django", "jinja2") | ||
121 | 43 | else: | ||
122 | 44 | engines = ("django",) | ||
123 | 45 | |||
124 | 46 | def setUp(self): | ||
125 | 47 | self._old_compress = settings.COMPRESS_ENABLED | ||
126 | 48 | self._old_compress_offline = settings.COMPRESS_OFFLINE | ||
127 | 49 | self._old_template_dirs = settings.TEMPLATE_DIRS | ||
128 | 50 | self._old_offline_context = settings.COMPRESS_OFFLINE_CONTEXT | ||
129 | 51 | self.log = StringIO() | ||
130 | 52 | |||
131 | 53 | # Reset template dirs, because it enables us to force compress to | ||
132 | 54 | # consider only a specific directory (helps us make true, | ||
133 | 55 | # independant unit tests). | ||
134 | 56 | # Specify both Jinja2 and Django template locations. When the wrong engine | ||
135 | 57 | # is used to parse a template, the TemplateSyntaxError will cause the | ||
136 | 58 | # template to be skipped over. | ||
137 | 59 | django_template_dir = os.path.join(settings.TEST_DIR, 'test_templates', self.templates_dir) | ||
138 | 60 | jinja2_template_dir = os.path.join(settings.TEST_DIR, 'test_templates_jinja2', self.templates_dir) | ||
139 | 61 | settings.TEMPLATE_DIRS = (django_template_dir, jinja2_template_dir) | ||
140 | 62 | |||
141 | 63 | # Enable offline compress | ||
142 | 64 | settings.COMPRESS_ENABLED = True | ||
143 | 65 | settings.COMPRESS_OFFLINE = True | ||
144 | 66 | |||
145 | 67 | if "django" in self.engines: | ||
146 | 68 | self.template_path = os.path.join(django_template_dir, self.template_name) | ||
147 | 69 | |||
148 | 70 | with io.open(self.template_path, encoding=settings.FILE_CHARSET) as file: | ||
149 | 71 | self.template = Template(file.read()) | ||
150 | 72 | |||
151 | 73 | self._old_jinja2_get_environment = settings.COMPRESS_JINJA2_GET_ENVIRONMENT | ||
152 | 74 | |||
153 | 75 | if "jinja2" in self.engines: | ||
154 | 76 | # Setup Jinja2 settings. | ||
155 | 77 | settings.COMPRESS_JINJA2_GET_ENVIRONMENT = lambda: self._get_jinja2_env() | ||
156 | 78 | jinja2_env = settings.COMPRESS_JINJA2_GET_ENVIRONMENT() | ||
157 | 79 | self.template_path_jinja2 = os.path.join(jinja2_template_dir, self.template_name) | ||
158 | 80 | |||
159 | 81 | with io.open(self.template_path_jinja2, encoding=settings.FILE_CHARSET) as file: | ||
160 | 82 | self.template_jinja2 = jinja2_env.from_string(file.read()) | ||
161 | 83 | |||
162 | 84 | def tearDown(self): | ||
163 | 85 | settings.COMPRESS_JINJA2_GET_ENVIRONMENT = self._old_jinja2_get_environment | ||
164 | 86 | settings.COMPRESS_ENABLED = self._old_compress | ||
165 | 87 | settings.COMPRESS_OFFLINE = self._old_compress_offline | ||
166 | 88 | settings.TEMPLATE_DIRS = self._old_template_dirs | ||
167 | 89 | manifest_path = os.path.join('CACHE', 'manifest.json') | ||
168 | 90 | if default_storage.exists(manifest_path): | ||
169 | 91 | default_storage.delete(manifest_path) | ||
170 | 92 | |||
171 | 93 | def _render_template(self, engine): | ||
172 | 94 | if engine == "django": | ||
173 | 95 | return self.template.render(Context(settings.COMPRESS_OFFLINE_CONTEXT)) | ||
174 | 96 | elif engine == "jinja2": | ||
175 | 97 | return self.template_jinja2.render(settings.COMPRESS_OFFLINE_CONTEXT) + "\n" | ||
176 | 98 | else: | ||
177 | 99 | return None | ||
178 | 100 | |||
179 | 101 | def _test_offline(self, engine): | ||
180 | 102 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
181 | 103 | self.assertEqual(1, count) | ||
182 | 104 | self.assertEqual([ | ||
183 | 105 | '<script type="text/javascript" src="/static/CACHE/js/%s.js"></script>' % (self.expected_hash, ), | ||
184 | 106 | ], result) | ||
185 | 107 | rendered_template = self._render_template(engine) | ||
186 | 108 | self.assertEqual(rendered_template, "".join(result) + "\n") | ||
187 | 109 | |||
188 | 110 | def test_offline(self): | ||
189 | 111 | for engine in self.engines: | ||
190 | 112 | self._test_offline(engine=engine) | ||
191 | 113 | |||
192 | 114 | def _get_jinja2_env(self): | ||
193 | 115 | import jinja2 | ||
194 | 116 | import jinja2.ext | ||
195 | 117 | from compressor.offline.jinja2 import url_for, SpacelessExtension | ||
196 | 118 | from compressor.contrib.jinja2ext import CompressorExtension | ||
197 | 119 | |||
198 | 120 | # Extensions needed for the test cases only. | ||
199 | 121 | extensions = [ | ||
200 | 122 | CompressorExtension, | ||
201 | 123 | SpacelessExtension, | ||
202 | 124 | jinja2.ext.with_, | ||
203 | 125 | jinja2.ext.do, | ||
204 | 126 | ] | ||
205 | 127 | loader = self._get_jinja2_loader() | ||
206 | 128 | env = jinja2.Environment(extensions=extensions, loader=loader) | ||
207 | 129 | env.globals['url_for'] = url_for | ||
208 | 130 | |||
209 | 131 | return env | ||
210 | 132 | |||
211 | 133 | def _get_jinja2_loader(self): | ||
212 | 134 | import jinja2 | ||
213 | 135 | |||
214 | 136 | loader = jinja2.FileSystemLoader(settings.TEMPLATE_DIRS, encoding=settings.FILE_CHARSET) | ||
215 | 137 | return loader | ||
216 | 138 | |||
217 | 139 | |||
218 | 140 | class OfflineGenerationSkipDuplicatesTestCase(OfflineTestCaseMixin, TestCase): | ||
219 | 141 | templates_dir = "test_duplicate" | ||
220 | 142 | |||
221 | 143 | # We don't need to test multiples engines here. | ||
222 | 144 | engines = ("django",) | ||
223 | 145 | |||
224 | 146 | def _test_offline(self, engine): | ||
225 | 147 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
226 | 148 | # Only one block compressed, the second identical one was skipped. | ||
227 | 149 | self.assertEqual(1, count) | ||
228 | 150 | # Only 1 <script> block in returned result as well. | ||
229 | 151 | self.assertEqual([ | ||
230 | 152 | '<script type="text/javascript" src="/static/CACHE/js/f5e179b8eca4.js"></script>', | ||
231 | 153 | ], result) | ||
232 | 154 | rendered_template = self._render_template(engine) | ||
233 | 155 | # But rendering the template returns both (identical) scripts. | ||
234 | 156 | self.assertEqual(rendered_template, "".join(result * 2) + "\n") | ||
235 | 157 | |||
236 | 158 | |||
237 | 159 | class OfflineGenerationBlockSuperTestCase(OfflineTestCaseMixin, TestCase): | ||
238 | 160 | templates_dir = "test_block_super" | ||
239 | 161 | expected_hash = "7c02d201f69d" | ||
240 | 162 | # Block.super not supported for Jinja2 yet. | ||
241 | 163 | engines = ("django",) | ||
242 | 164 | |||
243 | 165 | |||
244 | 166 | class OfflineGenerationBlockSuperMultipleTestCase(OfflineTestCaseMixin, TestCase): | ||
245 | 167 | templates_dir = "test_block_super_multiple" | ||
246 | 168 | expected_hash = "f8891c416981" | ||
247 | 169 | # Block.super not supported for Jinja2 yet. | ||
248 | 170 | engines = ("django",) | ||
249 | 171 | |||
250 | 172 | |||
251 | 173 | class OfflineGenerationBlockSuperMultipleWithCachedLoaderTestCase(OfflineTestCaseMixin, TestCase): | ||
252 | 174 | templates_dir = "test_block_super_multiple_cached" | ||
253 | 175 | expected_hash = "2f6ef61c488e" | ||
254 | 176 | # Block.super not supported for Jinja2 yet. | ||
255 | 177 | engines = ("django",) | ||
256 | 178 | |||
257 | 179 | def setUp(self): | ||
258 | 180 | self._old_template_loaders = settings.TEMPLATE_LOADERS | ||
259 | 181 | settings.TEMPLATE_LOADERS = ( | ||
260 | 182 | ('django.template.loaders.cached.Loader', ( | ||
261 | 183 | 'django.template.loaders.filesystem.Loader', | ||
262 | 184 | 'django.template.loaders.app_directories.Loader', | ||
263 | 185 | )), | ||
264 | 186 | ) | ||
265 | 187 | super(OfflineGenerationBlockSuperMultipleWithCachedLoaderTestCase, self).setUp() | ||
266 | 188 | |||
267 | 189 | def tearDown(self): | ||
268 | 190 | super(OfflineGenerationBlockSuperMultipleWithCachedLoaderTestCase, self).tearDown() | ||
269 | 191 | settings.TEMPLATE_LOADERS = self._old_template_loaders | ||
270 | 192 | |||
271 | 193 | |||
272 | 194 | class OfflineGenerationBlockSuperTestCaseWithExtraContent(OfflineTestCaseMixin, TestCase): | ||
273 | 195 | templates_dir = "test_block_super_extra" | ||
274 | 196 | # Block.super not supported for Jinja2 yet. | ||
275 | 197 | engines = ("django",) | ||
276 | 198 | |||
277 | 199 | def _test_offline(self, engine): | ||
278 | 200 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
279 | 201 | self.assertEqual(2, count) | ||
280 | 202 | self.assertEqual([ | ||
281 | 203 | '<script type="text/javascript" src="/static/CACHE/js/ced14aec5856.js"></script>', | ||
282 | 204 | '<script type="text/javascript" src="/static/CACHE/js/7c02d201f69d.js"></script>' | ||
283 | 205 | ], result) | ||
284 | 206 | rendered_template = self._render_template(engine) | ||
285 | 207 | self.assertEqual(rendered_template, "".join(result) + "\n") | ||
286 | 208 | |||
287 | 209 | |||
288 | 210 | class OfflineGenerationConditionTestCase(OfflineTestCaseMixin, TestCase): | ||
289 | 211 | templates_dir = "test_condition" | ||
290 | 212 | expected_hash = "4e3758d50224" | ||
291 | 213 | |||
292 | 214 | def setUp(self): | ||
293 | 215 | self.old_offline_context = settings.COMPRESS_OFFLINE_CONTEXT | ||
294 | 216 | settings.COMPRESS_OFFLINE_CONTEXT = { | ||
295 | 217 | 'condition': 'red', | ||
296 | 218 | } | ||
297 | 219 | super(OfflineGenerationConditionTestCase, self).setUp() | ||
298 | 220 | |||
299 | 221 | def tearDown(self): | ||
300 | 222 | self.COMPRESS_OFFLINE_CONTEXT = self.old_offline_context | ||
301 | 223 | super(OfflineGenerationConditionTestCase, self).tearDown() | ||
302 | 224 | |||
303 | 225 | |||
304 | 226 | class OfflineGenerationTemplateTagTestCase(OfflineTestCaseMixin, TestCase): | ||
305 | 227 | templates_dir = "test_templatetag" | ||
306 | 228 | expected_hash = "a27e1d3a619a" | ||
307 | 229 | |||
308 | 230 | |||
309 | 231 | class OfflineGenerationStaticTemplateTagTestCase(OfflineTestCaseMixin, TestCase): | ||
310 | 232 | templates_dir = "test_static_templatetag" | ||
311 | 233 | expected_hash = "dfa2bb387fa8" | ||
312 | 234 | |||
313 | 235 | |||
314 | 236 | class OfflineGenerationTestCaseWithContext(OfflineTestCaseMixin, TestCase): | ||
315 | 237 | templates_dir = "test_with_context" | ||
316 | 238 | expected_hash = "5838e2fd66af" | ||
317 | 239 | |||
318 | 240 | def setUp(self): | ||
319 | 241 | self.old_offline_context = settings.COMPRESS_OFFLINE_CONTEXT | ||
320 | 242 | settings.COMPRESS_OFFLINE_CONTEXT = { | ||
321 | 243 | 'content': 'OK!', | ||
322 | 244 | } | ||
323 | 245 | super(OfflineGenerationTestCaseWithContext, self).setUp() | ||
324 | 246 | |||
325 | 247 | def tearDown(self): | ||
326 | 248 | settings.COMPRESS_OFFLINE_CONTEXT = self.old_offline_context | ||
327 | 249 | super(OfflineGenerationTestCaseWithContext, self).tearDown() | ||
328 | 250 | |||
329 | 251 | |||
330 | 252 | class OfflineGenerationTestCaseErrors(OfflineTestCaseMixin, TestCase): | ||
331 | 253 | templates_dir = "test_error_handling" | ||
332 | 254 | |||
333 | 255 | def _test_offline(self, engine): | ||
334 | 256 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
335 | 257 | |||
336 | 258 | if engine == "django": | ||
337 | 259 | self.assertEqual(2, count) | ||
338 | 260 | else: | ||
339 | 261 | # Because we use env.parse in Jinja2Parser, the engine does not | ||
340 | 262 | # actually load the "extends" and "includes" templates, and so | ||
341 | 263 | # it is unable to detect that they are missing. So all the "compress" | ||
342 | 264 | # nodes are processed correctly. | ||
343 | 265 | self.assertEqual(4, count) | ||
344 | 266 | self.assertEqual(engine, "jinja2") | ||
345 | 267 | self.assertIn('<link rel="stylesheet" href="/static/CACHE/css/78bd7a762e2d.css" type="text/css" />', result) | ||
346 | 268 | self.assertIn('<link rel="stylesheet" href="/static/CACHE/css/e31030430724.css" type="text/css" />', result) | ||
347 | 269 | |||
348 | 270 | self.assertIn('<script type="text/javascript" src="/static/CACHE/js/3872c9ae3f42.js"></script>', result) | ||
349 | 271 | self.assertIn('<script type="text/javascript" src="/static/CACHE/js/cd8870829421.js"></script>', result) | ||
350 | 272 | |||
351 | 273 | |||
352 | 274 | class OfflineGenerationTestCaseWithError(OfflineTestCaseMixin, TestCase): | ||
353 | 275 | templates_dir = 'test_error_handling' | ||
354 | 276 | |||
355 | 277 | def setUp(self): | ||
356 | 278 | self._old_compress_precompilers = settings.COMPRESS_PRECOMPILERS | ||
357 | 279 | settings.COMPRESS_PRECOMPILERS = (('text/coffeescript', 'non-existing-binary'),) | ||
358 | 280 | super(OfflineGenerationTestCaseWithError, self).setUp() | ||
359 | 281 | |||
360 | 282 | def _test_offline(self, engine): | ||
361 | 283 | """ | ||
362 | 284 | Test that a CommandError is raised with DEBUG being False as well as | ||
363 | 285 | True, as otherwise errors in configuration will never show in | ||
364 | 286 | production. | ||
365 | 287 | """ | ||
366 | 288 | self._old_debug = settings.DEBUG | ||
367 | 289 | |||
368 | 290 | try: | ||
369 | 291 | settings.DEBUG = True | ||
370 | 292 | self.assertRaises(CommandError, CompressCommand().compress, engine=engine) | ||
371 | 293 | |||
372 | 294 | settings.DEBUG = False | ||
373 | 295 | self.assertRaises(CommandError, CompressCommand().compress, engine=engine) | ||
374 | 296 | |||
375 | 297 | finally: | ||
376 | 298 | settings.DEBUG = self._old_debug | ||
377 | 299 | |||
378 | 300 | def tearDown(self): | ||
379 | 301 | settings.COMPRESS_PRECOMPILERS = self._old_compress_precompilers | ||
380 | 302 | super(OfflineGenerationTestCaseWithError, self).tearDown() | ||
381 | 303 | |||
382 | 304 | |||
383 | 305 | class OfflineGenerationTestCase(OfflineTestCaseMixin, TestCase): | ||
384 | 306 | templates_dir = "basic" | ||
385 | 307 | expected_hash = "f5e179b8eca4" | ||
386 | 308 | |||
387 | 309 | def test_rendering_without_manifest_raises_exception(self): | ||
388 | 310 | # flush cached manifest | ||
389 | 311 | flush_offline_manifest() | ||
390 | 312 | self.assertRaises(OfflineGenerationError, | ||
391 | 313 | self.template.render, Context({})) | ||
392 | 314 | |||
393 | 315 | @unittest.skipIf(not _TEST_JINJA2, "No Jinja2 testing") | ||
394 | 316 | def test_rendering_without_manifest_raises_exception_jinja2(self): | ||
395 | 317 | # flush cached manifest | ||
396 | 318 | flush_offline_manifest() | ||
397 | 319 | self.assertRaises(OfflineGenerationError, | ||
398 | 320 | self.template_jinja2.render, {}) | ||
399 | 321 | |||
400 | 322 | def _test_deleting_manifest_does_not_affect_rendering(self, engine): | ||
401 | 323 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
402 | 324 | get_offline_manifest() | ||
403 | 325 | manifest_path = os.path.join('CACHE', 'manifest.json') | ||
404 | 326 | if default_storage.exists(manifest_path): | ||
405 | 327 | default_storage.delete(manifest_path) | ||
406 | 328 | self.assertEqual(1, count) | ||
407 | 329 | self.assertEqual([ | ||
408 | 330 | '<script type="text/javascript" src="/static/CACHE/js/%s.js"></script>' % (self.expected_hash, ), | ||
409 | 331 | ], result) | ||
410 | 332 | rendered_template = self._render_template(engine) | ||
411 | 333 | self.assertEqual(rendered_template, "".join(result) + "\n") | ||
412 | 334 | |||
413 | 335 | def test_deleting_manifest_does_not_affect_rendering(self): | ||
414 | 336 | for engine in self.engines: | ||
415 | 337 | self._test_deleting_manifest_does_not_affect_rendering(engine) | ||
416 | 338 | |||
417 | 339 | def test_requires_model_validation(self): | ||
418 | 340 | self.assertFalse(CompressCommand.requires_model_validation) | ||
419 | 341 | |||
420 | 342 | def test_get_loaders(self): | ||
421 | 343 | old_loaders = settings.TEMPLATE_LOADERS | ||
422 | 344 | settings.TEMPLATE_LOADERS = ( | ||
423 | 345 | ('django.template.loaders.cached.Loader', ( | ||
424 | 346 | 'django.template.loaders.filesystem.Loader', | ||
425 | 347 | 'django.template.loaders.app_directories.Loader', | ||
426 | 348 | )), | ||
427 | 349 | ) | ||
428 | 350 | try: | ||
429 | 351 | from django.template.loaders.filesystem import Loader as FileSystemLoader | ||
430 | 352 | from django.template.loaders.app_directories import Loader as AppDirectoriesLoader | ||
431 | 353 | except ImportError: | ||
432 | 354 | pass | ||
433 | 355 | else: | ||
434 | 356 | loaders = CompressCommand().get_loaders() | ||
435 | 357 | self.assertTrue(isinstance(loaders[0], FileSystemLoader)) | ||
436 | 358 | self.assertTrue(isinstance(loaders[1], AppDirectoriesLoader)) | ||
437 | 359 | finally: | ||
438 | 360 | settings.TEMPLATE_LOADERS = old_loaders | ||
439 | 361 | |||
440 | 362 | |||
441 | 363 | class OfflineGenerationBlockSuperBaseCompressed(OfflineTestCaseMixin, TestCase): | ||
442 | 364 | template_names = ["base.html", "base2.html", "test_compressor_offline.html"] | ||
443 | 365 | templates_dir = 'test_block_super_base_compressed' | ||
444 | 366 | expected_hash = ['028c3fc42232', '2e9d3f5545a6', 'f8891c416981'] | ||
445 | 367 | # Block.super not supported for Jinja2 yet. | ||
446 | 368 | engines = ("django",) | ||
447 | 369 | |||
448 | 370 | def setUp(self): | ||
449 | 371 | super(OfflineGenerationBlockSuperBaseCompressed, self).setUp() | ||
450 | 372 | |||
451 | 373 | self.template_paths = [] | ||
452 | 374 | self.templates = [] | ||
453 | 375 | for template_name in self.template_names: | ||
454 | 376 | template_path = os.path.join(settings.TEMPLATE_DIRS[0], template_name) | ||
455 | 377 | self.template_paths.append(template_path) | ||
456 | 378 | with io.open(template_path, encoding=settings.FILE_CHARSET) as file: | ||
457 | 379 | template = Template(file.read()) | ||
458 | 380 | self.templates.append(template) | ||
459 | 381 | |||
460 | 382 | def _render_template(self, template, engine): | ||
461 | 383 | if engine == "django": | ||
462 | 384 | return template.render(Context(settings.COMPRESS_OFFLINE_CONTEXT)) | ||
463 | 385 | elif engine == "jinja2": | ||
464 | 386 | return template.render(settings.COMPRESS_OFFLINE_CONTEXT) + "\n" | ||
465 | 387 | else: | ||
466 | 388 | return None | ||
467 | 389 | |||
468 | 390 | def _test_offline(self, engine): | ||
469 | 391 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
470 | 392 | self.assertEqual(len(self.expected_hash), count) | ||
471 | 393 | for expected_hash, template in zip(self.expected_hash, self.templates): | ||
472 | 394 | expected_output = '<script type="text/javascript" src="/static/CACHE/js/%s.js"></script>' % (expected_hash, ) | ||
473 | 395 | self.assertIn(expected_output, result) | ||
474 | 396 | rendered_template = self._render_template(template, engine) | ||
475 | 397 | self.assertEqual(rendered_template, expected_output + '\n') | ||
476 | 398 | |||
477 | 399 | |||
478 | 400 | class OfflineGenerationInlineNonAsciiTestCase(OfflineTestCaseMixin, TestCase): | ||
479 | 401 | templates_dir = "test_inline_non_ascii" | ||
480 | 402 | |||
481 | 403 | def setUp(self): | ||
482 | 404 | self.old_offline_context = settings.COMPRESS_OFFLINE_CONTEXT | ||
483 | 405 | settings.COMPRESS_OFFLINE_CONTEXT = { | ||
484 | 406 | 'test_non_ascii_value': '\u2014', | ||
485 | 407 | } | ||
486 | 408 | super(OfflineGenerationInlineNonAsciiTestCase, self).setUp() | ||
487 | 409 | |||
488 | 410 | def tearDown(self): | ||
489 | 411 | self.COMPRESS_OFFLINE_CONTEXT = self.old_offline_context | ||
490 | 412 | super(OfflineGenerationInlineNonAsciiTestCase, self).tearDown() | ||
491 | 413 | |||
492 | 414 | def _test_offline(self, engine): | ||
493 | 415 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
494 | 416 | rendered_template = self._render_template(engine) | ||
495 | 417 | self.assertEqual(rendered_template, "".join(result) + "\n") | ||
496 | 418 | |||
497 | 419 | |||
498 | 420 | class OfflineGenerationComplexTestCase(OfflineTestCaseMixin, TestCase): | ||
499 | 421 | templates_dir = "test_complex" | ||
500 | 422 | |||
501 | 423 | def setUp(self): | ||
502 | 424 | self.old_offline_context = settings.COMPRESS_OFFLINE_CONTEXT | ||
503 | 425 | settings.COMPRESS_OFFLINE_CONTEXT = { | ||
504 | 426 | 'condition': 'OK!', | ||
505 | 427 | # Django templating does not allow definition of tuples in the | ||
506 | 428 | # templates. Make sure this is same as test_templates_jinja2/test_complex. | ||
507 | 429 | 'my_names': ("js/one.js", "js/nonasc.js"), | ||
508 | 430 | } | ||
509 | 431 | super(OfflineGenerationComplexTestCase, self).setUp() | ||
510 | 432 | |||
511 | 433 | def tearDown(self): | ||
512 | 434 | self.COMPRESS_OFFLINE_CONTEXT = self.old_offline_context | ||
513 | 435 | super(OfflineGenerationComplexTestCase, self).tearDown() | ||
514 | 436 | |||
515 | 437 | def _test_offline(self, engine): | ||
516 | 438 | count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine) | ||
517 | 439 | self.assertEqual(3, count) | ||
518 | 440 | self.assertEqual([ | ||
519 | 441 | '<script type="text/javascript" src="/static/CACHE/js/0e8807bebcee.js"></script>', | ||
520 | 442 | '<script type="text/javascript" src="/static/CACHE/js/eed1d222933e.js"></script>', | ||
521 | 443 | '<script type="text/javascript" src="/static/CACHE/js/00b4baffe335.js"></script>', | ||
522 | 444 | ], result) | ||
523 | 445 | rendered_template = self._render_template(engine) | ||
524 | 446 | result = (result[0], result[2]) | ||
525 | 447 | self.assertEqual(rendered_template, "".join(result) + "\n") | ||
526 | 448 | |||
527 | 449 | |||
528 | 450 | # Coffin does not work on Python 3.2+ due to: | ||
529 | 451 | # The line at coffin/template/__init__.py:15 | ||
530 | 452 | # from library import * | ||
531 | 453 | # causing 'ImportError: No module named library'. | ||
532 | 454 | # It seems there is no evidence nor indicated support for Python 3+. | ||
533 | 455 | @unittest.skipIf(sys.version_info >= (3, 2), | ||
534 | 456 | "Coffin does not support 3.2+") | ||
535 | 457 | class OfflineGenerationCoffinTestCase(OfflineTestCaseMixin, TestCase): | ||
536 | 458 | templates_dir = "test_coffin" | ||
537 | 459 | expected_hash = "32c8281e3346" | ||
538 | 460 | engines = ("jinja2",) | ||
539 | 461 | |||
540 | 462 | def _get_jinja2_env(self): | ||
541 | 463 | import jinja2 | ||
542 | 464 | from coffin.common import env | ||
543 | 465 | from compressor.contrib.jinja2ext import CompressorExtension | ||
544 | 466 | |||
545 | 467 | # Could have used the env.add_extension method, but it's only available | ||
546 | 468 | # in Jinja2 v2.5 | ||
547 | 469 | new_env = jinja2.Environment(extensions=[CompressorExtension]) | ||
548 | 470 | env.extensions.update(new_env.extensions) | ||
549 | 471 | |||
550 | 472 | return env | ||
551 | 473 | |||
552 | 474 | |||
553 | 475 | # Jingo does not work when using Python 3.2 due to the use of Unicode string | ||
554 | 476 | # prefix (and possibly other stuff), but it actually works when using Python 3.3 | ||
555 | 477 | # since it tolerates the use of the Unicode string prefix. Python 3.3 support | ||
556 | 478 | # is also evident in its tox.ini file. | ||
557 | 479 | @unittest.skipIf(sys.version_info >= (3, 2) and sys.version_info < (3, 3), | ||
558 | 480 | "Jingo does not support 3.2") | ||
559 | 481 | class OfflineGenerationJingoTestCase(OfflineTestCaseMixin, TestCase): | ||
560 | 482 | templates_dir = "test_jingo" | ||
561 | 483 | expected_hash = "61ec584468eb" | ||
562 | 484 | engines = ("jinja2",) | ||
563 | 485 | |||
564 | 486 | def _get_jinja2_env(self): | ||
565 | 487 | import jinja2 | ||
566 | 488 | import jinja2.ext | ||
567 | 489 | from jingo import env | ||
568 | 490 | from compressor.contrib.jinja2ext import CompressorExtension | ||
569 | 491 | from compressor.offline.jinja2 import SpacelessExtension, url_for | ||
570 | 492 | |||
571 | 493 | # Could have used the env.add_extension method, but it's only available | ||
572 | 494 | # in Jinja2 v2.5 | ||
573 | 495 | new_env = jinja2.Environment(extensions=[CompressorExtension, SpacelessExtension, jinja2.ext.with_]) | ||
574 | 496 | env.extensions.update(new_env.extensions) | ||
575 | 497 | env.globals['url_for'] = url_for | ||
576 | 498 | |||
577 | 499 | return env | ||
578 | 500 | 0 | ||
579 | === removed directory '.pc/fix-test_settings.py-for-django-1.7.patch' | |||
580 | === removed directory '.pc/fix-test_settings.py-for-django-1.7.patch/compressor' | |||
581 | === removed file '.pc/fix-test_settings.py-for-django-1.7.patch/compressor/test_settings.py' | |||
582 | --- .pc/fix-test_settings.py-for-django-1.7.patch/compressor/test_settings.py 2014-09-08 17:31:54 +0000 | |||
583 | +++ .pc/fix-test_settings.py-for-django-1.7.patch/compressor/test_settings.py 1970-01-01 00:00:00 +0000 | |||
584 | @@ -1,40 +0,0 @@ | |||
585 | 1 | import os | ||
586 | 2 | import django | ||
587 | 3 | |||
588 | 4 | TEST_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'tests') | ||
589 | 5 | |||
590 | 6 | COMPRESS_CACHE_BACKEND = 'locmem://' | ||
591 | 7 | |||
592 | 8 | DATABASES = { | ||
593 | 9 | 'default': { | ||
594 | 10 | 'ENGINE': 'django.db.backends.sqlite3', | ||
595 | 11 | 'NAME': ':memory:', | ||
596 | 12 | } | ||
597 | 13 | } | ||
598 | 14 | |||
599 | 15 | INSTALLED_APPS = [ | ||
600 | 16 | 'compressor', | ||
601 | 17 | 'coffin', | ||
602 | 18 | 'jingo', | ||
603 | 19 | ] | ||
604 | 20 | |||
605 | 21 | STATIC_URL = '/static/' | ||
606 | 22 | |||
607 | 23 | |||
608 | 24 | STATIC_ROOT = os.path.join(TEST_DIR, 'static') | ||
609 | 25 | |||
610 | 26 | TEMPLATE_DIRS = ( | ||
611 | 27 | # Specifically choose a name that will not be considered | ||
612 | 28 | # by app_directories loader, to make sure each test uses | ||
613 | 29 | # a specific template without considering the others. | ||
614 | 30 | os.path.join(TEST_DIR, 'test_templates'), | ||
615 | 31 | ) | ||
616 | 32 | |||
617 | 33 | if django.VERSION[:2] < (1, 6): | ||
618 | 34 | TEST_RUNNER = 'discover_runner.DiscoverRunner' | ||
619 | 35 | |||
620 | 36 | SECRET_KEY = "iufoj=mibkpdz*%bob952x(%49rqgv8gg45k36kjcg76&-y5=!" | ||
621 | 37 | |||
622 | 38 | PASSWORD_HASHERS = ( | ||
623 | 39 | 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', | ||
624 | 40 | ) | ||
625 | 41 | 0 | ||
626 | === modified file '.travis.yml' | |||
627 | --- .travis.yml 2014-06-26 15:08:13 +0000 | |||
628 | +++ .travis.yml 2015-08-20 18:49:21 +0000 | |||
629 | @@ -3,20 +3,25 @@ | |||
630 | 3 | - sudo apt-get update | 3 | - sudo apt-get update |
631 | 4 | - sudo apt-get install csstidy libxml2-dev libxslt-dev | 4 | - sudo apt-get install csstidy libxml2-dev libxslt-dev |
632 | 5 | install: | 5 | install: |
634 | 6 | - pip install tox coveralls | 6 | - pip install tox |
635 | 7 | script: | 7 | script: |
636 | 8 | - tox | 8 | - tox |
637 | 9 | env: | 9 | env: |
645 | 10 | - TOXENV=py33-1.6.X | 10 | - TOXENV=py26-1.4.X |
639 | 11 | - TOXENV=py32-1.6.X | ||
640 | 12 | - TOXENV=py27-1.6.X | ||
641 | 13 | - TOXENV=py26-1.6.X | ||
642 | 14 | - TOXENV=py33-1.5.X | ||
643 | 15 | - TOXENV=py32-1.5.X | ||
644 | 16 | - TOXENV=py27-1.5.X | ||
646 | 17 | - TOXENV=py26-1.5.X | 11 | - TOXENV=py26-1.5.X |
647 | 18 | - TOXENV=py27-1.4.X | 12 | - TOXENV=py27-1.4.X |
649 | 19 | - TOXENV=py26-1.4.X | 13 | - TOXENV=py27-1.5.X |
650 | 14 | - TOXENV=py26-1.6.X | ||
651 | 15 | - TOXENV=py27-1.6.X | ||
652 | 16 | - TOXENV=py32-1.6.X | ||
653 | 17 | - TOXENV=py33-1.6.X | ||
654 | 18 | - TOXENV=py27-1.7.X | ||
655 | 19 | - TOXENV=py32-1.7.X | ||
656 | 20 | - TOXENV=py33-1.7.X | ||
657 | 21 | - TOXENV=py34-1.7.X | ||
658 | 22 | - TOXENV=py27-1.8.X | ||
659 | 23 | - TOXENV=py32-1.8.X | ||
660 | 24 | - TOXENV=py33-1.8.X | ||
661 | 25 | - TOXENV=py34-1.8.X | ||
662 | 20 | notifications: | 26 | notifications: |
663 | 21 | irc: "irc.freenode.org#django-compressor" | 27 | irc: "irc.freenode.org#django-compressor" |
664 | 22 | after_success: coveralls | ||
665 | 23 | 28 | ||
666 | === modified file 'AUTHORS' | |||
667 | --- AUTHORS 2015-01-06 14:31:34 +0000 | |||
668 | +++ AUTHORS 2015-08-20 18:49:21 +0000 | |||
669 | @@ -29,6 +29,7 @@ | |||
670 | 29 | Boris Shemigon | 29 | Boris Shemigon |
671 | 30 | Brad Whittington | 30 | Brad Whittington |
672 | 31 | Bruno Renié | 31 | Bruno Renié |
673 | 32 | Carlton Gibson | ||
674 | 32 | Cassus Adam Banko | 33 | Cassus Adam Banko |
675 | 33 | Chris Adams | 34 | Chris Adams |
676 | 34 | Chris Streeter | 35 | Chris Streeter |
677 | 35 | 36 | ||
678 | === modified file 'README.rst' | |||
679 | --- README.rst 2015-01-06 14:31:34 +0000 | |||
680 | +++ README.rst 2015-08-20 18:49:21 +0000 | |||
681 | @@ -4,16 +4,19 @@ | |||
682 | 4 | .. image:: https://coveralls.io/repos/django-compressor/django-compressor/badge.png?branch=develop | 4 | .. image:: https://coveralls.io/repos/django-compressor/django-compressor/badge.png?branch=develop |
683 | 5 | :target: https://coveralls.io/r/django-compressor/django-compressor?branch=develop | 5 | :target: https://coveralls.io/r/django-compressor/django-compressor?branch=develop |
684 | 6 | 6 | ||
692 | 7 | .. image:: https://pypip.in/v/django_compressor/badge.png | 7 | .. image:: https://pypip.in/v/django_compressor/badge.svg |
693 | 8 | :target: https://pypi.python.org/pypi/django_compressor | 8 | :target: https://pypi.python.org/pypi/django_compressor |
694 | 9 | 9 | ||
695 | 10 | .. image:: https://pypip.in/d/django_compressor/badge.png | 10 | .. image:: https://pypip.in/d/django_compressor/badge.svg |
696 | 11 | :target: https://pypi.python.org/pypi/django_compressor | 11 | :target: https://pypi.python.org/pypi/django_compressor |
697 | 12 | 12 | ||
698 | 13 | .. image:: https://secure.travis-ci.org/django-compressor/django-compressor.png?branch=develop | 13 | .. image:: https://secure.travis-ci.org/django-compressor/django-compressor.svg?branch=develop |
699 | 14 | :alt: Build Status | 14 | :alt: Build Status |
700 | 15 | :target: http://travis-ci.org/django-compressor/django-compressor | 15 | :target: http://travis-ci.org/django-compressor/django-compressor |
701 | 16 | 16 | ||
702 | 17 | .. image:: https://caniusepython3.com/project/django_compressor.svg | ||
703 | 18 | :target: https://caniusepython3.com/project/django_compressor | ||
704 | 19 | |||
705 | 17 | Django Compressor combines and compresses linked and inline Javascript | 20 | Django Compressor combines and compresses linked and inline Javascript |
706 | 18 | or CSS in a Django template into cacheable static files by using the | 21 | or CSS in a Django template into cacheable static files by using the |
707 | 19 | ``compress`` template tag. | 22 | ``compress`` template tag. |
708 | 20 | 23 | ||
709 | === modified file 'compressor/__init__.py' | |||
710 | --- compressor/__init__.py 2015-01-06 14:31:34 +0000 | |||
711 | +++ compressor/__init__.py 2015-08-20 18:49:21 +0000 | |||
712 | @@ -1,2 +1,2 @@ | |||
713 | 1 | # following PEP 386 | 1 | # following PEP 386 |
715 | 2 | __version__ = "1.4a1" | 2 | __version__ = "1.5" |
716 | 3 | 3 | ||
717 | === modified file 'compressor/base.py' | |||
718 | --- compressor/base.py 2015-01-06 14:31:34 +0000 | |||
719 | +++ compressor/base.py 2015-08-20 18:49:21 +0000 | |||
720 | @@ -5,7 +5,10 @@ | |||
721 | 5 | from django.core.files.base import ContentFile | 5 | from django.core.files.base import ContentFile |
722 | 6 | from django.template import Context | 6 | from django.template import Context |
723 | 7 | from django.template.loader import render_to_string | 7 | from django.template.loader import render_to_string |
725 | 8 | from django.utils.importlib import import_module | 8 | try: |
726 | 9 | from importlib import import_module | ||
727 | 10 | except: | ||
728 | 11 | from django.utils.importlib import import_module | ||
729 | 9 | from django.utils.safestring import mark_safe | 12 | from django.utils.safestring import mark_safe |
730 | 10 | 13 | ||
731 | 11 | try: | 14 | try: |
732 | @@ -140,6 +143,9 @@ | |||
733 | 140 | """ | 143 | """ |
734 | 141 | Reads file contents using given `charset` and returns it as text. | 144 | Reads file contents using given `charset` and returns it as text. |
735 | 142 | """ | 145 | """ |
736 | 146 | if charset == 'utf-8': | ||
737 | 147 | # Removes BOM | ||
738 | 148 | charset = 'utf-8-sig' | ||
739 | 143 | with codecs.open(filename, 'r', charset) as fd: | 149 | with codecs.open(filename, 'r', charset) as fd: |
740 | 144 | try: | 150 | try: |
741 | 145 | return fd.read() | 151 | return fd.read() |
742 | @@ -247,7 +253,7 @@ | |||
743 | 247 | mod_name, cls_name = get_mod_func(filter_or_command) | 253 | mod_name, cls_name = get_mod_func(filter_or_command) |
744 | 248 | try: | 254 | try: |
745 | 249 | mod = import_module(mod_name) | 255 | mod = import_module(mod_name) |
747 | 250 | except ImportError: | 256 | except (ImportError, TypeError): |
748 | 251 | filter = CompilerFilter( | 257 | filter = CompilerFilter( |
749 | 252 | content, filter_type=self.type, filename=filename, | 258 | content, filter_type=self.type, filename=filename, |
750 | 253 | charset=charset, command=filter_or_command) | 259 | charset=charset, command=filter_or_command) |
751 | 254 | 260 | ||
752 | === modified file 'compressor/cache.py' | |||
753 | --- compressor/cache.py 2015-01-06 14:31:34 +0000 | |||
754 | +++ compressor/cache.py 2015-08-20 18:49:21 +0000 | |||
755 | @@ -4,11 +4,21 @@ | |||
756 | 4 | import socket | 4 | import socket |
757 | 5 | import time | 5 | import time |
758 | 6 | 6 | ||
760 | 7 | from django.core.cache import get_cache | 7 | try: |
761 | 8 | from django.core.cache import caches | ||
762 | 9 | def get_cache(name): | ||
763 | 10 | return caches[name] | ||
764 | 11 | except ImportError: | ||
765 | 12 | from django.core.cache import get_cache | ||
766 | 13 | |||
767 | 8 | from django.core.files.base import ContentFile | 14 | from django.core.files.base import ContentFile |
768 | 9 | from django.utils.encoding import force_text, smart_bytes | 15 | from django.utils.encoding import force_text, smart_bytes |
769 | 10 | from django.utils.functional import SimpleLazyObject | 16 | from django.utils.functional import SimpleLazyObject |
771 | 11 | from django.utils.importlib import import_module | 17 | |
772 | 18 | try: | ||
773 | 19 | from importlib import import_module | ||
774 | 20 | except: | ||
775 | 21 | from django.utils.importlib import import_module | ||
776 | 12 | 22 | ||
777 | 13 | from compressor.conf import settings | 23 | from compressor.conf import settings |
778 | 14 | from compressor.storage import default_storage | 24 | from compressor.storage import default_storage |
779 | @@ -39,7 +49,7 @@ | |||
780 | 39 | mod_name, func_name = get_mod_func( | 49 | mod_name, func_name = get_mod_func( |
781 | 40 | settings.COMPRESS_CACHE_KEY_FUNCTION) | 50 | settings.COMPRESS_CACHE_KEY_FUNCTION) |
782 | 41 | _cachekey_func = getattr(import_module(mod_name), func_name) | 51 | _cachekey_func = getattr(import_module(mod_name), func_name) |
784 | 42 | except (AttributeError, ImportError) as e: | 52 | except (AttributeError, ImportError, TypeError) as e: |
785 | 43 | raise ImportError("Couldn't import cache key function %s: %s" % | 53 | raise ImportError("Couldn't import cache key function %s: %s" % |
786 | 44 | (settings.COMPRESS_CACHE_KEY_FUNCTION, e)) | 54 | (settings.COMPRESS_CACHE_KEY_FUNCTION, e)) |
787 | 45 | return _cachekey_func(*args, **kwargs) | 55 | return _cachekey_func(*args, **kwargs) |
788 | 46 | 56 | ||
789 | === modified file 'compressor/conf.py' | |||
790 | --- compressor/conf.py 2015-01-06 14:31:34 +0000 | |||
791 | +++ compressor/conf.py 2015-08-20 18:49:21 +0000 | |||
792 | @@ -45,6 +45,8 @@ | |||
793 | 45 | YUGLIFY_BINARY = 'yuglify' | 45 | YUGLIFY_BINARY = 'yuglify' |
794 | 46 | YUGLIFY_CSS_ARGUMENTS = '--terminal' | 46 | YUGLIFY_CSS_ARGUMENTS = '--terminal' |
795 | 47 | YUGLIFY_JS_ARGUMENTS = '--terminal' | 47 | YUGLIFY_JS_ARGUMENTS = '--terminal' |
796 | 48 | CLEAN_CSS_BINARY = 'cleancss' | ||
797 | 49 | CLEAN_CSS_ARGUMENTS = '' | ||
798 | 48 | DATA_URI_MAX_SIZE = 1024 | 50 | DATA_URI_MAX_SIZE = 1024 |
799 | 49 | 51 | ||
800 | 50 | # the cache backend to use | 52 | # the cache backend to use |
801 | 51 | 53 | ||
802 | === modified file 'compressor/css.py' | |||
803 | --- compressor/css.py 2014-06-26 15:08:13 +0000 | |||
804 | +++ compressor/css.py 2015-08-20 18:49:21 +0000 | |||
805 | @@ -34,7 +34,7 @@ | |||
806 | 34 | self.media_nodes[-1][1].split_content.append(data) | 34 | self.media_nodes[-1][1].split_content.append(data) |
807 | 35 | else: | 35 | else: |
808 | 36 | node = self.__class__(content=self.parser.elem_str(elem), | 36 | node = self.__class__(content=self.parser.elem_str(elem), |
810 | 37 | context=self.context) | 37 | context=self.context) |
811 | 38 | node.split_content.append(data) | 38 | node.split_content.append(data) |
812 | 39 | self.media_nodes.append((media, node)) | 39 | self.media_nodes.append((media, node)) |
813 | 40 | return self.split_content | 40 | return self.split_content |
814 | 41 | 41 | ||
815 | === modified file 'compressor/filters/base.py' | |||
816 | --- compressor/filters/base.py 2015-01-06 14:31:34 +0000 | |||
817 | +++ compressor/filters/base.py 2015-08-20 18:49:21 +0000 | |||
818 | @@ -3,9 +3,27 @@ | |||
819 | 3 | import logging | 3 | import logging |
820 | 4 | import subprocess | 4 | import subprocess |
821 | 5 | 5 | ||
822 | 6 | from platform import system | ||
823 | 7 | |||
824 | 8 | if system() != "Windows": | ||
825 | 9 | try: | ||
826 | 10 | from shlex import quote as shell_quote # Python 3 | ||
827 | 11 | except ImportError: | ||
828 | 12 | from pipes import quote as shell_quote # Python 2 | ||
829 | 13 | else: | ||
830 | 14 | from subprocess import list2cmdline | ||
831 | 15 | def shell_quote(s): | ||
832 | 16 | # shlex.quote/pipes.quote is not compatible with Windows | ||
833 | 17 | return list2cmdline([s]) | ||
834 | 18 | |||
835 | 6 | from django.core.exceptions import ImproperlyConfigured | 19 | from django.core.exceptions import ImproperlyConfigured |
836 | 7 | from django.core.files.temp import NamedTemporaryFile | 20 | from django.core.files.temp import NamedTemporaryFile |
838 | 8 | from django.utils.importlib import import_module | 21 | |
839 | 22 | try: | ||
840 | 23 | from importlib import import_module | ||
841 | 24 | except ImportError: | ||
842 | 25 | from django.utils.importlib import import_module | ||
843 | 26 | |||
844 | 9 | from django.utils.encoding import smart_text | 27 | from django.utils.encoding import smart_text |
845 | 10 | from django.utils import six | 28 | from django.utils import six |
846 | 11 | 29 | ||
847 | @@ -26,7 +44,7 @@ | |||
848 | 26 | """ | 44 | """ |
849 | 27 | def __init__(self, content, filter_type=None, filename=None, verbose=0, | 45 | def __init__(self, content, filter_type=None, filename=None, verbose=0, |
850 | 28 | charset=None): | 46 | charset=None): |
852 | 29 | self.type = filter_type | 47 | self.type = filter_type or getattr(self, 'type', None) |
853 | 30 | self.content = content | 48 | self.content = content |
854 | 31 | self.verbose = verbose or settings.COMPRESS_VERBOSE | 49 | self.verbose = verbose or settings.COMPRESS_VERBOSE |
855 | 32 | self.logger = logger | 50 | self.logger = logger |
856 | @@ -65,7 +83,7 @@ | |||
857 | 65 | try: | 83 | try: |
858 | 66 | mod_name, func_name = get_mod_func(self.callback) | 84 | mod_name, func_name = get_mod_func(self.callback) |
859 | 67 | func = getattr(import_module(mod_name), func_name) | 85 | func = getattr(import_module(mod_name), func_name) |
861 | 68 | except ImportError: | 86 | except (ImportError, TypeError): |
862 | 69 | if self.dependencies: | 87 | if self.dependencies: |
863 | 70 | if len(self.dependencies) == 1: | 88 | if len(self.dependencies) == 1: |
864 | 71 | warning = "dependency (%s) is" % self.dependencies[0] | 89 | warning = "dependency (%s) is" % self.dependencies[0] |
865 | @@ -147,6 +165,12 @@ | |||
866 | 147 | self.outfile = NamedTemporaryFile(mode='r+', suffix=ext) | 165 | self.outfile = NamedTemporaryFile(mode='r+', suffix=ext) |
867 | 148 | options["outfile"] = self.outfile.name | 166 | options["outfile"] = self.outfile.name |
868 | 149 | 167 | ||
869 | 168 | # Quote infile and outfile for spaces etc. | ||
870 | 169 | if "infile" in options: | ||
871 | 170 | options["infile"] = shell_quote(options["infile"]) | ||
872 | 171 | if "outfile" in options: | ||
873 | 172 | options["outfile"] = shell_quote(options["outfile"]) | ||
874 | 173 | |||
875 | 150 | try: | 174 | try: |
876 | 151 | command = self.command.format(**options) | 175 | command = self.command.format(**options) |
877 | 152 | proc = subprocess.Popen( | 176 | proc = subprocess.Popen( |
878 | 153 | 177 | ||
879 | === added file 'compressor/filters/cleancss.py' | |||
880 | --- compressor/filters/cleancss.py 1970-01-01 00:00:00 +0000 | |||
881 | +++ compressor/filters/cleancss.py 2015-08-20 18:49:21 +0000 | |||
882 | @@ -0,0 +1,10 @@ | |||
883 | 1 | from compressor.conf import settings | ||
884 | 2 | from compressor.filters import CompilerFilter | ||
885 | 3 | |||
886 | 4 | |||
887 | 5 | class CleanCSSFilter(CompilerFilter): | ||
888 | 6 | command = "{binary} {args} -o {outfile} {infile}" | ||
889 | 7 | options = ( | ||
890 | 8 | ("binary", settings.COMPRESS_CLEAN_CSS_BINARY), | ||
891 | 9 | ("args", settings.COMPRESS_CLEAN_CSS_ARGUMENTS), | ||
892 | 10 | ) | ||
893 | 0 | 11 | ||
894 | === modified file 'compressor/filters/css_default.py' | |||
895 | --- compressor/filters/css_default.py 2015-01-06 14:31:34 +0000 | |||
896 | +++ compressor/filters/css_default.py 2015-08-20 18:49:21 +0000 | |||
897 | @@ -5,7 +5,6 @@ | |||
898 | 5 | from compressor.cache import get_hashed_mtime, get_hashed_content | 5 | from compressor.cache import get_hashed_mtime, get_hashed_content |
899 | 6 | from compressor.conf import settings | 6 | from compressor.conf import settings |
900 | 7 | from compressor.filters import FilterBase, FilterError | 7 | from compressor.filters import FilterBase, FilterError |
901 | 8 | from compressor.utils import staticfiles | ||
902 | 9 | 8 | ||
903 | 10 | URL_PATTERN = re.compile(r'url\(([^\)]+)\)') | 9 | URL_PATTERN = re.compile(r'url\(([^\)]+)\)') |
904 | 11 | SRC_PATTERN = re.compile(r'src=([\'"])(.+?)\1') | 10 | SRC_PATTERN = re.compile(r'src=([\'"])(.+?)\1') |
905 | @@ -22,10 +21,7 @@ | |||
906 | 22 | self.has_scheme = False | 21 | self.has_scheme = False |
907 | 23 | 22 | ||
908 | 24 | def input(self, filename=None, basename=None, **kwargs): | 23 | def input(self, filename=None, basename=None, **kwargs): |
913 | 25 | if filename is not None: | 24 | if not filename: |
910 | 26 | filename = os.path.normcase(os.path.abspath(filename)) | ||
911 | 27 | if (not (filename and filename.startswith(self.root)) and | ||
912 | 28 | not self.find(basename)): | ||
914 | 29 | return self.content | 25 | return self.content |
915 | 30 | self.path = basename.replace(os.sep, '/') | 26 | self.path = basename.replace(os.sep, '/') |
916 | 31 | self.path = self.path.lstrip('/') | 27 | self.path = self.path.lstrip('/') |
917 | @@ -40,10 +36,6 @@ | |||
918 | 40 | return SRC_PATTERN.sub(self.src_converter, | 36 | return SRC_PATTERN.sub(self.src_converter, |
919 | 41 | URL_PATTERN.sub(self.url_converter, self.content)) | 37 | URL_PATTERN.sub(self.url_converter, self.content)) |
920 | 42 | 38 | ||
921 | 43 | def find(self, basename): | ||
922 | 44 | if settings.DEBUG and basename and staticfiles.finders: | ||
923 | 45 | return staticfiles.finders.find(basename) | ||
924 | 46 | |||
925 | 47 | def guess_filename(self, url): | 39 | def guess_filename(self, url): |
926 | 48 | local_path = url | 40 | local_path = url |
927 | 49 | if self.has_scheme: | 41 | if self.has_scheme: |
928 | @@ -70,6 +62,8 @@ | |||
929 | 70 | suffix = get_hashed_mtime(filename) | 62 | suffix = get_hashed_mtime(filename) |
930 | 71 | elif settings.COMPRESS_CSS_HASHING_METHOD in ("hash", "content"): | 63 | elif settings.COMPRESS_CSS_HASHING_METHOD in ("hash", "content"): |
931 | 72 | suffix = get_hashed_content(filename) | 64 | suffix = get_hashed_content(filename) |
932 | 65 | elif settings.COMPRESS_CSS_HASHING_METHOD is None: | ||
933 | 66 | suffix = None | ||
934 | 73 | else: | 67 | else: |
935 | 74 | raise FilterError('COMPRESS_CSS_HASHING_METHOD is configured ' | 68 | raise FilterError('COMPRESS_CSS_HASHING_METHOD is configured ' |
936 | 75 | 'with an unknown method (%s).' % | 69 | 'with an unknown method (%s).' % |
937 | 76 | 70 | ||
938 | === modified file 'compressor/js.py' | |||
939 | --- compressor/js.py 2012-10-14 10:51:47 +0000 | |||
940 | +++ compressor/js.py 2015-08-20 18:49:21 +0000 | |||
941 | @@ -12,14 +12,42 @@ | |||
942 | 12 | def split_contents(self): | 12 | def split_contents(self): |
943 | 13 | if self.split_content: | 13 | if self.split_content: |
944 | 14 | return self.split_content | 14 | return self.split_content |
945 | 15 | self.extra_nodes = [] | ||
946 | 15 | for elem in self.parser.js_elems(): | 16 | for elem in self.parser.js_elems(): |
947 | 16 | attribs = self.parser.elem_attribs(elem) | 17 | attribs = self.parser.elem_attribs(elem) |
948 | 17 | if 'src' in attribs: | 18 | if 'src' in attribs: |
949 | 18 | basename = self.get_basename(attribs['src']) | 19 | basename = self.get_basename(attribs['src']) |
950 | 19 | filename = self.get_filename(basename) | 20 | filename = self.get_filename(basename) |
951 | 20 | content = (SOURCE_FILE, filename, basename, elem) | 21 | content = (SOURCE_FILE, filename, basename, elem) |
956 | 21 | self.split_content.append(content) | 22 | else: |
957 | 22 | else: | 23 | content = (SOURCE_HUNK, self.parser.elem_content(elem), None, elem) |
958 | 23 | content = self.parser.elem_content(elem) | 24 | self.split_content.append(content) |
959 | 24 | self.split_content.append((SOURCE_HUNK, content, None, elem)) | 25 | if 'async' in attribs: |
960 | 26 | extra = ' async' | ||
961 | 27 | elif 'defer' in attribs: | ||
962 | 28 | extra = ' defer' | ||
963 | 29 | else: | ||
964 | 30 | extra = '' | ||
965 | 31 | # Append to the previous node if it had the same attribute | ||
966 | 32 | append_to_previous = (self.extra_nodes and | ||
967 | 33 | self.extra_nodes[-1][0] == extra) | ||
968 | 34 | if append_to_previous and settings.COMPRESS_ENABLED: | ||
969 | 35 | self.extra_nodes[-1][1].split_content.append(content) | ||
970 | 36 | else: | ||
971 | 37 | node = self.__class__(content=self.parser.elem_str(elem), | ||
972 | 38 | context=self.context) | ||
973 | 39 | node.split_content.append(content) | ||
974 | 40 | self.extra_nodes.append((extra, node)) | ||
975 | 25 | return self.split_content | 41 | return self.split_content |
976 | 42 | |||
977 | 43 | def output(self, *args, **kwargs): | ||
978 | 44 | if (settings.COMPRESS_ENABLED or settings.COMPRESS_PRECOMPILERS or | ||
979 | 45 | kwargs.get('forced', False)): | ||
980 | 46 | self.split_contents() | ||
981 | 47 | if hasattr(self, 'extra_nodes'): | ||
982 | 48 | ret = [] | ||
983 | 49 | for extra, subnode in self.extra_nodes: | ||
984 | 50 | subnode.extra_context.update({'extra': extra}) | ||
985 | 51 | ret.append(subnode.output(*args, **kwargs)) | ||
986 | 52 | return '\n'.join(ret) | ||
987 | 53 | return super(JsCompressor, self).output(*args, **kwargs) | ||
988 | 26 | 54 | ||
989 | === modified file 'compressor/management/commands/compress.py' | |||
990 | --- compressor/management/commands/compress.py 2015-01-06 14:31:34 +0000 | |||
991 | +++ compressor/management/commands/compress.py 2015-08-20 18:49:21 +0000 | |||
992 | @@ -5,6 +5,7 @@ | |||
993 | 5 | from fnmatch import fnmatch | 5 | from fnmatch import fnmatch |
994 | 6 | from optparse import make_option | 6 | from optparse import make_option |
995 | 7 | 7 | ||
996 | 8 | import django | ||
997 | 8 | from django.core.management.base import NoArgsCommand, CommandError | 9 | from django.core.management.base import NoArgsCommand, CommandError |
998 | 9 | import django.template | 10 | import django.template |
999 | 10 | from django.template import Context | 11 | from django.template import Context |
1000 | @@ -53,24 +54,30 @@ | |||
1001 | 53 | requires_model_validation = False | 54 | requires_model_validation = False |
1002 | 54 | 55 | ||
1003 | 55 | def get_loaders(self): | 56 | def get_loaders(self): |
1021 | 56 | from django.template.loader import template_source_loaders | 57 | if django.VERSION < (1, 8): |
1005 | 57 | if template_source_loaders is None: | ||
1006 | 58 | try: | ||
1007 | 59 | from django.template.loader import ( | ||
1008 | 60 | find_template as finder_func) | ||
1009 | 61 | except ImportError: | ||
1010 | 62 | from django.template.loader import ( | ||
1011 | 63 | find_template_source as finder_func) # noqa | ||
1012 | 64 | try: | ||
1013 | 65 | # Force django to calculate template_source_loaders from | ||
1014 | 66 | # TEMPLATE_LOADERS settings, by asking to find a dummy template | ||
1015 | 67 | source, name = finder_func('test') | ||
1016 | 68 | except django.template.TemplateDoesNotExist: | ||
1017 | 69 | pass | ||
1018 | 70 | # Reload template_source_loaders now that it has been calculated ; | ||
1019 | 71 | # it should contain the list of valid, instanciated template loaders | ||
1020 | 72 | # to use. | ||
1022 | 73 | from django.template.loader import template_source_loaders | 58 | from django.template.loader import template_source_loaders |
1023 | 59 | if template_source_loaders is None: | ||
1024 | 60 | try: | ||
1025 | 61 | from django.template.loader import ( | ||
1026 | 62 | find_template as finder_func) | ||
1027 | 63 | except ImportError: | ||
1028 | 64 | from django.template.loader import ( | ||
1029 | 65 | find_template_source as finder_func) # noqa | ||
1030 | 66 | try: | ||
1031 | 67 | # Force django to calculate template_source_loaders from | ||
1032 | 68 | # TEMPLATE_LOADERS settings, by asking to find a dummy template | ||
1033 | 69 | source, name = finder_func('test') | ||
1034 | 70 | except django.template.TemplateDoesNotExist: | ||
1035 | 71 | pass | ||
1036 | 72 | # Reload template_source_loaders now that it has been calculated ; | ||
1037 | 73 | # it should contain the list of valid, instanciated template loaders | ||
1038 | 74 | # to use. | ||
1039 | 75 | from django.template.loader import template_source_loaders | ||
1040 | 76 | else: | ||
1041 | 77 | from django.template import engines | ||
1042 | 78 | template_source_loaders = [] | ||
1043 | 79 | for e in engines.all(): | ||
1044 | 80 | template_source_loaders.extend(e.engine.get_template_loaders(e.engine.loaders)) | ||
1045 | 74 | loaders = [] | 81 | loaders = [] |
1046 | 75 | # If template loader is CachedTemplateLoader, return the loaders | 82 | # If template loader is CachedTemplateLoader, return the loaders |
1047 | 76 | # that it wraps around. So if we have | 83 | # that it wraps around. So if we have |
1048 | @@ -130,7 +137,7 @@ | |||
1049 | 130 | if get_template_sources is None: | 137 | if get_template_sources is None: |
1050 | 131 | get_template_sources = loader.get_template_sources | 138 | get_template_sources = loader.get_template_sources |
1051 | 132 | paths.update(list(get_template_sources(''))) | 139 | paths.update(list(get_template_sources(''))) |
1053 | 133 | except (ImportError, AttributeError): | 140 | except (ImportError, AttributeError, TypeError): |
1054 | 134 | # Yeah, this didn't work out so well, let's move on | 141 | # Yeah, this didn't work out so well, let's move on |
1055 | 135 | pass | 142 | pass |
1056 | 136 | if not paths: | 143 | if not paths: |
1057 | 137 | 144 | ||
1058 | === modified file 'compressor/offline/django.py' | |||
1059 | --- compressor/offline/django.py 2014-06-26 15:08:13 +0000 | |||
1060 | +++ compressor/offline/django.py 2015-08-20 18:49:21 +0000 | |||
1061 | @@ -1,13 +1,13 @@ | |||
1062 | 1 | from __future__ import absolute_import | 1 | from __future__ import absolute_import |
1063 | 2 | import io | ||
1064 | 3 | from copy import copy | 2 | from copy import copy |
1065 | 4 | 3 | ||
1066 | 4 | import django | ||
1067 | 5 | from django import template | 5 | from django import template |
1068 | 6 | from django.conf import settings | 6 | from django.conf import settings |
1069 | 7 | from django.template import Template | ||
1070 | 8 | from django.template import Context | 7 | from django.template import Context |
1071 | 9 | from django.template.base import Node, VariableNode, TextNode, NodeList | 8 | from django.template.base import Node, VariableNode, TextNode, NodeList |
1072 | 10 | from django.template.defaulttags import IfNode | 9 | from django.template.defaulttags import IfNode |
1073 | 10 | from django.template.loader import get_template | ||
1074 | 11 | from django.template.loader_tags import ExtendsNode, BlockNode, BlockContext | 11 | from django.template.loader_tags import ExtendsNode, BlockNode, BlockContext |
1075 | 12 | 12 | ||
1076 | 13 | 13 | ||
1077 | @@ -15,7 +15,7 @@ | |||
1078 | 15 | from compressor.templatetags.compress import CompressorNode | 15 | from compressor.templatetags.compress import CompressorNode |
1079 | 16 | 16 | ||
1080 | 17 | 17 | ||
1082 | 18 | def handle_extendsnode(extendsnode, block_context=None): | 18 | def handle_extendsnode(extendsnode, block_context=None, original=None): |
1083 | 19 | """Create a copy of Node tree of a derived template replacing | 19 | """Create a copy of Node tree of a derived template replacing |
1084 | 20 | all blocks tags with the nodes of appropriate blocks. | 20 | all blocks tags with the nodes of appropriate blocks. |
1085 | 21 | Also handles {{ block.super }} tags. | 21 | Also handles {{ block.super }} tags. |
1086 | @@ -27,6 +27,9 @@ | |||
1087 | 27 | block_context.add_blocks(blocks) | 27 | block_context.add_blocks(blocks) |
1088 | 28 | 28 | ||
1089 | 29 | context = Context(settings.COMPRESS_OFFLINE_CONTEXT) | 29 | context = Context(settings.COMPRESS_OFFLINE_CONTEXT) |
1090 | 30 | if original is not None: | ||
1091 | 31 | context.template = original | ||
1092 | 32 | |||
1093 | 30 | compiled_parent = extendsnode.get_parent(context) | 33 | compiled_parent = extendsnode.get_parent(context) |
1094 | 31 | parent_nodelist = compiled_parent.nodelist | 34 | parent_nodelist = compiled_parent.nodelist |
1095 | 32 | # If the parent template has an ExtendsNode it is not the root. | 35 | # If the parent template has an ExtendsNode it is not the root. |
1096 | @@ -34,7 +37,7 @@ | |||
1097 | 34 | # The ExtendsNode has to be the first non-text node. | 37 | # The ExtendsNode has to be the first non-text node. |
1098 | 35 | if not isinstance(node, TextNode): | 38 | if not isinstance(node, TextNode): |
1099 | 36 | if isinstance(node, ExtendsNode): | 39 | if isinstance(node, ExtendsNode): |
1101 | 37 | return handle_extendsnode(node, block_context) | 40 | return handle_extendsnode(node, block_context, original) |
1102 | 38 | break | 41 | break |
1103 | 39 | # Add blocks of the root template to block context. | 42 | # Add blocks of the root template to block context. |
1104 | 40 | blocks = dict((n.name, n) for n in | 43 | blocks = dict((n.name, n) for n in |
1105 | @@ -55,6 +58,8 @@ | |||
1106 | 55 | if not block_stack: | 58 | if not block_stack: |
1107 | 56 | continue | 59 | continue |
1108 | 57 | node = block_context.get_block(block_stack[-1].name) | 60 | node = block_context.get_block(block_stack[-1].name) |
1109 | 61 | if not node: | ||
1110 | 62 | continue | ||
1111 | 58 | if isinstance(node, BlockNode): | 63 | if isinstance(node, BlockNode): |
1112 | 59 | expanded_block = expand_blocknode(node, block_stack, block_context) | 64 | expanded_block = expand_blocknode(node, block_stack, block_context) |
1113 | 60 | new_nodelist.extend(expanded_block) | 65 | new_nodelist.extend(expanded_block) |
1114 | @@ -93,13 +98,15 @@ | |||
1115 | 93 | self.charset = charset | 98 | self.charset = charset |
1116 | 94 | 99 | ||
1117 | 95 | def parse(self, template_name): | 100 | def parse(self, template_name): |
1125 | 96 | with io.open(template_name, mode='rb') as file: | 101 | try: |
1126 | 97 | try: | 102 | if django.VERSION < (1, 8): |
1127 | 98 | return Template(file.read().decode(self.charset)) | 103 | return get_template(template_name) |
1128 | 99 | except template.TemplateSyntaxError as e: | 104 | else: |
1129 | 100 | raise TemplateSyntaxError(str(e)) | 105 | return get_template(template_name).template |
1130 | 101 | except template.TemplateDoesNotExist as e: | 106 | except template.TemplateSyntaxError as e: |
1131 | 102 | raise TemplateDoesNotExist(str(e)) | 107 | raise TemplateSyntaxError(str(e)) |
1132 | 108 | except template.TemplateDoesNotExist as e: | ||
1133 | 109 | raise TemplateDoesNotExist(str(e)) | ||
1134 | 103 | 110 | ||
1135 | 104 | def process_template(self, template, context): | 111 | def process_template(self, template, context): |
1136 | 105 | return True | 112 | return True |
1137 | @@ -111,15 +118,17 @@ | |||
1138 | 111 | pass | 118 | pass |
1139 | 112 | 119 | ||
1140 | 113 | def render_nodelist(self, template, context, node): | 120 | def render_nodelist(self, template, context, node): |
1141 | 121 | if django.VERSION >= (1, 8): | ||
1142 | 122 | context.template = template | ||
1143 | 114 | return node.nodelist.render(context) | 123 | return node.nodelist.render(context) |
1144 | 115 | 124 | ||
1145 | 116 | def render_node(self, template, context, node): | 125 | def render_node(self, template, context, node): |
1146 | 117 | return node.render(context, forced=True) | 126 | return node.render(context, forced=True) |
1147 | 118 | 127 | ||
1149 | 119 | def get_nodelist(self, node): | 128 | def get_nodelist(self, node, original=None): |
1150 | 120 | if isinstance(node, ExtendsNode): | 129 | if isinstance(node, ExtendsNode): |
1151 | 121 | try: | 130 | try: |
1153 | 122 | return handle_extendsnode(node) | 131 | return handle_extendsnode(node, block_context=None, original=original) |
1154 | 123 | except template.TemplateSyntaxError as e: | 132 | except template.TemplateSyntaxError as e: |
1155 | 124 | raise TemplateSyntaxError(str(e)) | 133 | raise TemplateSyntaxError(str(e)) |
1156 | 125 | except template.TemplateDoesNotExist as e: | 134 | except template.TemplateDoesNotExist as e: |
1157 | @@ -134,10 +143,12 @@ | |||
1158 | 134 | nodelist = getattr(node, 'nodelist', []) | 143 | nodelist = getattr(node, 'nodelist', []) |
1159 | 135 | return nodelist | 144 | return nodelist |
1160 | 136 | 145 | ||
1163 | 137 | def walk_nodes(self, node): | 146 | def walk_nodes(self, node, original=None): |
1164 | 138 | for node in self.get_nodelist(node): | 147 | if django.VERSION >= (1, 8) and original is None: |
1165 | 148 | original = node | ||
1166 | 149 | for node in self.get_nodelist(node, original): | ||
1167 | 139 | if isinstance(node, CompressorNode) and node.is_offline_compression_enabled(forced=True): | 150 | if isinstance(node, CompressorNode) and node.is_offline_compression_enabled(forced=True): |
1168 | 140 | yield node | 151 | yield node |
1169 | 141 | else: | 152 | else: |
1171 | 142 | for node in self.walk_nodes(node): | 153 | for node in self.walk_nodes(node, original): |
1172 | 143 | yield node | 154 | yield node |
1173 | 144 | 155 | ||
1174 | === modified file 'compressor/parser/__init__.py' | |||
1175 | --- compressor/parser/__init__.py 2014-06-26 15:08:13 +0000 | |||
1176 | +++ compressor/parser/__init__.py 2015-08-20 18:49:21 +0000 | |||
1177 | @@ -1,6 +1,9 @@ | |||
1178 | 1 | from django.utils import six | 1 | from django.utils import six |
1179 | 2 | from django.utils.functional import LazyObject | 2 | from django.utils.functional import LazyObject |
1181 | 3 | from django.utils.importlib import import_module | 3 | try: |
1182 | 4 | from importlib import import_module | ||
1183 | 5 | except ImportError: | ||
1184 | 6 | from django.utils.importlib import import_module | ||
1185 | 4 | 7 | ||
1186 | 5 | # support legacy parser module usage | 8 | # support legacy parser module usage |
1187 | 6 | from compressor.parser.base import ParserBase # noqa | 9 | from compressor.parser.base import ParserBase # noqa |
1188 | @@ -30,5 +33,5 @@ | |||
1189 | 30 | import_module(dependency) | 33 | import_module(dependency) |
1190 | 31 | self._wrapped = parser(content) | 34 | self._wrapped = parser(content) |
1191 | 32 | break | 35 | break |
1193 | 33 | except ImportError: | 36 | except (ImportError, TypeError): |
1194 | 34 | continue | 37 | continue |
1195 | 35 | 38 | ||
1196 | === modified file 'compressor/templates/compressor/js_file.html' | |||
1197 | --- compressor/templates/compressor/js_file.html 2012-10-14 10:51:47 +0000 | |||
1198 | +++ compressor/templates/compressor/js_file.html 2015-08-20 18:49:21 +0000 | |||
1199 | @@ -1,1 +1,1 @@ | |||
1200 | 1 | <script type="text/javascript" src="{{ compressed.url }}"></script> | ||
1201 | 2 | \ No newline at end of file | 1 | \ No newline at end of file |
1202 | 2 | <script type="text/javascript" src="{{ compressed.url }}"{{ compressed.extra }}></script> | ||
1203 | 3 | \ No newline at end of file | 3 | \ No newline at end of file |
1204 | 4 | 4 | ||
1205 | === modified file 'compressor/test_settings.py' | |||
1206 | --- compressor/test_settings.py 2015-01-06 14:31:34 +0000 | |||
1207 | +++ compressor/test_settings.py 2015-08-20 18:49:21 +0000 | |||
1208 | @@ -3,7 +3,13 @@ | |||
1209 | 3 | 3 | ||
1210 | 4 | TEST_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'tests') | 4 | TEST_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'tests') |
1211 | 5 | 5 | ||
1213 | 6 | COMPRESS_CACHE_BACKEND = 'django.core.cache.backends.locmem.CacheClass' | 6 | |
1214 | 7 | CACHES = { | ||
1215 | 8 | 'default': { | ||
1216 | 9 | 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', | ||
1217 | 10 | 'LOCATION': 'unique-snowflake' | ||
1218 | 11 | } | ||
1219 | 12 | } | ||
1220 | 7 | 13 | ||
1221 | 8 | DATABASES = { | 14 | DATABASES = { |
1222 | 9 | 'default': { | 15 | 'default': { |
1223 | @@ -13,8 +19,17 @@ | |||
1224 | 13 | } | 19 | } |
1225 | 14 | 20 | ||
1226 | 15 | INSTALLED_APPS = [ | 21 | INSTALLED_APPS = [ |
1227 | 22 | 'django.contrib.staticfiles', | ||
1228 | 16 | 'compressor', | 23 | 'compressor', |
1230 | 17 | 'jingo', | 24 | 'coffin', |
1231 | 25 | ] | ||
1232 | 26 | if django.VERSION < (1, 8): | ||
1233 | 27 | INSTALLED_APPS.append('jingo') | ||
1234 | 28 | |||
1235 | 29 | STATICFILES_FINDERS = [ | ||
1236 | 30 | 'django.contrib.staticfiles.finders.FileSystemFinder', | ||
1237 | 31 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', | ||
1238 | 32 | 'compressor.finders.CompressorFinder', | ||
1239 | 18 | ] | 33 | ] |
1240 | 19 | 34 | ||
1241 | 20 | STATIC_URL = '/static/' | 35 | STATIC_URL = '/static/' |
1242 | @@ -37,3 +52,5 @@ | |||
1243 | 37 | PASSWORD_HASHERS = ( | 52 | PASSWORD_HASHERS = ( |
1244 | 38 | 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', | 53 | 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', |
1245 | 39 | ) | 54 | ) |
1246 | 55 | |||
1247 | 56 | MIDDLEWARE_CLASSES = [] | ||
1248 | 40 | 57 | ||
1249 | === modified file 'compressor/tests/precompiler.py' | |||
1250 | --- compressor/tests/precompiler.py 2014-06-26 15:08:13 +0000 | |||
1251 | +++ compressor/tests/precompiler.py 2015-08-20 18:49:21 +0000 | |||
1252 | @@ -7,11 +7,11 @@ | |||
1253 | 7 | def main(): | 7 | def main(): |
1254 | 8 | p = optparse.OptionParser() | 8 | p = optparse.OptionParser() |
1255 | 9 | p.add_option('-f', '--file', action="store", | 9 | p.add_option('-f', '--file', action="store", |
1258 | 10 | type="string", dest="filename", | 10 | type="string", dest="filename", |
1259 | 11 | help="File to read from, defaults to stdin", default=None) | 11 | help="File to read from, defaults to stdin", default=None) |
1260 | 12 | p.add_option('-o', '--output', action="store", | 12 | p.add_option('-o', '--output', action="store", |
1263 | 13 | type="string", dest="outfile", | 13 | type="string", dest="outfile", |
1264 | 14 | help="File to write to, defaults to stdout", default=None) | 14 | help="File to write to, defaults to stdout", default=None) |
1265 | 15 | 15 | ||
1266 | 16 | options, arguments = p.parse_args() | 16 | options, arguments = p.parse_args() |
1267 | 17 | 17 | ||
1268 | 18 | 18 | ||
1269 | === added file 'compressor/tests/static/css/filename with spaces.css' | |||
1270 | --- compressor/tests/static/css/filename with spaces.css 1970-01-01 00:00:00 +0000 | |||
1271 | +++ compressor/tests/static/css/filename with spaces.css 2015-08-20 18:49:21 +0000 | |||
1272 | @@ -0,0 +1,1 @@ | |||
1273 | 1 | body { background:#424242; } | ||
1274 | 0 | \ No newline at end of file | 2 | \ No newline at end of file |
1275 | 1 | 3 | ||
1276 | === added file 'compressor/tests/static/css/utf-8_with-BOM.css' | |||
1277 | --- compressor/tests/static/css/utf-8_with-BOM.css 1970-01-01 00:00:00 +0000 | |||
1278 | +++ compressor/tests/static/css/utf-8_with-BOM.css 2015-08-20 18:49:21 +0000 | |||
1279 | @@ -0,0 +1,1 @@ | |||
1280 | 1 | .compress-test {color: red;} | ||
1281 | 0 | \ No newline at end of file | 2 | \ No newline at end of file |
1282 | 1 | 3 | ||
1283 | === added file 'compressor/tests/static/js/three.js' | |||
1284 | --- compressor/tests/static/js/three.js 1970-01-01 00:00:00 +0000 | |||
1285 | +++ compressor/tests/static/js/three.js 2015-08-20 18:49:21 +0000 | |||
1286 | @@ -0,0 +1,1 @@ | |||
1287 | 1 | hermanos = {} | ||
1288 | 0 | \ No newline at end of file | 2 | \ No newline at end of file |
1289 | 1 | 3 | ||
1290 | === added file 'compressor/tests/static/js/two.js' | |||
1291 | --- compressor/tests/static/js/two.js 1970-01-01 00:00:00 +0000 | |||
1292 | +++ compressor/tests/static/js/two.js 2015-08-20 18:49:21 +0000 | |||
1293 | @@ -0,0 +1,1 @@ | |||
1294 | 1 | pollos = {} | ||
1295 | 0 | \ No newline at end of file | 2 | \ No newline at end of file |
1296 | 1 | 3 | ||
1297 | === modified file 'compressor/tests/test_base.py' | |||
1298 | --- compressor/tests/test_base.py 2015-01-06 14:31:34 +0000 | |||
1299 | +++ compressor/tests/test_base.py 2015-08-20 18:49:21 +0000 | |||
1300 | @@ -12,11 +12,13 @@ | |||
1301 | 12 | from django.test import SimpleTestCase | 12 | from django.test import SimpleTestCase |
1302 | 13 | from django.test.utils import override_settings | 13 | from django.test.utils import override_settings |
1303 | 14 | 14 | ||
1305 | 15 | from compressor.base import SOURCE_HUNK, SOURCE_FILE | 15 | from compressor import cache as cachemod |
1306 | 16 | from compressor.base import SOURCE_FILE, SOURCE_HUNK | ||
1307 | 17 | from compressor.cache import get_cachekey | ||
1308 | 16 | from compressor.conf import settings | 18 | from compressor.conf import settings |
1309 | 17 | from compressor.css import CssCompressor | 19 | from compressor.css import CssCompressor |
1310 | 20 | from compressor.exceptions import FilterDoesNotExist, FilterError | ||
1311 | 18 | from compressor.js import JsCompressor | 21 | from compressor.js import JsCompressor |
1312 | 19 | from compressor.exceptions import FilterDoesNotExist | ||
1313 | 20 | 22 | ||
1314 | 21 | 23 | ||
1315 | 22 | def make_soup(markup): | 24 | def make_soup(markup): |
1316 | @@ -112,6 +114,14 @@ | |||
1317 | 112 | hunks = '\n'.join([h for h in self.css_node.hunks()]) | 114 | hunks = '\n'.join([h for h in self.css_node.hunks()]) |
1318 | 113 | self.assertEqual(out, hunks) | 115 | self.assertEqual(out, hunks) |
1319 | 114 | 116 | ||
1320 | 117 | def test_css_output_with_bom_input(self): | ||
1321 | 118 | out = 'body { background:#990; }\n.compress-test {color: red;}' | ||
1322 | 119 | css = ("""<link rel="stylesheet" href="/static/css/one.css" type="text/css" /> | ||
1323 | 120 | <link rel="stylesheet" href="/static/css/utf-8_with-BOM.css" type="text/css" />""") | ||
1324 | 121 | css_node_with_bom = CssCompressor(css) | ||
1325 | 122 | hunks = '\n'.join([h for h in css_node_with_bom.hunks()]) | ||
1326 | 123 | self.assertEqual(out, hunks) | ||
1327 | 124 | |||
1328 | 115 | def test_css_mtimes(self): | 125 | def test_css_mtimes(self): |
1329 | 116 | is_date = re.compile(r'^\d{10}[\.\d]+$') | 126 | is_date = re.compile(r'^\d{10}[\.\d]+$') |
1330 | 117 | for date in self.css_node.mtimes: | 127 | for date in self.css_node.mtimes: |
1331 | @@ -208,6 +218,14 @@ | |||
1332 | 208 | css_node = CssCompressor(css) | 218 | css_node = CssCompressor(css) |
1333 | 209 | self.assertRaises(FilterDoesNotExist, css_node.output, 'inline') | 219 | self.assertRaises(FilterDoesNotExist, css_node.output, 'inline') |
1334 | 210 | 220 | ||
1335 | 221 | @override_settings(COMPRESS_PRECOMPILERS=( | ||
1336 | 222 | ('text/foobar', './foo -I ./bar/baz'), | ||
1337 | 223 | ), COMPRESS_ENABLED=True) | ||
1338 | 224 | def test_command_with_dot_precompiler(self): | ||
1339 | 225 | css = '<style type="text/foobar">p { border:10px solid red;}</style>' | ||
1340 | 226 | css_node = CssCompressor(css) | ||
1341 | 227 | self.assertRaises(FilterError, css_node.output, 'inline') | ||
1342 | 228 | |||
1343 | 211 | 229 | ||
1344 | 212 | class CssMediaTestCase(SimpleTestCase): | 230 | class CssMediaTestCase(SimpleTestCase): |
1345 | 213 | def setUp(self): | 231 | def setUp(self): |
1346 | @@ -267,4 +285,49 @@ | |||
1347 | 267 | 285 | ||
1348 | 268 | def test_correct_backend(self): | 286 | def test_correct_backend(self): |
1349 | 269 | from compressor.cache import cache | 287 | from compressor.cache import cache |
1351 | 270 | self.assertEqual(cache.__class__, locmem.CacheClass) | 288 | self.assertEqual(cache.__class__, locmem.LocMemCache) |
1352 | 289 | |||
1353 | 290 | |||
1354 | 291 | class JsAsyncDeferTestCase(SimpleTestCase): | ||
1355 | 292 | def setUp(self): | ||
1356 | 293 | self.js = """\ | ||
1357 | 294 | <script src="/static/js/one.js" type="text/javascript"></script> | ||
1358 | 295 | <script src="/static/js/two.js" type="text/javascript" async></script> | ||
1359 | 296 | <script src="/static/js/three.js" type="text/javascript" defer></script> | ||
1360 | 297 | <script type="text/javascript">obj.value = "value";</script> | ||
1361 | 298 | <script src="/static/js/one.js" type="text/javascript" async></script> | ||
1362 | 299 | <script src="/static/js/two.js" type="text/javascript" async></script> | ||
1363 | 300 | <script src="/static/js/three.js" type="text/javascript"></script>""" | ||
1364 | 301 | |||
1365 | 302 | def test_js_output(self): | ||
1366 | 303 | def extract_attr(tag): | ||
1367 | 304 | if tag.has_attr('async'): | ||
1368 | 305 | return 'async' | ||
1369 | 306 | if tag.has_attr('defer'): | ||
1370 | 307 | return 'defer' | ||
1371 | 308 | js_node = JsCompressor(self.js) | ||
1372 | 309 | output = [None, 'async', 'defer', None, 'async', None] | ||
1373 | 310 | if six.PY3: | ||
1374 | 311 | scripts = make_soup(js_node.output()).find_all('script') | ||
1375 | 312 | attrs = [extract_attr(i) for i in scripts] | ||
1376 | 313 | else: | ||
1377 | 314 | scripts = make_soup(js_node.output()).findAll('script') | ||
1378 | 315 | attrs = [s.get('async') or s.get('defer') for s in scripts] | ||
1379 | 316 | self.assertEqual(output, attrs) | ||
1380 | 317 | |||
1381 | 318 | |||
1382 | 319 | class CacheTestCase(SimpleTestCase): | ||
1383 | 320 | |||
1384 | 321 | def setUp(self): | ||
1385 | 322 | cachemod._cachekey_func = None | ||
1386 | 323 | |||
1387 | 324 | def test_get_cachekey_basic(self): | ||
1388 | 325 | self.assertEqual(get_cachekey("foo"), "django_compressor.foo") | ||
1389 | 326 | |||
1390 | 327 | @override_settings(COMPRESS_CACHE_KEY_FUNCTION='.leading.dot') | ||
1391 | 328 | def test_get_cachekey_leading_dot(self): | ||
1392 | 329 | self.assertRaises(ImportError, lambda: get_cachekey("foo")) | ||
1393 | 330 | |||
1394 | 331 | @override_settings(COMPRESS_CACHE_KEY_FUNCTION='invalid.module') | ||
1395 | 332 | def test_get_cachekey_invalid_mod(self): | ||
1396 | 333 | self.assertRaises(ImportError, lambda: get_cachekey("foo")) | ||
1397 | 271 | 334 | ||
1398 | === modified file 'compressor/tests/test_filters.py' | |||
1399 | --- compressor/tests/test_filters.py 2015-01-06 14:31:34 +0000 | |||
1400 | +++ compressor/tests/test_filters.py 2015-08-20 18:49:21 +0000 | |||
1401 | @@ -1,4 +1,5 @@ | |||
1402 | 1 | from __future__ import with_statement, unicode_literals | 1 | from __future__ import with_statement, unicode_literals |
1403 | 2 | from collections import defaultdict | ||
1404 | 2 | import io | 3 | import io |
1405 | 3 | import os | 4 | import os |
1406 | 4 | import sys | 5 | import sys |
1407 | @@ -17,9 +18,18 @@ | |||
1408 | 17 | from compressor.filters.cssmin import CSSMinFilter | 18 | from compressor.filters.cssmin import CSSMinFilter |
1409 | 18 | from compressor.filters.css_default import CssAbsoluteFilter | 19 | from compressor.filters.css_default import CssAbsoluteFilter |
1410 | 19 | from compressor.filters.template import TemplateFilter | 20 | from compressor.filters.template import TemplateFilter |
1411 | 21 | from compressor.filters.closure import ClosureCompilerFilter | ||
1412 | 22 | from compressor.filters.csstidy import CSSTidyFilter | ||
1413 | 23 | from compressor.filters.yuglify import YUglifyCSSFilter, YUglifyJSFilter | ||
1414 | 24 | from compressor.filters.yui import YUICSSFilter, YUIJSFilter | ||
1415 | 25 | from compressor.filters.cleancss import CleanCSSFilter | ||
1416 | 20 | from compressor.tests.test_base import test_dir | 26 | from compressor.tests.test_base import test_dir |
1417 | 21 | 27 | ||
1418 | 22 | 28 | ||
1419 | 29 | def blankdict(*args, **kwargs): | ||
1420 | 30 | return defaultdict(lambda: '', *args, **kwargs) | ||
1421 | 31 | |||
1422 | 32 | |||
1423 | 23 | @unittest.skipIf(find_command(settings.COMPRESS_CSSTIDY_BINARY) is None, | 33 | @unittest.skipIf(find_command(settings.COMPRESS_CSSTIDY_BINARY) is None, |
1424 | 24 | 'CSStidy binary %r not found' % settings.COMPRESS_CSSTIDY_BINARY) | 34 | 'CSStidy binary %r not found' % settings.COMPRESS_CSSTIDY_BINARY) |
1425 | 25 | class CssTidyTestCase(TestCase): | 35 | class CssTidyTestCase(TestCase): |
1426 | @@ -30,7 +40,6 @@ | |||
1427 | 30 | color: black; | 40 | color: black; |
1428 | 31 | } | 41 | } |
1429 | 32 | """) | 42 | """) |
1430 | 33 | from compressor.filters.csstidy import CSSTidyFilter | ||
1431 | 34 | ret = CSSTidyFilter(content).input() | 43 | ret = CSSTidyFilter(content).input() |
1432 | 35 | self.assertIsInstance(ret, six.text_type) | 44 | self.assertIsInstance(ret, six.text_type) |
1433 | 36 | self.assertEqual( | 45 | self.assertEqual( |
1434 | @@ -39,10 +48,13 @@ | |||
1435 | 39 | 48 | ||
1436 | 40 | class PrecompilerTestCase(TestCase): | 49 | class PrecompilerTestCase(TestCase): |
1437 | 41 | def setUp(self): | 50 | def setUp(self): |
1439 | 42 | self.filename = os.path.join(test_dir, 'static/css/one.css') | 51 | self.test_precompiler = os.path.join(test_dir, 'precompiler.py') |
1440 | 52 | self.setup_infile() | ||
1441 | 53 | |||
1442 | 54 | def setup_infile(self, filename='static/css/one.css'): | ||
1443 | 55 | self.filename = os.path.join(test_dir, filename) | ||
1444 | 43 | with io.open(self.filename, encoding=settings.FILE_CHARSET) as file: | 56 | with io.open(self.filename, encoding=settings.FILE_CHARSET) as file: |
1445 | 44 | self.content = file.read() | 57 | self.content = file.read() |
1446 | 45 | self.test_precompiler = os.path.join(test_dir, 'precompiler.py') | ||
1447 | 46 | 58 | ||
1448 | 47 | def test_precompiler_infile_outfile(self): | 59 | def test_precompiler_infile_outfile(self): |
1449 | 48 | command = '%s %s -f {infile} -o {outfile}' % (sys.executable, self.test_precompiler) | 60 | command = '%s %s -f {infile} -o {outfile}' % (sys.executable, self.test_precompiler) |
1450 | @@ -51,6 +63,14 @@ | |||
1451 | 51 | charset=settings.FILE_CHARSET, command=command) | 63 | charset=settings.FILE_CHARSET, command=command) |
1452 | 52 | self.assertEqual("body { color:#990; }", compiler.input()) | 64 | self.assertEqual("body { color:#990; }", compiler.input()) |
1453 | 53 | 65 | ||
1454 | 66 | def test_precompiler_infile_with_spaces(self): | ||
1455 | 67 | self.setup_infile('static/css/filename with spaces.css') | ||
1456 | 68 | command = '%s %s -f {infile} -o {outfile}' % (sys.executable, self.test_precompiler) | ||
1457 | 69 | compiler = CompilerFilter( | ||
1458 | 70 | content=self.content, filename=self.filename, | ||
1459 | 71 | charset=settings.FILE_CHARSET, command=command) | ||
1460 | 72 | self.assertEqual("body { color:#424242; }", compiler.input()) | ||
1461 | 73 | |||
1462 | 54 | def test_precompiler_infile_stdout(self): | 74 | def test_precompiler_infile_stdout(self): |
1463 | 55 | command = '%s %s -f {infile}' % (sys.executable, self.test_precompiler) | 75 | command = '%s %s -f {infile}' % (sys.executable, self.test_precompiler) |
1464 | 56 | compiler = CompilerFilter( | 76 | compiler = CompilerFilter( |
1465 | @@ -99,8 +119,8 @@ | |||
1466 | 99 | class CssAbsolutizingTestCase(TestCase): | 119 | class CssAbsolutizingTestCase(TestCase): |
1467 | 100 | hashing_method = 'mtime' | 120 | hashing_method = 'mtime' |
1468 | 101 | hashing_func = staticmethod(get_hashed_mtime) | 121 | hashing_func = staticmethod(get_hashed_mtime) |
1471 | 102 | content = ("p { background: url('../../img/python.png') }" | 122 | template = ("p { background: url('%(url)simg/python.png%(query)s%(hash)s%(frag)s') }" |
1472 | 103 | "p { filter: Alpha(src='../../img/python.png') }") | 123 | "p { filter: Alpha(src='%(url)simg/python.png%(query)s%(hash)s%(frag)s') }") |
1473 | 104 | 124 | ||
1474 | 105 | def setUp(self): | 125 | def setUp(self): |
1475 | 106 | self.old_enabled = settings.COMPRESS_ENABLED | 126 | self.old_enabled = settings.COMPRESS_ENABLED |
1476 | @@ -120,40 +140,55 @@ | |||
1477 | 120 | settings.COMPRESS_URL = self.old_url | 140 | settings.COMPRESS_URL = self.old_url |
1478 | 121 | settings.COMPRESS_CSS_HASHING_METHOD = self.old_hashing_method | 141 | settings.COMPRESS_CSS_HASHING_METHOD = self.old_hashing_method |
1479 | 122 | 142 | ||
1480 | 143 | def test_css_no_hash(self): | ||
1481 | 144 | settings.COMPRESS_CSS_HASHING_METHOD = None | ||
1482 | 145 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | ||
1483 | 146 | content = self.template % blankdict(url='../../') | ||
1484 | 147 | params = blankdict({ | ||
1485 | 148 | 'url': settings.COMPRESS_URL, | ||
1486 | 149 | }) | ||
1487 | 150 | output = self.template % params | ||
1488 | 151 | filter = CssAbsoluteFilter(content) | ||
1489 | 152 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | ||
1490 | 153 | |||
1491 | 154 | settings.COMPRESS_URL = params['url'] = 'http://static.example.com/' | ||
1492 | 155 | output = self.template % params | ||
1493 | 156 | filter = CssAbsoluteFilter(content) | ||
1494 | 157 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | ||
1495 | 158 | |||
1496 | 123 | def test_css_absolute_filter(self): | 159 | def test_css_absolute_filter(self): |
1497 | 124 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | 160 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') |
1498 | 125 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') | 161 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') |
1500 | 126 | params = { | 162 | content = self.template % blankdict(url='../../') |
1501 | 163 | params = blankdict({ | ||
1502 | 127 | 'url': settings.COMPRESS_URL, | 164 | 'url': settings.COMPRESS_URL, |
1508 | 128 | 'hash': self.hashing_func(imagefilename), | 165 | 'hash': '?' + self.hashing_func(imagefilename), |
1509 | 129 | } | 166 | }) |
1510 | 130 | output = ("p { background: url('%(url)simg/python.png?%(hash)s') }" | 167 | output = self.template % params |
1511 | 131 | "p { filter: Alpha(src='%(url)simg/python.png?%(hash)s') }") % params | 168 | filter = CssAbsoluteFilter(content) |
1507 | 132 | filter = CssAbsoluteFilter(self.content) | ||
1512 | 133 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 169 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1513 | 170 | |||
1514 | 134 | settings.COMPRESS_URL = params['url'] = 'http://static.example.com/' | 171 | settings.COMPRESS_URL = params['url'] = 'http://static.example.com/' |
1519 | 135 | filter = CssAbsoluteFilter(self.content) | 172 | output = self.template % params |
1520 | 136 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | 173 | filter = CssAbsoluteFilter(content) |
1517 | 137 | output = ("p { background: url('%(url)simg/python.png?%(hash)s') }" | ||
1518 | 138 | "p { filter: Alpha(src='%(url)simg/python.png?%(hash)s') }") % params | ||
1521 | 139 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 174 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1522 | 140 | 175 | ||
1523 | 141 | def test_css_absolute_filter_url_fragment(self): | 176 | def test_css_absolute_filter_url_fragment(self): |
1524 | 142 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | 177 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') |
1525 | 143 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') | 178 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') |
1527 | 144 | params = { | 179 | content = self.template % blankdict(url='../../', frag='#foo') |
1528 | 180 | params = blankdict({ | ||
1529 | 145 | 'url': settings.COMPRESS_URL, | 181 | 'url': settings.COMPRESS_URL, |
1535 | 146 | 'hash': self.hashing_func(imagefilename), | 182 | 'hash': '?' + self.hashing_func(imagefilename), |
1536 | 147 | } | 183 | 'frag': '#foo', |
1537 | 148 | content = "p { background: url('../../img/python.png#foo') }" | 184 | }) |
1538 | 149 | 185 | output = self.template % params | |
1534 | 150 | output = "p { background: url('%(url)simg/python.png?%(hash)s#foo') }" % params | ||
1539 | 151 | filter = CssAbsoluteFilter(content) | 186 | filter = CssAbsoluteFilter(content) |
1540 | 152 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 187 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1541 | 188 | |||
1542 | 153 | settings.COMPRESS_URL = params['url'] = 'http://media.example.com/' | 189 | settings.COMPRESS_URL = params['url'] = 'http://media.example.com/' |
1543 | 190 | output = self.template % params | ||
1544 | 154 | filter = CssAbsoluteFilter(content) | 191 | filter = CssAbsoluteFilter(content) |
1545 | 155 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | ||
1546 | 156 | output = "p { background: url('%(url)simg/python.png?%(hash)s#foo') }" % params | ||
1547 | 157 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 192 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1548 | 158 | 193 | ||
1549 | 159 | def test_css_absolute_filter_only_url_fragment(self): | 194 | def test_css_absolute_filter_only_url_fragment(self): |
1550 | @@ -161,64 +196,78 @@ | |||
1551 | 161 | content = "p { background: url('#foo') }" | 196 | content = "p { background: url('#foo') }" |
1552 | 162 | filter = CssAbsoluteFilter(content) | 197 | filter = CssAbsoluteFilter(content) |
1553 | 163 | self.assertEqual(content, filter.input(filename=filename, basename='css/url/test.css')) | 198 | self.assertEqual(content, filter.input(filename=filename, basename='css/url/test.css')) |
1554 | 199 | |||
1555 | 164 | settings.COMPRESS_URL = 'http://media.example.com/' | 200 | settings.COMPRESS_URL = 'http://media.example.com/' |
1556 | 165 | filter = CssAbsoluteFilter(content) | 201 | filter = CssAbsoluteFilter(content) |
1557 | 166 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | ||
1558 | 167 | self.assertEqual(content, filter.input(filename=filename, basename='css/url/test.css')) | 202 | self.assertEqual(content, filter.input(filename=filename, basename='css/url/test.css')) |
1559 | 168 | 203 | ||
1560 | 169 | def test_css_absolute_filter_querystring(self): | 204 | def test_css_absolute_filter_querystring(self): |
1561 | 170 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | 205 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') |
1562 | 171 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') | 206 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') |
1564 | 172 | params = { | 207 | content = self.template % blankdict(url='../../', query='?foo') |
1565 | 208 | params = blankdict({ | ||
1566 | 173 | 'url': settings.COMPRESS_URL, | 209 | 'url': settings.COMPRESS_URL, |
1572 | 174 | 'hash': self.hashing_func(imagefilename), | 210 | 'query': '?foo', |
1573 | 175 | } | 211 | 'hash': '&' + self.hashing_func(imagefilename), |
1574 | 176 | content = "p { background: url('../../img/python.png?foo') }" | 212 | }) |
1575 | 177 | 213 | output = self.template % params | |
1571 | 178 | output = "p { background: url('%(url)simg/python.png?foo&%(hash)s') }" % params | ||
1576 | 179 | filter = CssAbsoluteFilter(content) | 214 | filter = CssAbsoluteFilter(content) |
1577 | 180 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 215 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1578 | 216 | |||
1579 | 181 | settings.COMPRESS_URL = params['url'] = 'http://media.example.com/' | 217 | settings.COMPRESS_URL = params['url'] = 'http://media.example.com/' |
1580 | 218 | output = self.template % params | ||
1581 | 182 | filter = CssAbsoluteFilter(content) | 219 | filter = CssAbsoluteFilter(content) |
1582 | 183 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | ||
1583 | 184 | output = "p { background: url('%(url)simg/python.png?foo&%(hash)s') }" % params | ||
1584 | 185 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 220 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1585 | 186 | 221 | ||
1586 | 187 | def test_css_absolute_filter_https(self): | 222 | def test_css_absolute_filter_https(self): |
1587 | 188 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | 223 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') |
1588 | 189 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') | 224 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') |
1590 | 190 | params = { | 225 | content = self.template % blankdict(url='../../') |
1591 | 226 | params = blankdict({ | ||
1592 | 191 | 'url': settings.COMPRESS_URL, | 227 | 'url': settings.COMPRESS_URL, |
1598 | 192 | 'hash': self.hashing_func(imagefilename), | 228 | 'hash': '?' + self.hashing_func(imagefilename), |
1599 | 193 | } | 229 | }) |
1600 | 194 | output = ("p { background: url('%(url)simg/python.png?%(hash)s') }" | 230 | output = self.template % params |
1601 | 195 | "p { filter: Alpha(src='%(url)simg/python.png?%(hash)s') }") % params | 231 | filter = CssAbsoluteFilter(content) |
1597 | 196 | filter = CssAbsoluteFilter(self.content) | ||
1602 | 197 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 232 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1603 | 233 | |||
1604 | 198 | settings.COMPRESS_URL = params['url'] = 'https://static.example.com/' | 234 | settings.COMPRESS_URL = params['url'] = 'https://static.example.com/' |
1609 | 199 | filter = CssAbsoluteFilter(self.content) | 235 | output = self.template % params |
1610 | 200 | filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') | 236 | filter = CssAbsoluteFilter(content) |
1607 | 201 | output = ("p { background: url('%(url)simg/python.png?%(hash)s') }" | ||
1608 | 202 | "p { filter: Alpha(src='%(url)simg/python.png?%(hash)s') }") % params | ||
1611 | 203 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 237 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1612 | 204 | 238 | ||
1613 | 205 | def test_css_absolute_filter_relative_path(self): | 239 | def test_css_absolute_filter_relative_path(self): |
1614 | 206 | filename = os.path.join(settings.TEST_DIR, 'whatever', '..', 'static', 'whatever/../css/url/test.css') | 240 | filename = os.path.join(settings.TEST_DIR, 'whatever', '..', 'static', 'whatever/../css/url/test.css') |
1615 | 207 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') | 241 | imagefilename = os.path.join(settings.COMPRESS_ROOT, 'img/python.png') |
1617 | 208 | params = { | 242 | content = self.template % blankdict(url='../../') |
1618 | 243 | params = blankdict({ | ||
1619 | 209 | 'url': settings.COMPRESS_URL, | 244 | 'url': settings.COMPRESS_URL, |
1625 | 210 | 'hash': self.hashing_func(imagefilename), | 245 | 'hash': '?' + self.hashing_func(imagefilename), |
1626 | 211 | } | 246 | }) |
1627 | 212 | output = ("p { background: url('%(url)simg/python.png?%(hash)s') }" | 247 | output = self.template % params |
1628 | 213 | "p { filter: Alpha(src='%(url)simg/python.png?%(hash)s') }") % params | 248 | filter = CssAbsoluteFilter(content) |
1624 | 214 | filter = CssAbsoluteFilter(self.content) | ||
1629 | 215 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 249 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1630 | 250 | |||
1631 | 216 | settings.COMPRESS_URL = params['url'] = 'https://static.example.com/' | 251 | settings.COMPRESS_URL = params['url'] = 'https://static.example.com/' |
1635 | 217 | filter = CssAbsoluteFilter(self.content) | 252 | output = self.template % params |
1636 | 218 | output = ("p { background: url('%(url)simg/python.png?%(hash)s') }" | 253 | filter = CssAbsoluteFilter(content) |
1634 | 219 | "p { filter: Alpha(src='%(url)simg/python.png?%(hash)s') }") % params | ||
1637 | 220 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) | 254 | self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css')) |
1638 | 221 | 255 | ||
1639 | 256 | def test_css_absolute_filter_filename_outside_compress_root(self): | ||
1640 | 257 | filename = '/foo/bar/baz/test.css' | ||
1641 | 258 | content = self.template % blankdict(url='../qux/') | ||
1642 | 259 | params = blankdict({ | ||
1643 | 260 | 'url': settings.COMPRESS_URL + 'bar/qux/', | ||
1644 | 261 | }) | ||
1645 | 262 | output = self.template % params | ||
1646 | 263 | filter = CssAbsoluteFilter(content) | ||
1647 | 264 | self.assertEqual(output, filter.input(filename=filename, basename='bar/baz/test.css')) | ||
1648 | 265 | settings.COMPRESS_URL = 'https://static.example.com/' | ||
1649 | 266 | params['url'] = settings.COMPRESS_URL + 'bar/qux/' | ||
1650 | 267 | output = self.template % params | ||
1651 | 268 | filter = CssAbsoluteFilter(content) | ||
1652 | 269 | self.assertEqual(output, filter.input(filename=filename, basename='bar/baz/test.css')) | ||
1653 | 270 | |||
1654 | 222 | def test_css_hunks(self): | 271 | def test_css_hunks(self): |
1655 | 223 | hash_dict = { | 272 | hash_dict = { |
1656 | 224 | 'hash1': self.hashing_func(os.path.join(settings.COMPRESS_ROOT, 'img/python.png')), | 273 | 'hash1': self.hashing_func(os.path.join(settings.COMPRESS_ROOT, 'img/python.png')), |
1657 | @@ -253,14 +302,6 @@ | |||
1658 | 253 | hashing_method = 'content' | 302 | hashing_method = 'content' |
1659 | 254 | hashing_func = staticmethod(get_hashed_content) | 303 | hashing_func = staticmethod(get_hashed_content) |
1660 | 255 | 304 | ||
1661 | 256 | def setUp(self): | ||
1662 | 257 | super(CssAbsolutizingTestCaseWithHash, self).setUp() | ||
1663 | 258 | self.css = """ | ||
1664 | 259 | <link rel="stylesheet" href="/static/css/url/url1.css" type="text/css" charset="utf-8"> | ||
1665 | 260 | <link rel="stylesheet" href="/static/css/url/2/url2.css" type="text/css" charset="utf-8"> | ||
1666 | 261 | """ | ||
1667 | 262 | self.css_node = CssCompressor(self.css) | ||
1668 | 263 | |||
1669 | 264 | 305 | ||
1670 | 265 | class CssDataUriTestCase(TestCase): | 306 | class CssDataUriTestCase(TestCase): |
1671 | 266 | def setUp(self): | 307 | def setUp(self): |
1672 | @@ -301,3 +342,38 @@ | |||
1673 | 301 | #footer {font-weight: bold;} | 342 | #footer {font-weight: bold;} |
1674 | 302 | """ | 343 | """ |
1675 | 303 | self.assertEqual(input, TemplateFilter(content).input()) | 344 | self.assertEqual(input, TemplateFilter(content).input()) |
1676 | 345 | |||
1677 | 346 | |||
1678 | 347 | class SpecializedFiltersTest(TestCase): | ||
1679 | 348 | """ | ||
1680 | 349 | Test to check the Specializations of filters. | ||
1681 | 350 | """ | ||
1682 | 351 | def test_closure_filter(self): | ||
1683 | 352 | filter = ClosureCompilerFilter('') | ||
1684 | 353 | self.assertEqual(filter.options, (('binary', six.text_type('java -jar compiler.jar')), ('args', six.text_type('')))) | ||
1685 | 354 | |||
1686 | 355 | def test_csstidy_filter(self): | ||
1687 | 356 | filter = CSSTidyFilter('') | ||
1688 | 357 | self.assertEqual(filter.options, (('binary', six.text_type('csstidy')), ('args', six.text_type('--template=highest')))) | ||
1689 | 358 | |||
1690 | 359 | def test_yuglify_filters(self): | ||
1691 | 360 | filter = YUglifyCSSFilter('') | ||
1692 | 361 | self.assertEqual(filter.command, '{binary} {args} --type=css') | ||
1693 | 362 | self.assertEqual(filter.options, (('binary', six.text_type('yuglify')), ('args', six.text_type('--terminal')))) | ||
1694 | 363 | |||
1695 | 364 | filter = YUglifyJSFilter('') | ||
1696 | 365 | self.assertEqual(filter.command, '{binary} {args} --type=js') | ||
1697 | 366 | self.assertEqual(filter.options, (('binary', six.text_type('yuglify')), ('args', six.text_type('--terminal')))) | ||
1698 | 367 | |||
1699 | 368 | def test_yui_filters(self): | ||
1700 | 369 | filter = YUICSSFilter('') | ||
1701 | 370 | self.assertEqual(filter.command, '{binary} {args} --type=css') | ||
1702 | 371 | self.assertEqual(filter.options, (('binary', six.text_type('java -jar yuicompressor.jar')), ('args', six.text_type('')))) | ||
1703 | 372 | |||
1704 | 373 | filter = YUIJSFilter('', verbose=1) | ||
1705 | 374 | self.assertEqual(filter.command, '{binary} {args} --type=js --verbose') | ||
1706 | 375 | self.assertEqual(filter.options, (('binary', six.text_type('java -jar yuicompressor.jar')), ('args', six.text_type('')), ('verbose', 1))) | ||
1707 | 376 | |||
1708 | 377 | def test_clean_css_filter(self): | ||
1709 | 378 | filter = CleanCSSFilter('') | ||
1710 | 379 | self.assertEqual(filter.options, (('binary', six.text_type('cleancss')), ('args', six.text_type('')))) | ||
1711 | 304 | 380 | ||
1712 | === modified file 'compressor/tests/test_jinja2ext.py' | |||
1713 | --- compressor/tests/test_jinja2ext.py 2015-01-06 14:31:34 +0000 | |||
1714 | +++ compressor/tests/test_jinja2ext.py 2015-08-20 18:49:21 +0000 | |||
1715 | @@ -65,8 +65,7 @@ | |||
1716 | 65 | self.assertEqual(tag_body, template.render()) | 65 | self.assertEqual(tag_body, template.render()) |
1717 | 66 | 66 | ||
1718 | 67 | def test_empty_tag(self): | 67 | def test_empty_tag(self): |
1721 | 68 | template = self.env.from_string("""{% compress js %}{% block js %} | 68 | template = self.env.from_string("""{% compress js %}{% block js %}{% endblock %}{% endcompress %}""") |
1720 | 69 | {% endblock %}{% endcompress %}""") | ||
1722 | 70 | context = {'STATIC_URL': settings.COMPRESS_URL} | 69 | context = {'STATIC_URL': settings.COMPRESS_URL} |
1723 | 71 | self.assertEqual('', template.render(context)) | 70 | self.assertEqual('', template.render(context)) |
1724 | 72 | 71 | ||
1725 | 73 | 72 | ||
1726 | === modified file 'compressor/tests/test_offline.py' | |||
1727 | --- compressor/tests/test_offline.py 2015-01-06 14:31:34 +0000 | |||
1728 | +++ compressor/tests/test_offline.py 2015-08-20 18:49:21 +0000 | |||
1729 | @@ -3,6 +3,7 @@ | |||
1730 | 3 | import os | 3 | import os |
1731 | 4 | import sys | 4 | import sys |
1732 | 5 | 5 | ||
1733 | 6 | import django | ||
1734 | 6 | from django.core.management.base import CommandError | 7 | from django.core.management.base import CommandError |
1735 | 7 | from django.template import Template, Context | 8 | from django.template import Template, Context |
1736 | 8 | from django.test import TestCase | 9 | from django.test import TestCase |
1737 | @@ -44,10 +45,6 @@ | |||
1738 | 44 | engines = ("django",) | 45 | engines = ("django",) |
1739 | 45 | 46 | ||
1740 | 46 | def setUp(self): | 47 | def setUp(self): |
1741 | 47 | self._old_compress = settings.COMPRESS_ENABLED | ||
1742 | 48 | self._old_compress_offline = settings.COMPRESS_OFFLINE | ||
1743 | 49 | self._old_template_dirs = settings.TEMPLATE_DIRS | ||
1744 | 50 | self._old_offline_context = settings.COMPRESS_OFFLINE_CONTEXT | ||
1745 | 51 | self.log = StringIO() | 48 | self.log = StringIO() |
1746 | 52 | 49 | ||
1747 | 53 | # Reset template dirs, because it enables us to force compress to | 50 | # Reset template dirs, because it enables us to force compress to |
1748 | @@ -58,11 +55,18 @@ | |||
1749 | 58 | # template to be skipped over. | 55 | # template to be skipped over. |
1750 | 59 | django_template_dir = os.path.join(settings.TEST_DIR, 'test_templates', self.templates_dir) | 56 | django_template_dir = os.path.join(settings.TEST_DIR, 'test_templates', self.templates_dir) |
1751 | 60 | jinja2_template_dir = os.path.join(settings.TEST_DIR, 'test_templates_jinja2', self.templates_dir) | 57 | jinja2_template_dir = os.path.join(settings.TEST_DIR, 'test_templates_jinja2', self.templates_dir) |
1757 | 61 | settings.TEMPLATE_DIRS = (django_template_dir, jinja2_template_dir) | 58 | |
1758 | 62 | 59 | override_settings = { | |
1759 | 63 | # Enable offline compress | 60 | 'TEMPLATE_DIRS': (django_template_dir, jinja2_template_dir,), |
1760 | 64 | settings.COMPRESS_ENABLED = True | 61 | 'COMPRESS_ENABLED': True, |
1761 | 65 | settings.COMPRESS_OFFLINE = True | 62 | 'COMPRESS_OFFLINE': True |
1762 | 63 | } | ||
1763 | 64 | |||
1764 | 65 | if "jinja2" in self.engines: | ||
1765 | 66 | override_settings["COMPRESS_JINJA2_GET_ENVIRONMENT"] = lambda: self._get_jinja2_env() | ||
1766 | 67 | |||
1767 | 68 | self.override_settings = self.settings(**override_settings) | ||
1768 | 69 | self.override_settings.__enter__() | ||
1769 | 66 | 70 | ||
1770 | 67 | if "django" in self.engines: | 71 | if "django" in self.engines: |
1771 | 68 | self.template_path = os.path.join(django_template_dir, self.template_name) | 72 | self.template_path = os.path.join(django_template_dir, self.template_name) |
1772 | @@ -70,22 +74,16 @@ | |||
1773 | 70 | with io.open(self.template_path, encoding=settings.FILE_CHARSET) as file: | 74 | with io.open(self.template_path, encoding=settings.FILE_CHARSET) as file: |
1774 | 71 | self.template = Template(file.read()) | 75 | self.template = Template(file.read()) |
1775 | 72 | 76 | ||
1776 | 73 | self._old_jinja2_get_environment = settings.COMPRESS_JINJA2_GET_ENVIRONMENT | ||
1777 | 74 | |||
1778 | 75 | if "jinja2" in self.engines: | 77 | if "jinja2" in self.engines: |
1782 | 76 | # Setup Jinja2 settings. | 78 | jinja2_env = override_settings["COMPRESS_JINJA2_GET_ENVIRONMENT"]() |
1780 | 77 | settings.COMPRESS_JINJA2_GET_ENVIRONMENT = lambda: self._get_jinja2_env() | ||
1781 | 78 | jinja2_env = settings.COMPRESS_JINJA2_GET_ENVIRONMENT() | ||
1783 | 79 | self.template_path_jinja2 = os.path.join(jinja2_template_dir, self.template_name) | 79 | self.template_path_jinja2 = os.path.join(jinja2_template_dir, self.template_name) |
1784 | 80 | 80 | ||
1785 | 81 | with io.open(self.template_path_jinja2, encoding=settings.FILE_CHARSET) as file: | 81 | with io.open(self.template_path_jinja2, encoding=settings.FILE_CHARSET) as file: |
1786 | 82 | self.template_jinja2 = jinja2_env.from_string(file.read()) | 82 | self.template_jinja2 = jinja2_env.from_string(file.read()) |
1787 | 83 | 83 | ||
1788 | 84 | def tearDown(self): | 84 | def tearDown(self): |
1793 | 85 | settings.COMPRESS_JINJA2_GET_ENVIRONMENT = self._old_jinja2_get_environment | 85 | self.override_settings.__exit__(None, None, None) |
1794 | 86 | settings.COMPRESS_ENABLED = self._old_compress | 86 | |
1791 | 87 | settings.COMPRESS_OFFLINE = self._old_compress_offline | ||
1792 | 88 | settings.TEMPLATE_DIRS = self._old_template_dirs | ||
1795 | 89 | manifest_path = os.path.join('CACHE', 'manifest.json') | 87 | manifest_path = os.path.join('CACHE', 'manifest.json') |
1796 | 90 | if default_storage.exists(manifest_path): | 88 | if default_storage.exists(manifest_path): |
1797 | 91 | default_storage.delete(manifest_path) | 89 | default_storage.delete(manifest_path) |
1798 | @@ -452,9 +450,10 @@ | |||
1799 | 452 | # from library import * | 450 | # from library import * |
1800 | 453 | # causing 'ImportError: No module named library'. | 451 | # causing 'ImportError: No module named library'. |
1801 | 454 | # It seems there is no evidence nor indicated support for Python 3+. | 452 | # It seems there is no evidence nor indicated support for Python 3+. |
1802 | 455 | @unittest.skip("Coffin tests disable under Ubuntu build") | ||
1803 | 456 | @unittest.skipIf(sys.version_info >= (3, 2), | 453 | @unittest.skipIf(sys.version_info >= (3, 2), |
1804 | 457 | "Coffin does not support 3.2+") | 454 | "Coffin does not support 3.2+") |
1805 | 455 | @unittest.skipIf(django.VERSION >= (1, 8), | ||
1806 | 456 | "Import error on 1.8") | ||
1807 | 458 | class OfflineGenerationCoffinTestCase(OfflineTestCaseMixin, TestCase): | 457 | class OfflineGenerationCoffinTestCase(OfflineTestCaseMixin, TestCase): |
1808 | 459 | templates_dir = "test_coffin" | 458 | templates_dir = "test_coffin" |
1809 | 460 | expected_hash = "32c8281e3346" | 459 | expected_hash = "32c8281e3346" |
1810 | @@ -479,6 +478,8 @@ | |||
1811 | 479 | # is also evident in its tox.ini file. | 478 | # is also evident in its tox.ini file. |
1812 | 480 | @unittest.skipIf(sys.version_info >= (3, 2) and sys.version_info < (3, 3), | 479 | @unittest.skipIf(sys.version_info >= (3, 2) and sys.version_info < (3, 3), |
1813 | 481 | "Jingo does not support 3.2") | 480 | "Jingo does not support 3.2") |
1814 | 481 | @unittest.skipIf(django.VERSION >= (1, 8), | ||
1815 | 482 | "Import error on 1.8") | ||
1816 | 482 | class OfflineGenerationJingoTestCase(OfflineTestCaseMixin, TestCase): | 483 | class OfflineGenerationJingoTestCase(OfflineTestCaseMixin, TestCase): |
1817 | 483 | templates_dir = "test_jingo" | 484 | templates_dir = "test_jingo" |
1818 | 484 | expected_hash = "61ec584468eb" | 485 | expected_hash = "61ec584468eb" |
1819 | 485 | 486 | ||
1820 | === modified file 'compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html' | |||
1821 | --- compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html 2014-06-26 15:08:13 +0000 | |||
1822 | +++ compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html 2015-08-20 18:49:21 +0000 | |||
1823 | @@ -5,4 +5,9 @@ | |||
1824 | 5 | <script type="text/javascript"> | 5 | <script type="text/javascript"> |
1825 | 6 | alert("this alert shouldn't be alone!"); | 6 | alert("this alert shouldn't be alone!"); |
1826 | 7 | </script> | 7 | </script> |
1827 | 8 | {% block orphan %} | ||
1828 | 9 | {{ block.super }} | ||
1829 | 10 | An 'orphan' block that refers to a non-existent super block. | ||
1830 | 11 | Contents of this block are ignored. | ||
1831 | 12 | {% endblock %} | ||
1832 | 8 | {% endspaceless %}{% endblock %} | 13 | {% endspaceless %}{% endblock %} |
1833 | 9 | 14 | ||
1834 | === modified file 'compressor/utils/staticfiles.py' | |||
1835 | --- compressor/utils/staticfiles.py 2014-06-26 15:08:13 +0000 | |||
1836 | +++ compressor/utils/staticfiles.py 2015-08-20 18:49:21 +0000 | |||
1837 | @@ -4,20 +4,10 @@ | |||
1838 | 4 | 4 | ||
1839 | 5 | from compressor.conf import settings | 5 | from compressor.conf import settings |
1840 | 6 | 6 | ||
1855 | 7 | INSTALLED = ("staticfiles" in settings.INSTALLED_APPS or | 7 | if "django.contrib.staticfiles" in settings.INSTALLED_APPS: |
1856 | 8 | "django.contrib.staticfiles" in settings.INSTALLED_APPS) | 8 | from django.contrib.staticfiles import finders # noqa |
1857 | 9 | 9 | ||
1858 | 10 | if INSTALLED: | 10 | if ("compressor.finders.CompressorFinder" |
1845 | 11 | if "django.contrib.staticfiles" in settings.INSTALLED_APPS: | ||
1846 | 12 | from django.contrib.staticfiles import finders | ||
1847 | 13 | else: | ||
1848 | 14 | try: | ||
1849 | 15 | from staticfiles import finders # noqa | ||
1850 | 16 | except ImportError: | ||
1851 | 17 | # Old (pre 1.0) and incompatible version of staticfiles | ||
1852 | 18 | INSTALLED = False | ||
1853 | 19 | |||
1854 | 20 | if (INSTALLED and "compressor.finders.CompressorFinder" | ||
1859 | 21 | not in settings.STATICFILES_FINDERS): | 11 | not in settings.STATICFILES_FINDERS): |
1860 | 22 | raise ImproperlyConfigured( | 12 | raise ImproperlyConfigured( |
1861 | 23 | "When using Django Compressor together with staticfiles, " | 13 | "When using Django Compressor together with staticfiles, " |
1862 | 24 | 14 | ||
1863 | === modified file 'debian/changelog' | |||
1864 | --- debian/changelog 2015-01-06 14:31:34 +0000 | |||
1865 | +++ debian/changelog 2015-08-20 18:49:21 +0000 | |||
1866 | @@ -1,3 +1,23 @@ | |||
1867 | 1 | python-django-compressor (1.5-1ubuntu1) UNRELEASED; urgency=low | ||
1868 | 2 | |||
1869 | 3 | * Merge from Debian unstable. Remaining changes: | ||
1870 | 4 | - d/control: Drop BD on python-coffin. | ||
1871 | 5 | - d/p/disable-coffin-tests.patch: Rebase. | ||
1872 | 6 | * Fix d/watch | ||
1873 | 7 | |||
1874 | 8 | -- David Ames <david.ames@canonical.com> Tue, 04 Aug 2015 16:11:41 +0000 | ||
1875 | 9 | |||
1876 | 10 | python-django-compressor (1.5-1) unstable; urgency=medium | ||
1877 | 11 | |||
1878 | 12 | * New upstream release. | ||
1879 | 13 | * Added Python 3 support. | ||
1880 | 14 | * Removed django 1.7 patche. | ||
1881 | 15 | * Added patch to not run a unit test that fails: | ||
1882 | 16 | - compressor.tests.test_base.JsAsyncDeferTestCase | ||
1883 | 17 | * Fixed PyPi watch file. | ||
1884 | 18 | |||
1885 | 19 | -- Thomas Goirand <zigo@debian.org> Tue, 04 Aug 2015 08:17:03 +0000 | ||
1886 | 20 | |||
1887 | 1 | python-django-compressor (1.4-2ubuntu3) vivid; urgency=medium | 21 | python-django-compressor (1.4-2ubuntu3) vivid; urgency=medium |
1888 | 2 | 22 | ||
1889 | 3 | * d/control: Drop BD on python-coffin. | 23 | * d/control: Drop BD on python-coffin. |
1890 | 4 | 24 | ||
1891 | === modified file 'debian/control' | |||
1892 | --- debian/control 2015-01-06 14:31:34 +0000 | |||
1893 | +++ debian/control 2015-08-20 18:49:21 +0000 | |||
1894 | @@ -5,34 +5,66 @@ | |||
1895 | 5 | XSBC-Original-Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org> | 5 | XSBC-Original-Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org> |
1896 | 6 | Uploaders: Thomas Goirand <zigo@debian.org>, | 6 | Uploaders: Thomas Goirand <zigo@debian.org>, |
1897 | 7 | Build-Depends: debhelper (>= 9), | 7 | Build-Depends: debhelper (>= 9), |
1898 | 8 | dh-python, | ||
1899 | 8 | openstack-pkg-tools, | 9 | openstack-pkg-tools, |
1903 | 9 | python-all (>= 2.6.6-3~), | 10 | python-all, |
1904 | 10 | python-setuptools | 11 | python-setuptools, |
1905 | 11 | Build-Depends-Indep: python-appconf, | 12 | python3-all, |
1906 | 13 | python3-setuptools | ||
1907 | 14 | Build-Depends-Indep: csstidy, | ||
1908 | 15 | python-appconf, | ||
1909 | 12 | python-bs4, | 16 | python-bs4, |
1910 | 13 | python-coverage, | 17 | python-coverage, |
1912 | 14 | python-django (>= 1.6), | 18 | python-django, |
1913 | 19 | python-django-discover-runner, | ||
1914 | 15 | python-html5lib, | 20 | python-html5lib, |
1915 | 16 | python-jingo, | 21 | python-jingo, |
1916 | 17 | python-jinja2, | 22 | python-jinja2, |
1917 | 18 | python-lxml, | 23 | python-lxml, |
1918 | 19 | python-mock, | 24 | python-mock, |
1919 | 20 | python-nose, | 25 | python-nose, |
1922 | 21 | python-unittest2 | 26 | python-unittest2, |
1923 | 22 | Standards-Version: 3.9.5 | 27 | python3-appconf, |
1924 | 28 | python3-bs4, | ||
1925 | 29 | python3-coverage, | ||
1926 | 30 | python3-django, | ||
1927 | 31 | python3-django-discover-runner, | ||
1928 | 32 | python3-html5lib, | ||
1929 | 33 | python3-jingo, | ||
1930 | 34 | python3-jinja2, | ||
1931 | 35 | python3-lxml, | ||
1932 | 36 | python3-mock, | ||
1933 | 37 | python3-nose, | ||
1934 | 38 | python3-unittest2 | ||
1935 | 39 | Standards-Version: 3.9.6 | ||
1936 | 23 | Vcs-Browser: http://anonscm.debian.org/gitweb/?p=openstack/python-django-compressor.git;a=summary | 40 | Vcs-Browser: http://anonscm.debian.org/gitweb/?p=openstack/python-django-compressor.git;a=summary |
1937 | 24 | Vcs-Git: git://anonscm.debian.org/openstack/python-django-compressor.git | 41 | Vcs-Git: git://anonscm.debian.org/openstack/python-django-compressor.git |
1938 | 25 | Homepage: http://pypi.python.org/pypi/django_compressor/ | 42 | Homepage: http://pypi.python.org/pypi/django_compressor/ |
1939 | 26 | 43 | ||
1940 | 27 | Package: python-compressor | 44 | Package: python-compressor |
1941 | 28 | Architecture: all | 45 | Architecture: all |
1942 | 29 | Pre-Depends: dpkg (>= 1.15.6~) | ||
1943 | 30 | Depends: python-appconf, | 46 | Depends: python-appconf, |
1945 | 31 | python-django (>= 1.1), | 47 | python-django, |
1946 | 32 | ${misc:Depends}, | 48 | ${misc:Depends}, |
1947 | 33 | ${python:Depends} | 49 | ${python:Depends} |
1948 | 34 | Provides: ${python:Provides} | 50 | Provides: ${python:Provides} |
1953 | 35 | Description: Compresses linked and inline JavaScript or CSS into single cached files | 51 | Description: Compresses linked, inline JS or CSS into single cached files - Python 2.7 |
1954 | 36 | Django Compressor combines and compresses linked and inline Javascript or CSS | 52 | Django Compressor combines and compresses linked and inline Javascript or CSS |
1955 | 37 | in a Django templates into cacheable static files by using the compress | 53 | in a Django templates into cacheable static files by using the compress |
1956 | 38 | template tag. | 54 | template tag. |
1957 | 55 | . | ||
1958 | 56 | This package contains the Python 2.7 module. | ||
1959 | 57 | |||
1960 | 58 | Package: python3-compressor | ||
1961 | 59 | Architecture: all | ||
1962 | 60 | Depends: python3-appconf, | ||
1963 | 61 | python3-django, | ||
1964 | 62 | ${misc:Depends}, | ||
1965 | 63 | ${python3:Depends} | ||
1966 | 64 | Provides: ${python:Provides} | ||
1967 | 65 | Description: Compresses linked, inline JS or CSS into single cached files - Python 3.x | ||
1968 | 66 | Django Compressor combines and compresses linked and inline Javascript or CSS | ||
1969 | 67 | in a Django templates into cacheable static files by using the compress | ||
1970 | 68 | template tag. | ||
1971 | 69 | . | ||
1972 | 70 | This package contains the Python 3.x module. | ||
1973 | 39 | 71 | ||
1974 | === modified file 'debian/gbp.conf' | |||
1975 | --- debian/gbp.conf 2013-05-12 15:20:14 +0000 | |||
1976 | +++ debian/gbp.conf 2015-08-20 18:49:21 +0000 | |||
1977 | @@ -4,5 +4,5 @@ | |||
1978 | 4 | upstream-tag = %(version)s | 4 | upstream-tag = %(version)s |
1979 | 5 | compression = xz | 5 | compression = xz |
1980 | 6 | 6 | ||
1982 | 7 | [git-buildpackage] | 7 | [buildpackage] |
1983 | 8 | export-dir = ../build-area/ | 8 | export-dir = ../build-area/ |
1984 | 9 | 9 | ||
1985 | === modified file 'debian/patches/disable-coffin-tests.patch' | |||
1986 | --- debian/patches/disable-coffin-tests.patch 2015-01-06 12:34:51 +0000 | |||
1987 | +++ debian/patches/disable-coffin-tests.patch 2015-08-20 18:49:21 +0000 | |||
1988 | @@ -1,20 +1,20 @@ | |||
1989 | 1 | --- a/compressor/test_settings.py | 1 | --- a/compressor/test_settings.py |
1990 | 2 | +++ b/compressor/test_settings.py | 2 | +++ b/compressor/test_settings.py |
1993 | 3 | @@ -14,7 +14,6 @@ DATABASES = { | 3 | @@ -21,7 +21,6 @@ |
1992 | 4 | |||
1994 | 5 | INSTALLED_APPS = [ | 4 | INSTALLED_APPS = [ |
1995 | 5 | 'django.contrib.staticfiles', | ||
1996 | 6 | 'compressor', | 6 | 'compressor', |
1997 | 7 | - 'coffin', | 7 | - 'coffin', |
1998 | 8 | 'jingo', | ||
1999 | 9 | ] | 8 | ] |
2001 | 10 | 9 | if django.VERSION < (1, 8): | |
2002 | 10 | INSTALLED_APPS.append('jingo') | ||
2003 | 11 | --- a/compressor/tests/test_offline.py | 11 | --- a/compressor/tests/test_offline.py |
2004 | 12 | +++ b/compressor/tests/test_offline.py | 12 | +++ b/compressor/tests/test_offline.py |
2006 | 13 | @@ -452,6 +452,7 @@ class OfflineGenerationComplexTestCase(O | 13 | @@ -450,6 +450,7 @@ |
2007 | 14 | # from library import * | 14 | # from library import * |
2008 | 15 | # causing 'ImportError: No module named library'. | 15 | # causing 'ImportError: No module named library'. |
2009 | 16 | # It seems there is no evidence nor indicated support for Python 3+. | 16 | # It seems there is no evidence nor indicated support for Python 3+. |
2010 | 17 | +@unittest.skip("Coffin tests disable under Ubuntu build") | 17 | +@unittest.skip("Coffin tests disable under Ubuntu build") |
2011 | 18 | @unittest.skipIf(sys.version_info >= (3, 2), | 18 | @unittest.skipIf(sys.version_info >= (3, 2), |
2012 | 19 | "Coffin does not support 3.2+") | 19 | "Coffin does not support 3.2+") |
2014 | 20 | class OfflineGenerationCoffinTestCase(OfflineTestCaseMixin, TestCase): | 20 | @unittest.skipIf(django.VERSION >= (1, 8), |
2015 | 21 | 21 | ||
2016 | === removed file 'debian/patches/fix-test_settings.py-for-django-1.7.patch' | |||
2017 | --- debian/patches/fix-test_settings.py-for-django-1.7.patch 2014-09-08 17:31:54 +0000 | |||
2018 | +++ debian/patches/fix-test_settings.py-for-django-1.7.patch 1970-01-01 00:00:00 +0000 | |||
2019 | @@ -1,16 +0,0 @@ | |||
2020 | 1 | Description: Fix test_settings.py for Django 1.7 compat | ||
2021 | 2 | Author: Thomas Goirand <zigo@debian.org> | ||
2022 | 3 | Forwarded: no | ||
2023 | 4 | Last-Update: 2014-09-09 | ||
2024 | 5 | |||
2025 | 6 | --- python-django-compressor-1.4.orig/compressor/test_settings.py | ||
2026 | 7 | +++ python-django-compressor-1.4/compressor/test_settings.py | ||
2027 | 8 | @@ -3,7 +3,7 @@ import django | ||
2028 | 9 | |||
2029 | 10 | TEST_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'tests') | ||
2030 | 11 | |||
2031 | 12 | -COMPRESS_CACHE_BACKEND = 'locmem://' | ||
2032 | 13 | +COMPRESS_CACHE_BACKEND = 'django.core.cache.backends.locmem.CacheClass' | ||
2033 | 14 | |||
2034 | 15 | DATABASES = { | ||
2035 | 16 | 'default': { | ||
2036 | 17 | 0 | ||
2037 | === added file 'debian/patches/remove-failed-test.patch' | |||
2038 | --- debian/patches/remove-failed-test.patch 1970-01-01 00:00:00 +0000 | |||
2039 | +++ debian/patches/remove-failed-test.patch 2015-08-20 18:49:21 +0000 | |||
2040 | @@ -0,0 +1,43 @@ | |||
2041 | 1 | Description: Removes failed test | ||
2042 | 2 | This unit test is failing, so removing it to build the package. | ||
2043 | 3 | Author: Thomas Goirand <zigo@debian.org> | ||
2044 | 4 | Forwarded: no | ||
2045 | 5 | Last-Update: 2015-08-04 | ||
2046 | 6 | |||
2047 | 7 | --- python-django-compressor-1.5.orig/compressor/tests/test_base.py | ||
2048 | 8 | +++ python-django-compressor-1.5/compressor/tests/test_base.py | ||
2049 | 9 | @@ -288,34 +288,6 @@ class CacheBackendTestCase(CompressorTes | ||
2050 | 10 | self.assertEqual(cache.__class__, locmem.LocMemCache) | ||
2051 | 11 | |||
2052 | 12 | |||
2053 | 13 | -class JsAsyncDeferTestCase(SimpleTestCase): | ||
2054 | 14 | - def setUp(self): | ||
2055 | 15 | - self.js = """\ | ||
2056 | 16 | - <script src="/static/js/one.js" type="text/javascript"></script> | ||
2057 | 17 | - <script src="/static/js/two.js" type="text/javascript" async></script> | ||
2058 | 18 | - <script src="/static/js/three.js" type="text/javascript" defer></script> | ||
2059 | 19 | - <script type="text/javascript">obj.value = "value";</script> | ||
2060 | 20 | - <script src="/static/js/one.js" type="text/javascript" async></script> | ||
2061 | 21 | - <script src="/static/js/two.js" type="text/javascript" async></script> | ||
2062 | 22 | - <script src="/static/js/three.js" type="text/javascript"></script>""" | ||
2063 | 23 | - | ||
2064 | 24 | - def test_js_output(self): | ||
2065 | 25 | - def extract_attr(tag): | ||
2066 | 26 | - if tag.has_attr('async'): | ||
2067 | 27 | - return 'async' | ||
2068 | 28 | - if tag.has_attr('defer'): | ||
2069 | 29 | - return 'defer' | ||
2070 | 30 | - js_node = JsCompressor(self.js) | ||
2071 | 31 | - output = [None, 'async', 'defer', None, 'async', None] | ||
2072 | 32 | - if six.PY3: | ||
2073 | 33 | - scripts = make_soup(js_node.output()).find_all('script') | ||
2074 | 34 | - attrs = [extract_attr(i) for i in scripts] | ||
2075 | 35 | - else: | ||
2076 | 36 | - scripts = make_soup(js_node.output()).findAll('script') | ||
2077 | 37 | - attrs = [s.get('async') or s.get('defer') for s in scripts] | ||
2078 | 38 | - self.assertEqual(output, attrs) | ||
2079 | 39 | - | ||
2080 | 40 | - | ||
2081 | 41 | class CacheTestCase(SimpleTestCase): | ||
2082 | 42 | |||
2083 | 43 | def setUp(self): | ||
2084 | 0 | 44 | ||
2085 | === modified file 'debian/patches/series' | |||
2086 | --- debian/patches/series 2015-01-06 12:34:51 +0000 | |||
2087 | +++ debian/patches/series 2015-08-20 18:49:21 +0000 | |||
2088 | @@ -1,2 +1,2 @@ | |||
2089 | 1 | fix-test_settings.py-for-django-1.7.patch | ||
2090 | 2 | disable-coffin-tests.patch | 1 | disable-coffin-tests.patch |
2091 | 2 | remove-failed-test.patch | ||
2092 | 3 | 3 | ||
2093 | === modified file 'debian/rules' | |||
2094 | --- debian/rules 2014-12-05 10:34:59 +0000 | |||
2095 | +++ debian/rules 2015-08-20 18:49:21 +0000 | |||
2096 | @@ -1,13 +1,14 @@ | |||
2097 | 1 | #!/usr/bin/make -f | 1 | #!/usr/bin/make -f |
2098 | 2 | 2 | ||
2100 | 3 | #export DH_VERBOSE=1 | 3 | PYTHONS:=$(shell pyversions -vr) |
2101 | 4 | PYTHON3S:=$(shell py3versions -vr) | ||
2102 | 4 | 5 | ||
2103 | 5 | UPSTREAM_GIT = git://github.com/jezdez/django_compressor.git | 6 | UPSTREAM_GIT = git://github.com/jezdez/django_compressor.git |
2104 | 6 | 7 | ||
2105 | 7 | include /usr/share/openstack-pkg-tools/pkgos.make | 8 | include /usr/share/openstack-pkg-tools/pkgos.make |
2106 | 8 | 9 | ||
2107 | 9 | %: | 10 | %: |
2109 | 10 | dh $@ --with python2 | 11 | dh $@ --buildsystem=python_distutils --with python2,python3 |
2110 | 11 | 12 | ||
2111 | 12 | override_dh_clean: | 13 | override_dh_clean: |
2112 | 13 | dh_clean | 14 | dh_clean |
2113 | @@ -15,24 +16,27 @@ | |||
2114 | 15 | 16 | ||
2115 | 16 | override_dh_auto_test: | 17 | override_dh_auto_test: |
2116 | 17 | ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS))) | 18 | ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS))) |
2119 | 18 | PYTHONPATH=. python-coverage run --branch --source=compressor /usr/bin/django-admin test --settings=compressor.test_settings compressor | 19 | PYTHON=python2 PYTHONPATH=. python-coverage run --branch --source=compressor /usr/bin/django-admin test --settings=compressor.test_settings compressor |
2118 | 19 | #PYTHONPATH=$PYTHONPATH:. python /usr/share/pyshared/django/bin/django-admin.py test --settings=compressor.test_settings compressor || true | ||
2120 | 20 | rm -rf $(CURDIR)/compressor/tests/static/CACHE | 20 | rm -rf $(CURDIR)/compressor/tests/static/CACHE |
2121 | 21 | # TODO: make unit tests to work. | ||
2122 | 22 | # PYTHON=python3 PYTHONPATH=. python3-coverage run --branch --source=compressor /usr/bin/django-admin test --settings=compressor.test_settings compressor | ||
2123 | 23 | # rm -rf $(CURDIR)/compressor/tests/static/CACHE | ||
2124 | 21 | endif | 24 | endif |
2125 | 22 | 25 | ||
2126 | 23 | override_dh_auto_build: | 26 | override_dh_auto_build: |
2127 | 24 | 27 | ||
2128 | 25 | override_dh_install: | 28 | override_dh_install: |
2139 | 26 | set -e ; for i in `pyversions -s` ; do \ | 29 | set -e ; for pyvers in $(PYTHONS); do \ |
2140 | 27 | $$i setup.py install --install-layout=deb --root=debian/python-compressor ; \ | 30 | python$$pyvers setup.py install --install-layout=deb \ |
2141 | 28 | rm -f $(CURDIR)/debian/usr/lib/$$i/dist-packages/compressor/tests/static/CACHE/css/* ; \ | 31 | --root $(CURDIR)/debian/python-compressor; \ |
2142 | 29 | rm -f $(CURDIR)/debian/usr/lib/$$i/dist-packages/compressor/tests/static/CACHE/js/* ; \ | 32 | done |
2143 | 30 | done | 33 | set -e ; for pyvers in $(PYTHON3S); do \ |
2144 | 31 | find debian/python-compressor -iname '*.pyc' -delete | 34 | python$$pyvers setup.py install --install-layout=deb \ |
2145 | 32 | 35 | --root $(CURDIR)/debian/python3-compressor; \ | |
2146 | 33 | override_dh_usrlocal: | 36 | done |
2147 | 34 | rm -f $(CURDIR)/debian/usr/share/pyshared/compressor/tests/static/CACHE/css/* | 37 | rm -f $(CURDIR)/debian/usr/lib/python*/dist-packages/compressor/tests/static/CACHE/css/* |
2148 | 35 | rm -f $(CURDIR)/debian/usr/share/pyshared/compressor/tests/static/CACHE/js/* | 38 | rm -f $(CURDIR)/debian/usr/lib/python*/dist-packages/compressor/tests/static/CACHE/js/* |
2149 | 39 | find debian -iname '*.pyc' -delete | ||
2150 | 36 | 40 | ||
2151 | 37 | # Commands not to run | 41 | # Commands not to run |
2152 | 38 | override_dh_installcatalogs: | 42 | override_dh_installcatalogs: |
2153 | 39 | 43 | ||
2154 | === modified file 'debian/watch' | |||
2155 | --- debian/watch 2012-10-14 10:51:47 +0000 | |||
2156 | +++ debian/watch 2015-08-20 18:49:21 +0000 | |||
2157 | @@ -1,2 +1,3 @@ | |||
2158 | 1 | version=3 | 1 | version=3 |
2160 | 2 | http://pypi.python.org/packages/source/d/django-compressor/django-compressor-(.*)\.tar.gz | 2 | opts=uversionmangle=s/(rc|a|b|c)/~$1/ \ |
2161 | 3 | http://pypi.debian.net/django_compressor/django_compressor-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) | ||
2162 | 3 | 4 | ||
2163 | === modified file 'docs/changelog.txt' | |||
2164 | --- docs/changelog.txt 2015-01-06 14:31:34 +0000 | |||
2165 | +++ docs/changelog.txt 2015-08-20 18:49:21 +0000 | |||
2166 | @@ -1,12 +1,46 @@ | |||
2167 | 1 | Changelog | 1 | Changelog |
2168 | 2 | ========= | 2 | ========= |
2169 | 3 | 3 | ||
2172 | 4 | v1.4 | 4 | v1.5 (03/27/2015) |
2173 | 5 | ---- | 5 | ----------------- |
2174 | 6 | |||
2175 | 7 | `Full Changelog <https://github.com/django-compressor/django-compressor/compare/1.4...HEAD>`_ | ||
2176 | 8 | |||
2177 | 9 | - Fix compress command and run automated tests for Django 1.8 | ||
2178 | 10 | |||
2179 | 11 | - Fix Django 1.8 warnings | ||
2180 | 12 | |||
2181 | 13 | - Handle TypeError from import_module | ||
2182 | 14 | |||
2183 | 15 | - Fix reading UTF-8 files which have BOM | ||
2184 | 16 | |||
2185 | 17 | - Fix incompatibility with Windows (shell_quote is not supported) | ||
2186 | 18 | |||
2187 | 19 | - Run automated tests on Django 1.7 | ||
2188 | 20 | |||
2189 | 21 | - Ignore non-existent {{ block.super }} in offline compression instead of raising AttributeError | ||
2190 | 22 | |||
2191 | 23 | - Support for clean-css | ||
2192 | 24 | |||
2193 | 25 | - Fix link markup | ||
2194 | 26 | |||
2195 | 27 | - Add support for COMPRESS_CSS_HASHING_METHOD = None | ||
2196 | 28 | |||
2197 | 29 | - Remove compatibility with old 'staticfiles' app | ||
2198 | 30 | |||
2199 | 31 | - In compress command, use get_template() instead of opening template files manually, fixing compatibility issues with custom template loaders | ||
2200 | 32 | |||
2201 | 33 | - Fix FilterBase so that does not override self.type for subclasses if filter_type is not specified at init | ||
2202 | 34 | |||
2203 | 35 | - Remove unnecessary filename and existence checks in CssAbsoluteFilter | ||
2204 | 36 | |||
2205 | 37 | |||
2206 | 38 | v1.4 (06/20/2014) | ||
2207 | 39 | ----------------- | ||
2208 | 6 | 40 | ||
2209 | 7 | - Added Python 3 compatibility. | 41 | - Added Python 3 compatibility. |
2210 | 8 | 42 | ||
2212 | 9 | - Added compatibility with Django 1.6.x. | 43 | - Added compatibility with Django 1.6.x and dropped support for Django 1.3.X. |
2213 | 10 | 44 | ||
2214 | 11 | - Fixed compatibility with html5lib 1.0. | 45 | - Fixed compatibility with html5lib 1.0. |
2215 | 12 | 46 | ||
2216 | @@ -46,7 +80,7 @@ | |||
2217 | 46 | - Dropped support for Python 2.5. Removed ``any`` and ``walk`` compatibility | 80 | - Dropped support for Python 2.5. Removed ``any`` and ``walk`` compatibility |
2218 | 47 | functions in ``compressor.utils``. | 81 | functions in ``compressor.utils``. |
2219 | 48 | 82 | ||
2221 | 49 | - Removed compatibility with Django 1.2 for default values of some settings: | 83 | - Removed compatibility with some old django setttings: |
2222 | 50 | 84 | ||
2223 | 51 | - :attr:`~COMPRESS_ROOT` no longer uses ``MEDIA_ROOT`` if ``STATIC_ROOT`` is | 85 | - :attr:`~COMPRESS_ROOT` no longer uses ``MEDIA_ROOT`` if ``STATIC_ROOT`` is |
2224 | 52 | not defined. It expects ``STATIC_ROOT`` to be defined instead. | 86 | not defined. It expects ``STATIC_ROOT`` to be defined instead. |
2225 | 53 | 87 | ||
2226 | === modified file 'docs/contributing.txt' | |||
2227 | --- docs/contributing.txt 2015-01-06 14:31:34 +0000 | |||
2228 | +++ docs/contributing.txt 2015-08-20 18:49:21 +0000 | |||
2229 | @@ -9,11 +9,12 @@ | |||
2230 | 9 | Community | 9 | Community |
2231 | 10 | --------- | 10 | --------- |
2232 | 11 | 11 | ||
2235 | 12 | People interested in developing for the Django Compressor should head | 12 | People interested in developing for the Django Compressor should: |
2236 | 13 | over to #django-compressor on the `freenode`_ IRC network for help and to | 13 | |
2237 | 14 | 1. Head over to #django-compressor on the `freenode`_ IRC network for help and to | ||
2238 | 14 | discuss the development. | 15 | discuss the development. |
2239 | 16 | 2. Open an issue on GitHub explaining your ideas. | ||
2240 | 15 | 17 | ||
2241 | 16 | You may also be interested in following `@jezdez`_ on Twitter. | ||
2242 | 17 | 18 | ||
2243 | 18 | In a nutshell | 19 | In a nutshell |
2244 | 19 | ------------- | 20 | ------------- |
2245 | @@ -143,7 +144,7 @@ | |||
2246 | 143 | - Accessible. You should assume the reader to be moderately familiar with | 144 | - Accessible. You should assume the reader to be moderately familiar with |
2247 | 144 | Python and Django, but not anything else. Link to documentation of libraries | 145 | Python and Django, but not anything else. Link to documentation of libraries |
2248 | 145 | you use, for example, even if they are "obvious" to you. A brief | 146 | you use, for example, even if they are "obvious" to you. A brief |
2250 | 146 | description of what it does is also welcome. | 147 | description of what it does is also welcome. |
2251 | 147 | 148 | ||
2252 | 148 | Pulling of documentation is pretty fast and painless. Usually somebody goes | 149 | Pulling of documentation is pretty fast and painless. Usually somebody goes |
2253 | 149 | over your text and merges it, since there are no "breaks" and that github | 150 | over your text and merges it, since there are no "breaks" and that github |
2254 | 150 | 151 | ||
2255 | === modified file 'docs/django-sekizai.txt' | |||
2256 | --- docs/django-sekizai.txt 2015-01-06 14:31:34 +0000 | |||
2257 | +++ docs/django-sekizai.txt 2015-08-20 18:49:21 +0000 | |||
2258 | @@ -3,12 +3,12 @@ | |||
2259 | 3 | django-sekizai Support | 3 | django-sekizai Support |
2260 | 4 | ====================== | 4 | ====================== |
2261 | 5 | 5 | ||
2264 | 6 | Django Compressor comes with support for _django-sekizai via an extension. | 6 | Django Compressor comes with support for django-sekizai_ via an extension. |
2265 | 7 | _django-sekizai provides the ability to include template code, from within | 7 | django-sekizai provides the ability to include template code, from within |
2266 | 8 | any block, to a parent block. It is primarily used to include js/css from | 8 | any block, to a parent block. It is primarily used to include js/css from |
2267 | 9 | included templates to the master template. | 9 | included templates to the master template. |
2268 | 10 | 10 | ||
2270 | 11 | It requires _django-sekizai to installed. Refer to the _django-sekizai _docs | 11 | It requires django-sekizai to be installed. Refer to the `django-sekizai docs`_ |
2271 | 12 | for how to use ``render_block`` | 12 | for how to use ``render_block`` |
2272 | 13 | 13 | ||
2273 | 14 | Usage | 14 | Usage |
2274 | @@ -21,4 +21,4 @@ | |||
2275 | 21 | 21 | ||
2276 | 22 | 22 | ||
2277 | 23 | .. _django-sekizai: https://github.com/ojii/django-sekizai | 23 | .. _django-sekizai: https://github.com/ojii/django-sekizai |
2279 | 24 | .. _docs: http://django-sekizai.readthedocs.org/en/latest/ | 24 | .. _django-sekizai docs: http://django-sekizai.readthedocs.org/en/latest/ |
2280 | 25 | 25 | ||
2281 | === modified file 'docs/jinja2.txt' | |||
2282 | --- docs/jinja2.txt 2015-01-06 14:31:34 +0000 | |||
2283 | +++ docs/jinja2.txt 2015-08-20 18:49:21 +0000 | |||
2284 | @@ -42,13 +42,13 @@ | |||
2285 | 42 | ================================== | 42 | ================================== |
2286 | 43 | You'd need to configure ``COMPRESS_JINJA2_GET_ENVIRONMENT`` so that | 43 | You'd need to configure ``COMPRESS_JINJA2_GET_ENVIRONMENT`` so that |
2287 | 44 | Compressor can retrieve the Jinja2 environment for rendering. | 44 | Compressor can retrieve the Jinja2 environment for rendering. |
2289 | 45 | This can be a lamda or function that returns a Jinja2 environment. | 45 | This can be a lambda or function that returns a Jinja2 environment. |
2290 | 46 | 46 | ||
2291 | 47 | Usage | 47 | Usage |
2292 | 48 | ----- | 48 | ----- |
2294 | 49 | Run the following compress command along with an ``-engine`` parameter. The | 49 | Run the following compress command along with an ``--engine`` parameter. The |
2295 | 50 | parameter can be either jinja2 or django (default). For example, | 50 | parameter can be either jinja2 or django (default). For example, |
2297 | 51 | "./manage.py compress -engine jinja2". | 51 | ``./manage.py compress --engine jinja2``. |
2298 | 52 | 52 | ||
2299 | 53 | Using both Django and Jinja2 templates | 53 | Using both Django and Jinja2 templates |
2300 | 54 | -------------------------------------- | 54 | -------------------------------------- |
2301 | @@ -60,9 +60,9 @@ | |||
2302 | 60 | 60 | ||
2303 | 61 | A typical usage could be : | 61 | A typical usage could be : |
2304 | 62 | 62 | ||
2306 | 63 | - "./manage.py compress" for processing Django templates first, skipping | 63 | - ``./manage.py compress`` for processing Django templates first, skipping |
2307 | 64 | Jinja2 templates. | 64 | Jinja2 templates. |
2309 | 65 | - "./manage.py compress -engine jinja2" for processing Jinja2 templates, | 65 | - ``./manage.py compress --engine jinja2`` for processing Jinja2 templates, |
2310 | 66 | skipping Django templates. | 66 | skipping Django templates. |
2311 | 67 | 67 | ||
2312 | 68 | However, it is still recommended that you do not mix Django and Jinja2 | 68 | However, it is still recommended that you do not mix Django and Jinja2 |
2313 | @@ -172,4 +172,3 @@ | |||
2314 | 172 | .. _Jinja2: http://jinja.pocoo.org/docs/ | 172 | .. _Jinja2: http://jinja.pocoo.org/docs/ |
2315 | 173 | .. _Coffin: http://pypi.python.org/pypi/Coffin | 173 | .. _Coffin: http://pypi.python.org/pypi/Coffin |
2316 | 174 | .. _Jingo: https://jingo.readthedocs.org/en/latest/ | 174 | .. _Jingo: https://jingo.readthedocs.org/en/latest/ |
2317 | 175 | |||
2318 | 176 | 175 | ||
2319 | === modified file 'docs/quickstart.txt' | |||
2320 | --- docs/quickstart.txt 2015-01-06 14:31:34 +0000 | |||
2321 | +++ docs/quickstart.txt 2015-08-20 18:49:21 +0000 | |||
2322 | @@ -18,10 +18,8 @@ | |||
2323 | 18 | * See the list of :ref:`settings` to modify Django Compressor's | 18 | * See the list of :ref:`settings` to modify Django Compressor's |
2324 | 19 | default behaviour and make adjustments for your website. | 19 | default behaviour and make adjustments for your website. |
2325 | 20 | 20 | ||
2330 | 21 | * In case you use Django's staticfiles_ contrib app (or its standalone | 21 | * In case you use Django's staticfiles_ contrib app you have to add Django |
2331 | 22 | counterpart django-staticfiles_) you have to add Django Compressor's file | 22 | Compressor's file finder to the ``STATICFILES_FINDERS`` setting, like this: |
2328 | 23 | finder to the ``STATICFILES_FINDERS`` setting, for example with | ||
2329 | 24 | ``django.contrib.staticfiles``: | ||
2332 | 25 | 23 | ||
2333 | 26 | .. code-block:: python | 24 | .. code-block:: python |
2334 | 27 | 25 | ||
2335 | @@ -95,6 +93,6 @@ | |||
2336 | 95 | .. _lxml: http://codespeak.net/lxml/ | 93 | .. _lxml: http://codespeak.net/lxml/ |
2337 | 96 | .. _libxml2: http://xmlsoft.org/ | 94 | .. _libxml2: http://xmlsoft.org/ |
2338 | 97 | .. _html5lib: http://code.google.com/p/html5lib/ | 95 | .. _html5lib: http://code.google.com/p/html5lib/ |
2340 | 98 | .. _`Slim It`: http://slimit.org/ | 96 | .. _`Slim It`: https://github.com/rspivak/slimit |
2341 | 99 | .. _django-appconf: http://pypi.python.org/pypi/django-appconf/ | 97 | .. _django-appconf: http://pypi.python.org/pypi/django-appconf/ |
2342 | 100 | .. _versiontools: http://pypi.python.org/pypi/versiontools/ | 98 | .. _versiontools: http://pypi.python.org/pypi/versiontools/ |
2343 | 101 | 99 | ||
2344 | === modified file 'docs/remote-storages.txt' | |||
2345 | --- docs/remote-storages.txt 2015-01-06 14:31:34 +0000 | |||
2346 | +++ docs/remote-storages.txt 2015-08-20 18:49:21 +0000 | |||
2347 | @@ -39,12 +39,11 @@ | |||
2348 | 39 | Using staticfiles | 39 | Using staticfiles |
2349 | 40 | ^^^^^^^^^^^^^^^^^ | 40 | ^^^^^^^^^^^^^^^^^ |
2350 | 41 | 41 | ||
2357 | 42 | If you are using Django's staticfiles_ contrib app or the standalone | 42 | If you are using Django's staticfiles_ contrib app, you'll need to use a |
2358 | 43 | app django-staticfiles_, you'll need to use a temporary filesystem cache | 43 | temporary filesystem cache for Django Compressor to know which files to |
2359 | 44 | for Django Compressor to know which files to compress. Since staticfiles | 44 | compress. Since staticfiles provides a management command to collect static |
2360 | 45 | provides a management command to collect static files from various | 45 | files from various locations which uses a storage backend, this is where both |
2361 | 46 | locations which uses a storage backend, this is where both apps can be | 46 | apps can be integrated. |
2356 | 47 | integrated. | ||
2362 | 48 | 47 | ||
2363 | 49 | #. Make sure the :attr:`~django.conf.settings.COMPRESS_ROOT` and STATIC_ROOT_ | 48 | #. Make sure the :attr:`~django.conf.settings.COMPRESS_ROOT` and STATIC_ROOT_ |
2364 | 50 | settings are equal since both apps need to look at the same directories | 49 | settings are equal since both apps need to look at the same directories |
2365 | @@ -84,7 +83,6 @@ | |||
2366 | 84 | .. _Amazon S3: https://s3.amazonaws.com/ | 83 | .. _Amazon S3: https://s3.amazonaws.com/ |
2367 | 85 | .. _boto: http://boto.cloudhackers.com/ | 84 | .. _boto: http://boto.cloudhackers.com/ |
2368 | 86 | .. _django-storages: http://code.welldev.org/django-storages/ | 85 | .. _django-storages: http://code.welldev.org/django-storages/ |
2369 | 87 | .. _django-staticfiles: http://github.com/jezdez/django-staticfiles/ | ||
2370 | 88 | .. _staticfiles: http://docs.djangoproject.com/en/dev/howto/static-files/ | 86 | .. _staticfiles: http://docs.djangoproject.com/en/dev/howto/static-files/ |
2371 | 89 | .. _STATIC_ROOT: http://docs.djangoproject.com/en/dev/ref/settings/#static-root | 87 | .. _STATIC_ROOT: http://docs.djangoproject.com/en/dev/ref/settings/#static-root |
2372 | 90 | .. _STATIC_URL: http://docs.djangoproject.com/en/dev/ref/settings/#static-url | 88 | .. _STATIC_URL: http://docs.djangoproject.com/en/dev/ref/settings/#static-url |
2373 | 91 | 89 | ||
2374 | === modified file 'docs/settings.txt' | |||
2375 | --- docs/settings.txt 2015-01-06 14:31:34 +0000 | |||
2376 | +++ docs/settings.txt 2015-08-20 18:49:21 +0000 | |||
2377 | @@ -81,10 +81,11 @@ | |||
2378 | 81 | 81 | ||
2379 | 82 | .. attribute:: COMPRESS_CSS_HASHING_METHOD | 82 | .. attribute:: COMPRESS_CSS_HASHING_METHOD |
2380 | 83 | 83 | ||
2385 | 84 | The method to use when calculating the hash to append to | 84 | The method to use when calculating the suffix to append to URLs in |
2386 | 85 | processed URLs. Either ``'mtime'`` (default) or ``'content'``. | 85 | your processed CSS files. Either ``None``, ``'mtime'`` (default) or |
2387 | 86 | Use the latter in case you're using multiple server to serve your | 86 | ``'content'``. Use the ``None`` if you want to completely disable that |
2388 | 87 | static files. | 87 | feature, and the ``'content'`` in case you're using multiple servers |
2389 | 88 | to serve your content. | ||
2390 | 88 | 89 | ||
2391 | 89 | - ``compressor.filters.csstidy.CSSTidyFilter`` | 90 | - ``compressor.filters.csstidy.CSSTidyFilter`` |
2392 | 90 | 91 | ||
2393 | @@ -136,9 +137,24 @@ | |||
2394 | 136 | A filter that uses Zachary Voase's Python port of the YUI CSS compression | 137 | A filter that uses Zachary Voase's Python port of the YUI CSS compression |
2395 | 137 | algorithm cssmin_. | 138 | algorithm cssmin_. |
2396 | 138 | 139 | ||
2397 | 140 | - ``compressor.filters.cleancss.CleanCSSFilter`` | ||
2398 | 141 | |||
2399 | 142 | A filter that passes the CSS content to the `clean-css`_ tool. | ||
2400 | 143 | |||
2401 | 144 | .. attribute:: CLEAN_CSS_BINARY | ||
2402 | 145 | |||
2403 | 146 | The clean-css binary filesystem path. | ||
2404 | 147 | |||
2405 | 148 | .. attribute:: CLEAN_CSS_ARGUMENTS | ||
2406 | 149 | |||
2407 | 150 | The arguments passed to clean-css. | ||
2408 | 151 | |||
2409 | 152 | |||
2410 | 139 | .. _CSSTidy: http://csstidy.sourceforge.net/ | 153 | .. _CSSTidy: http://csstidy.sourceforge.net/ |
2411 | 140 | .. _`data: URIs`: http://en.wikipedia.org/wiki/Data_URI_scheme | 154 | .. _`data: URIs`: http://en.wikipedia.org/wiki/Data_URI_scheme |
2412 | 141 | .. _cssmin: http://pypi.python.org/pypi/cssmin/ | 155 | .. _cssmin: http://pypi.python.org/pypi/cssmin/ |
2413 | 156 | .. _`clean-css`: https://github.com/GoalSmashers/clean-css/ | ||
2414 | 157 | |||
2415 | 142 | 158 | ||
2416 | 143 | - ``compressor.filters.template.TemplateFilter`` | 159 | - ``compressor.filters.template.TemplateFilter`` |
2417 | 144 | 160 | ||
2418 | @@ -220,7 +236,7 @@ | |||
2419 | 220 | .. _`Google Closure compiler`: http://code.google.com/closure/compiler/ | 236 | .. _`Google Closure compiler`: http://code.google.com/closure/compiler/ |
2420 | 221 | .. _`YUI compressor`: http://developer.yahoo.com/yui/compressor/ | 237 | .. _`YUI compressor`: http://developer.yahoo.com/yui/compressor/ |
2421 | 222 | .. _`yUglify compressor`: https://github.com/yui/yuglify | 238 | .. _`yUglify compressor`: https://github.com/yui/yuglify |
2423 | 223 | .. _`Slim It`: http://slimit.org/ | 239 | .. _`Slim It`: https://github.com/rspivak/slimit |
2424 | 224 | 240 | ||
2425 | 225 | .. attribute:: COMPRESS_PRECOMPILERS | 241 | .. attribute:: COMPRESS_PRECOMPILERS |
2426 | 226 | 242 | ||
2427 | @@ -305,7 +321,7 @@ | |||
2428 | 305 | <link rel="stylesheet" href="/static/CACHE/css/8ccf8d877f18.css" type="text/css" charset="utf-8"> | 321 | <link rel="stylesheet" href="/static/CACHE/css/8ccf8d877f18.css" type="text/css" charset="utf-8"> |
2429 | 306 | 322 | ||
2430 | 307 | .. _less: http://lesscss.org/ | 323 | .. _less: http://lesscss.org/ |
2432 | 308 | .. _CoffeeScript: http://jashkenas.github.com/coffee-script/ | 324 | .. _CoffeeScript: http://coffeescript.org/ |
2433 | 309 | 325 | ||
2434 | 310 | .. attribute:: COMPRESS_STORAGE | 326 | .. attribute:: COMPRESS_STORAGE |
2435 | 311 | 327 | ||
2436 | 312 | 328 | ||
2437 | === modified file 'docs/usage.txt' | |||
2438 | --- docs/usage.txt 2015-01-06 14:31:34 +0000 | |||
2439 | +++ docs/usage.txt 2015-08-20 18:49:21 +0000 | |||
2440 | @@ -48,7 +48,7 @@ | |||
2441 | 48 | 48 | ||
2442 | 49 | .. note:: | 49 | .. note:: |
2443 | 50 | 50 | ||
2445 | 51 | Remember that django-compressor will try to :ref:`group ouputs by media <css_notes>`. | 51 | Remember that django-compressor will try to :ref:`group outputs by media <css_notes>`. |
2446 | 52 | 52 | ||
2447 | 53 | Linked files **must** be accessible via | 53 | Linked files **must** be accessible via |
2448 | 54 | :attr:`~django.conf.settings.COMPRESS_URL`. | 54 | :attr:`~django.conf.settings.COMPRESS_URL`. |
2449 | 55 | 55 | ||
2450 | === modified file 'tox.ini' | |||
2451 | --- tox.ini 2014-06-26 15:08:13 +0000 | |||
2452 | +++ tox.ini 2015-08-20 18:49:21 +0000 | |||
2453 | @@ -33,89 +33,34 @@ | |||
2454 | 33 | 33 | ||
2455 | 34 | [tox] | 34 | [tox] |
2456 | 35 | envlist = | 35 | envlist = |
2468 | 36 | py33-1.6.X, | 36 | {py26,py27}-{1.4.X,1.5.X}, |
2469 | 37 | py32-1.6.X, | 37 | {py26,py27,py32,py33}-{1.6.X}, |
2470 | 38 | py27-1.6.X, | 38 | {py27,py32,py33,py34}-{1.7.X}, |
2471 | 39 | py26-1.6.X, | 39 | {py27,py32,py33,py34}-{1.8.X} |
2461 | 40 | py33-1.5.X, | ||
2462 | 41 | py32-1.5.X, | ||
2463 | 42 | py27-1.5.X, | ||
2464 | 43 | py26-1.5.X, | ||
2465 | 44 | py27-1.4.X, | ||
2466 | 45 | py26-1.4.X | ||
2467 | 46 | |||
2472 | 47 | [testenv] | 40 | [testenv] |
2473 | 41 | basepython = | ||
2474 | 42 | py26: python2.6 | ||
2475 | 43 | py27: python2.7 | ||
2476 | 44 | py32: python3.2 | ||
2477 | 45 | py33: python3.3 | ||
2478 | 46 | py34: python3.4 | ||
2479 | 47 | usedevelop = true | ||
2480 | 48 | setenv = | 48 | setenv = |
2481 | 49 | CPPFLAGS=-O0 | 49 | CPPFLAGS=-O0 |
2482 | 50 | usedevelop = true | ||
2483 | 51 | whitelist_externals = /usr/bin/make | 50 | whitelist_externals = /usr/bin/make |
2484 | 52 | downloadcache = {toxworkdir}/_download/ | 51 | downloadcache = {toxworkdir}/_download/ |
2485 | 53 | commands = | 52 | commands = |
2486 | 54 | django-admin.py --version | 53 | django-admin.py --version |
2487 | 55 | make test | 54 | make test |
2554 | 56 | 55 | deps = | |
2555 | 57 | [testenv:py33-1.6.X] | 56 | 1.4.X: Django>=1.4,<1.5 |
2556 | 58 | basepython = python3.3 | 57 | 1.5.X: Django>=1.5,<1.6 |
2557 | 59 | deps = | 58 | 1.6.X: Django>=1.6,<1.7 |
2558 | 60 | Django>=1.6,<1.7 | 59 | 1.7.X: Django>=1.7,<1.8 |
2559 | 61 | {[deps]three} | 60 | 1.8.X: Django>=1.8,<1.9 |
2560 | 62 | 61 | py26: {[deps]two} | |
2561 | 63 | [testenv:py32-1.6.X] | 62 | py27: {[deps]two} |
2562 | 64 | basepython = python3.2 | 63 | py32: {[deps]three_two} |
2563 | 65 | deps = | 64 | py33: {[deps]three} |
2564 | 66 | Django>=1.6,<1.7 | 65 | py34: {[deps]three} |
2565 | 67 | {[deps]three_two} | 66 | django-discover-runner |
2500 | 68 | |||
2501 | 69 | [testenv:py27-1.6.X] | ||
2502 | 70 | basepython = python2.7 | ||
2503 | 71 | deps = | ||
2504 | 72 | Django>=1.6,<1.7 | ||
2505 | 73 | {[deps]two} | ||
2506 | 74 | |||
2507 | 75 | [testenv:py26-1.6.X] | ||
2508 | 76 | basepython = python2.6 | ||
2509 | 77 | deps = | ||
2510 | 78 | Django>=1.6,<1.7 | ||
2511 | 79 | {[deps]two} | ||
2512 | 80 | |||
2513 | 81 | [testenv:py33-1.5.X] | ||
2514 | 82 | basepython = python3.3 | ||
2515 | 83 | deps = | ||
2516 | 84 | Django>=1.5,<1.6 | ||
2517 | 85 | django-discover-runner | ||
2518 | 86 | {[deps]three} | ||
2519 | 87 | |||
2520 | 88 | [testenv:py32-1.5.X] | ||
2521 | 89 | basepython = python3.2 | ||
2522 | 90 | deps = | ||
2523 | 91 | Django>=1.5,<1.6 | ||
2524 | 92 | django-discover-runner | ||
2525 | 93 | {[deps]three_two} | ||
2526 | 94 | |||
2527 | 95 | [testenv:py27-1.5.X] | ||
2528 | 96 | basepython = python2.7 | ||
2529 | 97 | deps = | ||
2530 | 98 | Django>=1.5,<1.6 | ||
2531 | 99 | django-discover-runner | ||
2532 | 100 | {[deps]two} | ||
2533 | 101 | |||
2534 | 102 | [testenv:py26-1.5.X] | ||
2535 | 103 | basepython = python2.6 | ||
2536 | 104 | deps = | ||
2537 | 105 | Django>=1.5,<1.6 | ||
2538 | 106 | django-discover-runner | ||
2539 | 107 | {[deps]two} | ||
2540 | 108 | |||
2541 | 109 | [testenv:py27-1.4.X] | ||
2542 | 110 | basepython = python2.7 | ||
2543 | 111 | deps = | ||
2544 | 112 | Django>=1.4,<1.5 | ||
2545 | 113 | django-discover-runner | ||
2546 | 114 | {[deps]two} | ||
2547 | 115 | |||
2548 | 116 | [testenv:py26-1.4.X] | ||
2549 | 117 | basepython = python2.6 | ||
2550 | 118 | deps = | ||
2551 | 119 | Django>=1.4,<1.5 | ||
2552 | 120 | django-discover-runner | ||
2553 | 121 | {[deps]two} |
Looks good but just a few minor adjustments.
There are a few extra differences in the d/control build-depends. Can we get those in sync or is that for a reason?
Also d/watch wasn't pulling down the orig tar for me, so you may want to update with:
version=3 ngle=s/ (rc|a|b| c)/~$1/ \ pypi.debian. net/django_ compressor/ django_ compressor- (.+)\.(?:zip| tgz|tbz| txz|(?: tar\.(? :gz|bz2| xz)))
opts=uversionma
http://
then we can submit that in a patch to debian (just the d/watch part) via the 'submittodebian' command.