Merge lp:~nataliabidart/django-preflight/cache-status-info into lp:django-preflight
- cache-status-info
- Merge into trunk
Proposed by
Natalia Bidart
Status: | Merged |
---|---|
Approved by: | Natalia Bidart |
Approved revision: | 33 |
Merged at revision: | 30 |
Proposed branch: | lp:~nataliabidart/django-preflight/cache-status-info |
Merge into: | lp:django-preflight |
Diff against target: |
759 lines (+183/-135) 12 files modified
debian/control (+1/-1) preflight/__init__.py (+1/-14) preflight/models.py (+58/-24) preflight/templates/preflight/overview.html (+22/-5) preflight/tests.py (+67/-42) preflight/urls.py (+4/-4) preflight/views.py (+13/-8) preflight_example_project/app/preflight.py (+3/-2) preflight_example_project/run.py (+0/-2) preflight_example_project/urls.py (+3/-4) setup.py (+1/-1) tox.ini (+10/-28) |
To merge this branch: | bzr merge lp:~nataliabidart/django-preflight/cache-status-info |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Albisetti (community) | Approve | ||
Review via email: mp+203601@code.launchpad.net |
Commit message
- Include status information for django caches.
- Include database connection health checks.
Description of the change
To post a comment you must log in.
Revision history for this message
Martin Albisetti (beuno) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/control' |
2 | --- debian/control 2011-02-07 16:06:51 +0000 |
3 | +++ debian/control 2014-01-28 17:39:58 +0000 |
4 | @@ -14,7 +14,7 @@ |
5 | Architecture: all |
6 | XB-Python-Version: ${python:Versions} |
7 | Depends: ${misc:Depends}, ${python:Depends}, |
8 | - python-django (>= 1.0.2) |
9 | + python-django (>= 1.4) |
10 | Description: Base for creating pre-flight checks page for Django projects. |
11 | This project provides basic support for creating pre-flight checks page for Django |
12 | based projects. Such page consists with series of checks, provided by the project |
13 | |
14 | === modified file 'preflight/__init__.py' |
15 | --- preflight/__init__.py 2013-05-17 14:56:11 +0000 |
16 | +++ preflight/__init__.py 2014-01-28 17:39:58 +0000 |
17 | @@ -3,7 +3,7 @@ |
18 | |
19 | from django.conf import settings |
20 | |
21 | -from .models import REGISTRY |
22 | +from .models import Preflight, register # NOQA |
23 | |
24 | __version__ = "0.1.5" |
25 | |
26 | @@ -18,16 +18,3 @@ |
27 | msg = e.args[0].lower() |
28 | if 'no module named' not in msg or 'preflight' not in msg: |
29 | raise |
30 | - |
31 | - |
32 | -class Preflight(object): |
33 | - |
34 | - name = "Application Checks" |
35 | - |
36 | - def authenticate(self, request): |
37 | - return request.user.is_staff |
38 | - |
39 | - |
40 | -def register(class_): |
41 | - if class_ not in REGISTRY: |
42 | - REGISTRY.append(class_) |
43 | |
44 | === modified file 'preflight/models.py' |
45 | --- preflight/models.py 2014-01-24 12:21:51 +0000 |
46 | +++ preflight/models.py 2014-01-28 17:39:58 +0000 |
47 | @@ -2,12 +2,17 @@ |
48 | # GNU Affero General Public License version 3 (see the file LICENSE). |
49 | |
50 | from __future__ import absolute_import |
51 | + |
52 | +import platform |
53 | import re |
54 | import sys |
55 | import traceback |
56 | |
57 | import django |
58 | + |
59 | +from django import db |
60 | from django.conf import settings |
61 | +from django.core.cache import get_cache |
62 | from django.views.debug import HIDDEN_SETTINGS |
63 | |
64 | from .conf import ENABLE_SETTINGS |
65 | @@ -15,6 +20,26 @@ |
66 | REGISTRY = [] |
67 | |
68 | |
69 | +def register(class_): |
70 | + if class_ not in REGISTRY: |
71 | + REGISTRY.append(class_) |
72 | + |
73 | + |
74 | +class Preflight(object): |
75 | + |
76 | + name = "Application Checks" |
77 | + |
78 | + def authenticate(self, request): |
79 | + return request.user.is_staff |
80 | + |
81 | + def check_database(self): |
82 | + """Are database connections accepted?""" |
83 | + cursor = db.connection.cursor() |
84 | + cursor.execute('SELECT 42') |
85 | + cursor.fetchone() |
86 | + return True |
87 | + |
88 | + |
89 | class Application(object): |
90 | |
91 | def __init__(self, class_): |
92 | @@ -28,8 +53,8 @@ |
93 | if s.startswith('check_')) |
94 | for check_name in check_names: |
95 | instance = self.class_() |
96 | - bound_method = getattr(instance, check_name) |
97 | - check = Check(check_name[len('check_'):], bound_method) |
98 | + check_method = getattr(instance, check_name) |
99 | + check = Check(check_name[len('check_'):], check_method) |
100 | check.check() |
101 | self.checks.append(check) |
102 | |
103 | @@ -49,10 +74,7 @@ |
104 | |
105 | |
106 | class Check(object): |
107 | - |
108 | - """ |
109 | - Representation of one check performed and place to store its result. |
110 | - """ |
111 | + """Representation of one check performed and place to store its result.""" |
112 | |
113 | def __init__(self, name, bound_method): |
114 | self.name = name |
115 | @@ -63,14 +85,14 @@ |
116 | self.description = "" |
117 | |
118 | def check(self): |
119 | - """ |
120 | - Returns True if check was successful and False otherwise. |
121 | + """Return True if check was successful and False otherwise. |
122 | |
123 | This result is also stored in object's attribute ``passed``. |
124 | + |
125 | """ |
126 | try: |
127 | self.passed = bool(self.bound_method()) |
128 | - except Exception, exc: |
129 | + except Exception: |
130 | exc_type, exc_value, exc_traceback = sys.exc_info() |
131 | self.exception = u"".join( |
132 | traceback.format_exception(exc_type, exc_value, |
133 | @@ -96,21 +118,12 @@ |
134 | |
135 | |
136 | def gather_versions(): |
137 | - """ |
138 | - Gather list of version information to be displayed alongside the checks |
139 | - data. |
140 | - |
141 | - """ |
142 | - import platform |
143 | - import sys |
144 | - import django |
145 | - import preflight |
146 | + """Return list of version information to be shown with the checks data.""" |
147 | |
148 | items = [ |
149 | {'name': 'Platform', 'version': platform.platform()}, |
150 | {'name': 'Django', 'version': django.get_version()}, |
151 | {'name': 'Python', 'version': sys.version}, |
152 | - {'name': 'preflight', 'version': preflight.__version__} |
153 | ] |
154 | |
155 | for class_ in REGISTRY: |
156 | @@ -152,7 +165,7 @@ |
157 | else: |
158 | if isinstance(value, dict): |
159 | cleansed = dict((k, cleanse_setting(k, v, hidden)) |
160 | - for k,v in value.items()) |
161 | + for k, v in value.items()) |
162 | else: |
163 | cleansed = value |
164 | except TypeError: |
165 | @@ -160,11 +173,13 @@ |
166 | cleansed = value |
167 | return cleansed |
168 | |
169 | + |
170 | def gather_settings(): |
171 | if not ENABLE_SETTINGS: |
172 | return [] |
173 | |
174 | - names = sorted([x for x in settings._wrapped.__dict__ |
175 | + names = sorted([ |
176 | + x for x in settings._wrapped.__dict__ |
177 | if x.isupper() and not x.startswith('_')]) |
178 | settings_list = [] |
179 | hidden_settings = getattr(settings, 'PREFLIGHT_HIDDEN_SETTINGS', None) |
180 | @@ -183,9 +198,7 @@ |
181 | |
182 | |
183 | def authenticate(request): |
184 | - """ |
185 | - To be able to access you need to have permission from every preflight class. |
186 | - """ |
187 | + """For access, permission from every preflight class is required.""" |
188 | return all(class_().authenticate(request) for class_ in REGISTRY) |
189 | |
190 | |
191 | @@ -249,3 +262,24 @@ |
192 | status_text=switch['statusLabel'], |
193 | conditions=conditions, |
194 | ) |
195 | + |
196 | + |
197 | +def gather_caches(): |
198 | + """Expose the status of memcache on the preflight page.""" |
199 | + caches = {} |
200 | + |
201 | + for cache_name, cache_settings in settings.CACHES.iteritems(): |
202 | + cache = get_cache(cache_name) |
203 | + try: |
204 | + stats = cache._cache.get_stats()[0][1] |
205 | + except Exception as exc: |
206 | + stats = dict(error=unicode(exc)) |
207 | + else: |
208 | + stats['hit_rate'] = 100 * int( |
209 | + stats.get('get_hits')) / int(stats.get('cmd_get')) |
210 | + |
211 | + stats['backend'] = cache_settings['BACKEND'] |
212 | + stats['host'] = cache_settings.get('LOCATION', 'No location given') |
213 | + caches[cache_name] = stats |
214 | + |
215 | + return caches |
216 | |
217 | === modified file 'preflight/templates/preflight/overview.html' |
218 | --- preflight/templates/preflight/overview.html 2014-01-24 14:07:11 +0000 |
219 | +++ preflight/templates/preflight/overview.html 2014-01-28 17:39:58 +0000 |
220 | @@ -5,11 +5,11 @@ |
221 | |
222 | {% load i18n %} |
223 | |
224 | -{% block title %}{% trans "Application Pre-Flight Checks" %}{% endblock %} |
225 | +{% block title %}{% trans "Preflight Checks" %}{% endblock %} |
226 | |
227 | {% block content %} |
228 | <div id="preflight"> |
229 | - <h1>{% trans "Pre-flight Applications Checks" %}</h1> |
230 | + <h1>{% trans "Preflight Checks" %}</h1> |
231 | |
232 | <ul id="links"> |
233 | {% for application in applications %} |
234 | @@ -22,6 +22,9 @@ |
235 | {% if switches %} |
236 | <li><a href="#switches">Switches</a></li> |
237 | {% endif %} |
238 | + {% if caches %} |
239 | + <li><a href="#caches">Caches</a></li> |
240 | + {% endif %} |
241 | </ul> |
242 | |
243 | {% for application in applications %} |
244 | @@ -60,7 +63,7 @@ |
245 | {% endfor %} |
246 | |
247 | <a href="#links" style="text-decoration: none;"> |
248 | - <h1 id="versions">{% trans "Versions" %}</h1> |
249 | + <h2 id="versions">{% trans "Versions" %}</h2> |
250 | </a> |
251 | <table class="{{ preflight_table_class }}"> |
252 | <thead> |
253 | @@ -81,7 +84,7 @@ |
254 | |
255 | {% if settings %} |
256 | <a href="#links" style="text-decoration: none;"> |
257 | - <h1 id="settings">{% trans "Settings" %}</h1> |
258 | + <h2 id="settings">{% trans "Settings" %}</h2> |
259 | </a> |
260 | <dl class="{{ preflight_table_class }}"> |
261 | {% for setting in settings %} |
262 | @@ -94,7 +97,7 @@ |
263 | |
264 | {% if switches %} |
265 | <a href="#links" style="text-decoration: none;"> |
266 | - <h1 id="switches">{% trans "Switches" %}</h1> |
267 | + <h2 id="switches">{% trans "Gargoyle Switches" %}</h2> |
268 | </a> |
269 | <table id="switches-table" class="{{ preflight_table_class }}"> |
270 | <thead> |
271 | @@ -130,6 +133,20 @@ |
272 | {% else %} |
273 | <p>No switches.</p> |
274 | {% endif %} |
275 | + |
276 | + {% for name, cache in caches.items %} |
277 | + <a href="#links" style="text-decoration: none;"> |
278 | + <h2 id="caches">Cache {{ name }}</h2> |
279 | + </a> |
280 | + <dl> |
281 | + {% for key, value in cache %} |
282 | + <strong>{{ key }}</strong>: {{ value }}<br /> |
283 | + {% endfor %} |
284 | + </dl> |
285 | + {% empty %} |
286 | + <p>No caches.</p> |
287 | + {% endfor %} |
288 | + |
289 | </div> |
290 | |
291 | <p>View generated at: {{ now }}</p> |
292 | |
293 | === modified file 'preflight/tests.py' |
294 | --- preflight/tests.py 2014-01-24 14:07:11 +0000 |
295 | +++ preflight/tests.py 2014-01-28 17:39:58 +0000 |
296 | @@ -1,12 +1,9 @@ |
297 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
298 | # GNU Affero General Public License version 3 (see the file LICENSE). |
299 | import sys |
300 | -try: |
301 | - from unittest import skipIf |
302 | -except ImportError: |
303 | - from unittest2 import skipIf # NOQA |
304 | - |
305 | -from django.conf import settings |
306 | + |
307 | +from cStringIO import StringIO |
308 | + |
309 | from django.contrib.auth.models import AnonymousUser, User |
310 | from django.core.management import call_command |
311 | from django.core.urlresolvers import reverse |
312 | @@ -14,20 +11,24 @@ |
313 | from django.test import TestCase |
314 | from django.template import RequestContext |
315 | from django.template.loader import render_to_string |
316 | +from gargoyle import gargoyle |
317 | +from gargoyle.builtins import IPAddressConditionSet |
318 | +from gargoyle.models import ( |
319 | + DISABLED, GLOBAL, INHERIT, SELECTIVE, |
320 | + Switch, |
321 | +) |
322 | from mock import ( |
323 | Mock, |
324 | patch, |
325 | ) |
326 | - |
327 | -from cStringIO import StringIO |
328 | from pyquery import PyQuery |
329 | |
330 | -from . import Preflight |
331 | -from .models import ( |
332 | +from preflight.models import ( |
333 | + HIDDEN_SETTINGS, |
334 | + REGISTRY, |
335 | Application, |
336 | Check, |
337 | - HIDDEN_SETTINGS, |
338 | - REGISTRY, |
339 | + Preflight, |
340 | authenticate, |
341 | cleanse_setting, |
342 | gather_checks, |
343 | @@ -47,7 +48,7 @@ |
344 | self.return_value = True |
345 | |
346 | def check_method(self): |
347 | - "description" |
348 | + """Some description""" |
349 | if self.exception: |
350 | raise self.exception |
351 | return self.return_value |
352 | @@ -55,8 +56,8 @@ |
353 | def test_initialisation(self): |
354 | check = Check("check_name", self.check_method) |
355 | |
356 | - self.assertEquals(check.name, "check_name") |
357 | - self.assertEquals(check.description, "description") |
358 | + self.assertEqual(check.name, "check_name") |
359 | + self.assertEqual(check.description, "Some description") |
360 | |
361 | def test_initialisation_when_doc_is_none(self): |
362 | def method(): |
363 | @@ -64,7 +65,7 @@ |
364 | |
365 | check = Check("check_name", method) |
366 | |
367 | - self.assertEquals(check.description, "") |
368 | + self.assertEqual(check.description, "") |
369 | |
370 | def test_check_when_check_method_returns_true(self): |
371 | check = Check("check_name", self.check_method) |
372 | @@ -89,7 +90,7 @@ |
373 | def test_check_returns_right_return_value(self): |
374 | check = Check("check_name", self.check_method) |
375 | |
376 | - self.assertEquals(check.check(), check.passed) |
377 | + self.assertEqual(check.check(), check.passed) |
378 | |
379 | def test_check_after_exception_has_exception_attribute(self): |
380 | self.exception = Exception("error") |
381 | @@ -128,7 +129,7 @@ |
382 | app = Application(DummyPreflight) |
383 | |
384 | self.assertEqual(app.name, "preflight checks") |
385 | - self.assertEqual(len(app.checks), 4) |
386 | + self.assertEqual(len(app.checks), 5) |
387 | |
388 | def test_check_name_is_properly_handled(self): |
389 | app = Application(DummyPreflight) |
390 | @@ -138,6 +139,7 @@ |
391 | 'check_test', |
392 | 'maybe_fail', |
393 | 'maybe_error', |
394 | + 'database', |
395 | ])) |
396 | |
397 | def test_check_sets_passed_to_false_if_at_least_one_of_check_fails(self): |
398 | @@ -146,14 +148,11 @@ |
399 | self.assertFalse(app.passed) |
400 | |
401 | def test_check_sets_passed_to_true_if_all_checks_passed(self): |
402 | - DummyPreflight.fail = False |
403 | - |
404 | - app = Application(DummyPreflight) |
405 | + with patch.object(DummyPreflight, 'fail', False): |
406 | + app = Application(DummyPreflight) |
407 | |
408 | self.assertTrue(app.passed) |
409 | |
410 | - DummyPreflight.fail = True |
411 | - |
412 | |
413 | class AuthenticatePass(Preflight): |
414 | |
415 | @@ -241,13 +240,13 @@ |
416 | |
417 | applications = gather_checks() |
418 | |
419 | - self.assertEquals(len(applications), 3) |
420 | + self.assertEqual(len(applications), 3) |
421 | |
422 | |
423 | class ExtraVersionAsCallable(Preflight): |
424 | |
425 | def versions(self): |
426 | - return [{'name': 'spam', 'version': 'ni'}] |
427 | + return [{'name': 'spam', 'version': lambda: 'ni'}] |
428 | |
429 | |
430 | class ExtraVersionAsList(Preflight): |
431 | @@ -262,7 +261,7 @@ |
432 | |
433 | versions = gather_versions() |
434 | |
435 | - self.assertEquals(len(versions), 4) |
436 | + self.assertEqual(len(versions), 3) |
437 | for item in versions: |
438 | self.assertTrue('name' in item and 'version' in item) |
439 | |
440 | @@ -272,8 +271,8 @@ |
441 | |
442 | versions = gather_versions() |
443 | |
444 | - self.assertEquals(len(versions), 5) |
445 | - self.assertEquals(versions[-1]['name'], 'spam') |
446 | + self.assertEqual(len(versions), 4) |
447 | + self.assertEqual(versions[-1]['name'], 'spam') |
448 | |
449 | def test_get_extra_version_information_from_class_attribute(self): |
450 | clear_registry() |
451 | @@ -281,8 +280,8 @@ |
452 | |
453 | versions = gather_versions() |
454 | |
455 | - self.assertEquals(len(versions), 5) |
456 | - self.assertEquals(versions[-1]['version'], 'peng') |
457 | + self.assertEqual(len(versions), 4) |
458 | + self.assertEqual(versions[-1]['version'], 'peng') |
459 | |
460 | |
461 | class PreflightCommandTestCase(TestCase): |
462 | @@ -330,6 +329,7 @@ |
463 | finally: |
464 | sys.stdout = sys.__stdout__ |
465 | |
466 | + |
467 | class OverviewView(TestCase): |
468 | @patch('preflight.views.authenticate') |
469 | def test_overview_when_not_authenticated(self, mock_authenticate): |
470 | @@ -457,21 +457,11 @@ |
471 | self.assertFalse('secret' in result['default']['PASSWORD']) |
472 | |
473 | |
474 | -@skipIf(not settings.USE_GARGOYLE, 'skipping for Django 1.1') |
475 | class GargoyleTestCase(TestCase): |
476 | |
477 | def setUp(self): |
478 | - from gargoyle import gargoyle |
479 | self.gargoyle = gargoyle |
480 | - from gargoyle.builtins import IPAddressConditionSet |
481 | self.IPAddressConditionSet = IPAddressConditionSet |
482 | - from gargoyle.models import ( |
483 | - Switch, |
484 | - DISABLED, |
485 | - SELECTIVE, |
486 | - GLOBAL, |
487 | - INHERIT |
488 | - ) |
489 | self.Switch = Switch |
490 | self.DISABLED = DISABLED |
491 | self.SELECTIVE = SELECTIVE |
492 | @@ -482,8 +472,8 @@ |
493 | |
494 | def get_switches(self): |
495 | switches = [ |
496 | - self.Switch(key='DISABLED', status=self.DISABLED, |
497 | - description='switch 1'), |
498 | + self.Switch( |
499 | + key='DISABLED', status=self.DISABLED, description='switch 1'), |
500 | self.Switch(key='SELECTIVE_1', status=self.SELECTIVE), |
501 | self.Switch(key='SELECTIVE_2', status=self.SELECTIVE), |
502 | self.Switch(key='GLOBAL', status=self.GLOBAL), |
503 | @@ -553,3 +543,38 @@ |
504 | self.assertEqual(row[0].text, switch.key) |
505 | self.assertEqual(row[1].text, str(switch.description)) |
506 | self.assertEqual(row[3].text, switch.get_status_label()) |
507 | + |
508 | + |
509 | +class PreflightTestCase(TestCase): |
510 | + |
511 | + url = '/preflight/' |
512 | + email = 'email@domain.local' |
513 | + password = 'testpassword' |
514 | + |
515 | + def setUp(self): |
516 | + super(PreflightTestCase, self).setUp() |
517 | + self.user = User.objects.create_superuser( |
518 | + username='pepe', email=self.email, password=self.password) |
519 | + |
520 | + def test_anonymous(self): |
521 | + response = self.client.get(self.url) |
522 | + |
523 | + self.assertEqual(404, response.status_code) |
524 | + |
525 | + def test_not_staff(self): |
526 | + user = User.objects.create_user( |
527 | + username='jose', email='jose@example.com', password=self.password) |
528 | + assert not user.is_staff |
529 | + assert self.client.login(username='jose', password=self.password) |
530 | + |
531 | + response = self.client.get(self.url) |
532 | + self.assertEqual(404, response.status_code) |
533 | + |
534 | + def test_success(self): |
535 | + assert self.user.is_staff |
536 | + assert self.client.login( |
537 | + username=self.user.username, password=self.password) |
538 | + |
539 | + response = self.client.get(self.url) |
540 | + |
541 | + self.assertEqual(200, response.status_code) |
542 | |
543 | === modified file 'preflight/urls.py' |
544 | --- preflight/urls.py 2011-10-04 15:54:50 +0000 |
545 | +++ preflight/urls.py 2014-01-28 17:39:58 +0000 |
546 | @@ -1,9 +1,9 @@ |
547 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
548 | # GNU Affero General Public License version 3 (see the file LICENSE). |
549 | |
550 | -from django.conf.urls.defaults import patterns, url |
551 | - |
552 | - |
553 | -urlpatterns = patterns('preflight.views', |
554 | +from django.conf.urls import patterns, url |
555 | + |
556 | +urlpatterns = patterns( |
557 | + 'preflight.views', |
558 | url(r'^$', 'overview', name='preflight-overview'), |
559 | ) |
560 | |
561 | === modified file 'preflight/views.py' |
562 | --- preflight/views.py 2013-06-10 12:57:48 +0000 |
563 | +++ preflight/views.py 2014-01-28 17:39:58 +0000 |
564 | @@ -1,24 +1,26 @@ |
565 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
566 | # GNU Affero General Public License version 3 (see the file LICENSE). |
567 | |
568 | +import functools |
569 | +import json |
570 | + |
571 | from datetime import datetime |
572 | -import json |
573 | -import functools |
574 | |
575 | from django.contrib.auth import authenticate as django_authenticate |
576 | -from django.views.decorators.cache import never_cache |
577 | from django.http import Http404, HttpResponse |
578 | from django.shortcuts import render_to_response |
579 | from django.template import RequestContext |
580 | +from django.views.decorators.cache import never_cache |
581 | |
582 | -from .models import ( |
583 | +from preflight.conf import BASE_TEMPLATE, TABLE_CLASS |
584 | +from preflight.models import ( |
585 | authenticate, |
586 | + gather_caches, |
587 | gather_checks, |
588 | gather_settings, |
589 | + gather_switches, |
590 | gather_versions, |
591 | - gather_switches, |
592 | ) |
593 | -from .conf import BASE_TEMPLATE, TABLE_CLASS |
594 | |
595 | |
596 | JSON_TYPE = 'application/json' |
597 | @@ -29,11 +31,16 @@ |
598 | if not authenticate(request): |
599 | raise Http404 |
600 | |
601 | + caches = { |
602 | + name: [i for i in sorted(cache.iteritems())] |
603 | + for name, cache in gather_caches().iteritems() |
604 | + } |
605 | data = { |
606 | "applications": gather_checks(), |
607 | "versions": gather_versions(), |
608 | "settings": gather_settings(), |
609 | "switches": gather_switches(), |
610 | + "caches": caches, |
611 | } |
612 | # poor man's conneg |
613 | if JSON_TYPE in request.META.get('HTTP_ACCEPT', ''): |
614 | @@ -76,5 +83,3 @@ |
615 | request.user = basic_user |
616 | return f(self, request) |
617 | return wrapper |
618 | - |
619 | - |
620 | |
621 | === modified file 'preflight_example_project/app/preflight.py' |
622 | --- preflight_example_project/app/preflight.py 2011-02-07 16:06:51 +0000 |
623 | +++ preflight_example_project/app/preflight.py 2014-01-28 17:39:58 +0000 |
624 | @@ -5,9 +5,10 @@ |
625 | |
626 | from django.conf import settings |
627 | |
628 | -import os.path |
629 | +import os |
630 | +import tempfile |
631 | + |
632 | import preflight |
633 | -import tempfile |
634 | |
635 | |
636 | class AppPreflight(preflight.Preflight): |
637 | |
638 | === modified file 'preflight_example_project/run.py' |
639 | --- preflight_example_project/run.py 2013-05-31 16:23:03 +0000 |
640 | +++ preflight_example_project/run.py 2014-01-28 17:39:58 +0000 |
641 | @@ -13,7 +13,6 @@ |
642 | from django.conf import settings |
643 | |
644 | |
645 | - |
646 | def tests(): |
647 | TestRunner = get_runner(settings) |
648 | if hasattr(TestRunner, 'func_name'): |
649 | @@ -26,6 +25,5 @@ |
650 | sys.exit(bool(failures)) |
651 | |
652 | |
653 | - |
654 | if __name__ == '__main__': |
655 | tests() |
656 | |
657 | === modified file 'preflight_example_project/urls.py' |
658 | --- preflight_example_project/urls.py 2011-10-04 15:54:50 +0000 |
659 | +++ preflight_example_project/urls.py 2014-01-28 17:39:58 +0000 |
660 | @@ -1,15 +1,14 @@ |
661 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
662 | # GNU Affero General Public License version 3 (see the file LICENSE). |
663 | |
664 | -from django.conf.urls.defaults import ( |
665 | - handler404, handler500, include, patterns |
666 | -) |
667 | +from django.conf.urls import include, patterns |
668 | |
669 | import preflight |
670 | |
671 | |
672 | preflight.autodiscover() |
673 | |
674 | -urlpatterns = patterns('', |
675 | +urlpatterns = patterns( |
676 | + '', |
677 | (r'^preflight/', include('preflight.urls')), |
678 | ) |
679 | |
680 | === modified file 'setup.py' |
681 | --- setup.py 2013-05-31 16:23:03 +0000 |
682 | +++ setup.py 2014-01-28 17:39:58 +0000 |
683 | @@ -56,7 +56,7 @@ |
684 | 'preflight': ['templates/preflight/*.html'], |
685 | }, |
686 | install_requires=[ |
687 | - 'django >= 1.1', |
688 | + 'django >= 1.4', |
689 | ], |
690 | tests_require=tests_require, |
691 | extras_require={ |
692 | |
693 | === modified file 'tox.ini' |
694 | --- tox.ini 2013-05-17 14:50:46 +0000 |
695 | +++ tox.ini 2014-01-28 17:39:58 +0000 |
696 | @@ -1,10 +1,8 @@ |
697 | [tox] |
698 | -envlist = |
699 | - py2.6-django1.1, py2.7-django1.1, |
700 | - py2.6-django1.2, py2.7-django1.2, |
701 | - py2.6-django1.3, py2.7-django1.3, |
702 | +envlist = |
703 | py2.6-django1.4, py2.7-django1.4, |
704 | py2.6-django1.5, py2.7-django1.5, |
705 | + py2.6-django1.6, py2.7-django1.6, |
706 | docs |
707 | |
708 | [testenv] |
709 | @@ -19,18 +17,6 @@ |
710 | sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html |
711 | |
712 | # Python 2.6 |
713 | -[testenv:py2.6-django1.1] |
714 | -basepython = python2.6 |
715 | -deps = django >= 1.1, < 1.2 |
716 | - |
717 | -[testenv:py2.6-django1.2] |
718 | -basepython = python2.6 |
719 | -deps = django >= 1.2, < 1.3 |
720 | - |
721 | -[testenv:py2.6-django1.3] |
722 | -basepython = python2.6 |
723 | -deps = django >= 1.3, < 1.4 |
724 | - |
725 | [testenv:py2.6-django1.4] |
726 | basepython = python2.6 |
727 | deps = django >= 1.4, < 1.5 |
728 | @@ -39,19 +25,11 @@ |
729 | basepython = python2.6 |
730 | deps = django >= 1.5, < 1.6 |
731 | |
732 | +[testenv:py2.6-django1.6] |
733 | +basepython = python2.6 |
734 | +deps = django >= 1.6, < 1.7 |
735 | + |
736 | # Python 2.7 |
737 | -[testenv:py2.7-django1.1] |
738 | -basepython = python2.7 |
739 | -deps = django >= 1.1, < 1.2 |
740 | - |
741 | -[testenv:py2.7-django1.2] |
742 | -basepython = python2.7 |
743 | -deps = django >= 1.2, < 1.3 |
744 | - |
745 | -[testenv:py2.7-django1.3] |
746 | -basepython = python2.7 |
747 | -deps = django >= 1.3, < 1.4 |
748 | - |
749 | [testenv:py2.7-django1.4] |
750 | basepython = python2.7 |
751 | deps = django >= 1.4, < 1.5 |
752 | @@ -59,3 +37,7 @@ |
753 | [testenv:py2.7-django1.5] |
754 | basepython = python2.7 |
755 | deps = django >= 1.5, < 1.6 |
756 | + |
757 | +[testenv:py2.7-django1.6] |
758 | +basepython = python2.7 |
759 | +deps = django >= 1.6, < 1.7 |