Merge lp:~fgallina/django-statsd/sync into lp:~ubuntuone-pqm-team/django-statsd/stable
- sync
- Merge into stable
Proposed by
Fabián Ezequiel Gallina
Status: | Merged |
---|---|
Merged at revision: | 78 |
Proposed branch: | lp:~fgallina/django-statsd/sync |
Merge into: | lp:~ubuntuone-pqm-team/django-statsd/stable |
Diff against target: |
446 lines (+252/-50) 9 files modified
.travis.yml (+1/-1) django_statsd/patches/__init__.py (+1/-5) django_statsd/patches/db.py (+37/-21) django_statsd/patches/utils.py (+15/-2) django_statsd/test_settings.py (+13/-0) django_statsd/tests.py (+167/-19) docs/index.rst (+16/-1) requirements.txt (+1/-0) setup.py (+1/-1) |
To merge this branch: | bzr merge lp:~fgallina/django-statsd/sync |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu One PQM Team | Pending | ||
Review via email: mp+217975@code.launchpad.net |
Commit message
Bump to latest released version
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.travis.yml' | |||
2 | --- .travis.yml 2012-09-12 17:33:25 +0000 | |||
3 | +++ .travis.yml 2014-05-01 19:34:04 +0000 | |||
4 | @@ -3,6 +3,6 @@ | |||
5 | 3 | - "2.6" | 3 | - "2.6" |
6 | 4 | - "2.7" | 4 | - "2.7" |
7 | 5 | install: pip install -r requirements.txt -r optional.txt --use-mirrors | 5 | install: pip install -r requirements.txt -r optional.txt --use-mirrors |
9 | 6 | script: nosetests | 6 | script: DJANGO_SETTINGS_MODULE='django_statsd.test_settings' nosetests |
10 | 7 | notifications: | 7 | notifications: |
11 | 8 | irc: "irc.mozilla.org#amo-bots" | 8 | irc: "irc.mozilla.org#amo-bots" |
12 | 9 | 9 | ||
13 | === modified file 'django_statsd/patches/__init__.py' | |||
14 | --- django_statsd/patches/__init__.py 2012-06-20 12:58:58 +0000 | |||
15 | +++ django_statsd/patches/__init__.py 2014-05-01 19:34:04 +0000 | |||
16 | @@ -1,11 +1,7 @@ | |||
17 | 1 | from django.conf import settings | 1 | from django.conf import settings |
18 | 2 | from django.utils.importlib import import_module | 2 | from django.utils.importlib import import_module |
19 | 3 | 3 | ||
25 | 4 | # Workaround for tests. | 4 | patches = getattr(settings, 'STATSD_PATCHES', []) |
21 | 5 | try: | ||
22 | 6 | patches = getattr(settings, 'STATSD_PATCHES', []) | ||
23 | 7 | except ImportError: | ||
24 | 8 | patches = [] | ||
26 | 9 | 5 | ||
27 | 10 | for patch in patches: | 6 | for patch in patches: |
28 | 11 | import_module(patch).patch() | 7 | import_module(patch).patch() |
29 | 12 | 8 | ||
30 | === modified file 'django_statsd/patches/db.py' | |||
31 | --- django_statsd/patches/db.py 2014-04-06 21:54:47 +0000 | |||
32 | +++ django_statsd/patches/db.py 2014-05-01 19:34:04 +0000 | |||
33 | @@ -1,45 +1,61 @@ | |||
34 | 1 | import django | 1 | import django |
35 | 2 | from django.db.backends import util | 2 | from django.db.backends import util |
38 | 3 | 3 | from django_statsd.patches.utils import wrap, patch_method | |
39 | 4 | from django_statsd.patches.utils import wrap | 4 | from django_statsd.clients import statsd |
40 | 5 | 5 | ||
41 | 6 | 6 | ||
42 | 7 | def key(db, attr): | 7 | def key(db, attr): |
43 | 8 | return 'db.%s.%s.%s' % (db.client.executable_name, db.alias, attr) | 8 | return 'db.%s.%s.%s' % (db.client.executable_name, db.alias, attr) |
44 | 9 | 9 | ||
45 | 10 | 10 | ||
47 | 11 | def __getattr__(self, attr): | 11 | def pre_django_1_6_cursorwrapper_getattr(self, attr): |
48 | 12 | """ | 12 | """ |
49 | 13 | The CursorWrapper is a pretty small wrapper around the cursor. | 13 | The CursorWrapper is a pretty small wrapper around the cursor. |
50 | 14 | If you are NOT in debug mode, this is the wrapper that's used. | 14 | If you are NOT in debug mode, this is the wrapper that's used. |
51 | 15 | Sadly if it's in debug mode, we get a different wrapper. | 15 | Sadly if it's in debug mode, we get a different wrapper. |
52 | 16 | """ | 16 | """ |
55 | 17 | if django.VERSION < (1, 6) and self.db.is_managed(): | 17 | if self.db.is_managed(): |
54 | 18 | # In Django 1.6 you can't put a connection in managed mode | ||
56 | 19 | self.db.set_dirty() | 18 | self.db.set_dirty() |
57 | 20 | if attr in self.__dict__: | 19 | if attr in self.__dict__: |
58 | 21 | return self.__dict__[attr] | 20 | return self.__dict__[attr] |
59 | 22 | else: | 21 | else: |
61 | 23 | if attr in ['execute', 'executemany']: | 22 | if attr in ['execute', 'executemany', 'callproc']: |
62 | 24 | return wrap(getattr(self.cursor, attr), key(self.db, attr)) | 23 | return wrap(getattr(self.cursor, attr), key(self.db, attr)) |
63 | 25 | return getattr(self.cursor, attr) | 24 | return getattr(self.cursor, attr) |
64 | 26 | 25 | ||
65 | 27 | 26 | ||
77 | 28 | def wrap_class(base): | 27 | def patched_execute(orig_execute, self, *args, **kwargs): |
78 | 29 | class Wrapper(base): | 28 | with statsd.timer(key(self.db, 'execute')): |
79 | 30 | def execute(self, *args, **kw): | 29 | return orig_execute(self, *args, **kwargs) |
80 | 31 | return wrap(super(Wrapper, self).execute, | 30 | |
81 | 32 | key(self.db, 'execute'))(*args, **kw) | 31 | |
82 | 33 | 32 | def patched_executemany(orig_executemany, self, *args, **kwargs): | |
83 | 34 | def executemany(self, *args, **kw): | 33 | with statsd.timer(key(self.db, 'executemany')): |
84 | 35 | return wrap(super(Wrapper, self).executemany, | 34 | return orig_executemany(self, *args, **kwargs) |
85 | 36 | key(self.db, 'executemany'))(*args, **kw) | 35 | |
86 | 37 | 36 | ||
87 | 38 | return Wrapper | 37 | def patched_callproc(orig_callproc, self, *args, **kwargs): |
88 | 38 | with statsd.timer(key(self.db, 'callproc')): | ||
89 | 39 | return orig_callproc(self, *args, **kwargs) | ||
90 | 39 | 40 | ||
91 | 40 | 41 | ||
92 | 41 | def patch(): | 42 | def patch(): |
97 | 42 | # So that it will work when DEBUG = True. | 43 | """ |
98 | 43 | util.CursorDebugWrapper = wrap_class(util.CursorDebugWrapper) | 44 | The CursorWrapper is a pretty small wrapper around the cursor. If |
99 | 44 | # So that it will work when DEBUG = False. | 45 | you are NOT in debug mode, this is the wrapper that's used. Sadly |
100 | 45 | util.CursorWrapper.__getattr__ = __getattr__ | 46 | if it's in debug mode, we get a different wrapper for version |
101 | 47 | earlier than 1.6. | ||
102 | 48 | """ | ||
103 | 49 | |||
104 | 50 | if django.VERSION > (1, 6): | ||
105 | 51 | # In 1.6+ util.CursorDebugWrapper just makes calls to CursorWrapper | ||
106 | 52 | # As such, we only need to instrument CursorWrapper. | ||
107 | 53 | # Instrumenting both will result in duplicated metrics | ||
108 | 54 | patch_method(util.CursorWrapper, 'execute')(patched_execute) | ||
109 | 55 | patch_method(util.CursorWrapper, 'executemany')(patched_executemany) | ||
110 | 56 | patch_method(util.CursorWrapper, 'callproc')(patched_callproc) | ||
111 | 57 | else: | ||
112 | 58 | util.CursorWrapper.__getattr__ = pre_django_1_6_cursorwrapper_getattr | ||
113 | 59 | patch_method(util.CursorDebugWrapper, 'execute')(patched_execute) | ||
114 | 60 | patch_method( | ||
115 | 61 | util.CursorDebugWrapper, 'executemany')(patched_executemany) | ||
116 | 46 | 62 | ||
117 | === modified file 'django_statsd/patches/utils.py' | |||
118 | --- django_statsd/patches/utils.py 2012-06-20 12:58:58 +0000 | |||
119 | +++ django_statsd/patches/utils.py 2014-05-01 19:34:04 +0000 | |||
120 | @@ -1,6 +1,19 @@ | |||
121 | 1 | from django_statsd.clients import statsd | 1 | from django_statsd.clients import statsd |
124 | 2 | from functools import partial | 2 | from functools import partial, wraps |
125 | 3 | 3 | ||
126 | 4 | def patch_method(target, name, external_decorator=None): | ||
127 | 5 | |||
128 | 6 | def decorator(patch_function): | ||
129 | 7 | original_function = getattr(target, name) | ||
130 | 8 | |||
131 | 9 | @wraps(patch_function) | ||
132 | 10 | def wrapper(*args, **kw): | ||
133 | 11 | return patch_function(original_function, *args, **kw) | ||
134 | 12 | |||
135 | 13 | setattr(target, name, wrapper) | ||
136 | 14 | return wrapper | ||
137 | 15 | |||
138 | 16 | return decorator | ||
139 | 4 | 17 | ||
140 | 5 | def wrapped(method, key, *args, **kw): | 18 | def wrapped(method, key, *args, **kw): |
141 | 6 | with statsd.timer(key): | 19 | with statsd.timer(key): |
142 | 7 | 20 | ||
143 | === added file 'django_statsd/test_settings.py' | |||
144 | --- django_statsd/test_settings.py 1970-01-01 00:00:00 +0000 | |||
145 | +++ django_statsd/test_settings.py 2014-05-01 19:34:04 +0000 | |||
146 | @@ -0,0 +1,13 @@ | |||
147 | 1 | DATABASES = { | ||
148 | 2 | 'default': { | ||
149 | 3 | 'ENGINE': 'django.db.backends.sqlite3', | ||
150 | 4 | 'NAME': 'mydatabase' | ||
151 | 5 | } | ||
152 | 6 | } | ||
153 | 7 | |||
154 | 8 | ROOT_URLCONF = '' | ||
155 | 9 | STATSD_CLIENT = 'django_statsd.clients.null' | ||
156 | 10 | STATSD_PREFIX = None | ||
157 | 11 | METLOG = None | ||
158 | 12 | |||
159 | 13 | SECRET_KEY = 'secret' | ||
160 | 0 | 14 | ||
161 | === modified file 'django_statsd/tests.py' | |||
162 | --- django_statsd/tests.py 2013-12-19 15:53:26 +0000 | |||
163 | +++ django_statsd/tests.py 2014-05-01 19:34:04 +0000 | |||
164 | @@ -5,23 +5,9 @@ | |||
165 | 5 | from django.conf import settings | 5 | from django.conf import settings |
166 | 6 | from nose.exc import SkipTest | 6 | from nose.exc import SkipTest |
167 | 7 | from nose import tools as nose_tools | 7 | from nose import tools as nose_tools |
185 | 8 | 8 | from unittest2 import skipUnless | |
186 | 9 | minimal = { | 9 | |
187 | 10 | 'DATABASES': { | 10 | from django import VERSION |
171 | 11 | 'default': { | ||
172 | 12 | 'ENGINE': 'django.db.backends.sqlite3', | ||
173 | 13 | 'NAME': 'mydatabase' | ||
174 | 14 | } | ||
175 | 15 | }, | ||
176 | 16 | 'ROOT_URLCONF': '', | ||
177 | 17 | 'STATSD_CLIENT': 'django_statsd.clients.null', | ||
178 | 18 | 'STATSD_PREFIX': None, | ||
179 | 19 | 'METLOG': None | ||
180 | 20 | } | ||
181 | 21 | |||
182 | 22 | if not settings.configured: | ||
183 | 23 | settings.configure(**minimal) | ||
184 | 24 | |||
188 | 25 | from django.core.urlresolvers import reverse | 11 | from django.core.urlresolvers import reverse |
189 | 26 | from django.http import HttpResponse, HttpResponseForbidden | 12 | from django.http import HttpResponse, HttpResponseForbidden |
190 | 27 | from django.test import TestCase | 13 | from django.test import TestCase |
191 | @@ -31,7 +17,13 @@ | |||
192 | 31 | 17 | ||
193 | 32 | import mock | 18 | import mock |
194 | 33 | from nose.tools import eq_ | 19 | from nose.tools import eq_ |
196 | 34 | from django_statsd.clients import get_client | 20 | from django_statsd.clients import get_client, statsd |
197 | 21 | from django_statsd.patches import utils | ||
198 | 22 | from django_statsd.patches.db import ( | ||
199 | 23 | patched_callproc, | ||
200 | 24 | patched_execute, | ||
201 | 25 | patched_executemany, | ||
202 | 26 | ) | ||
203 | 35 | from django_statsd import middleware | 27 | from django_statsd import middleware |
204 | 36 | 28 | ||
205 | 37 | cfg = { | 29 | cfg = { |
206 | @@ -261,7 +253,7 @@ | |||
207 | 261 | STATSD_CLIENT='django_statsd.clients.moz_metlog'): | 253 | STATSD_CLIENT='django_statsd.clients.moz_metlog'): |
208 | 262 | client = get_client() | 254 | client = get_client() |
209 | 263 | client.incr('foo', 2) | 255 | client.incr('foo', 2) |
211 | 264 | 256 | ||
212 | 265 | def test_metlog_prefixes(self): | 257 | def test_metlog_prefixes(self): |
213 | 266 | metlog = self._create_client() | 258 | metlog = self._create_client() |
214 | 267 | 259 | ||
215 | @@ -407,3 +399,159 @@ | |||
216 | 407 | def test_not_emit(self, incr): | 399 | def test_not_emit(self, incr): |
217 | 408 | self.log.error('blargh!') | 400 | self.log.error('blargh!') |
218 | 409 | assert not incr.called | 401 | assert not incr.called |
219 | 402 | |||
220 | 403 | |||
221 | 404 | class TestPatchMethod(TestCase): | ||
222 | 405 | |||
223 | 406 | def setUp(self): | ||
224 | 407 | super(TestPatchMethod, self).setUp() | ||
225 | 408 | |||
226 | 409 | class DummyClass(object): | ||
227 | 410 | |||
228 | 411 | def sumargs(self, a, b, c=3, d=4): | ||
229 | 412 | return a + b + c + d | ||
230 | 413 | |||
231 | 414 | def badfn(self, a, b=2): | ||
232 | 415 | raise ValueError | ||
233 | 416 | |||
234 | 417 | self.cls = DummyClass | ||
235 | 418 | |||
236 | 419 | def test_late_patching(self): | ||
237 | 420 | """ | ||
238 | 421 | Objects created before patching should get patched as well. | ||
239 | 422 | """ | ||
240 | 423 | def patch_fn(original_fn, self, *args, **kwargs): | ||
241 | 424 | return original_fn(self, *args, **kwargs) + 10 | ||
242 | 425 | |||
243 | 426 | obj = self.cls() | ||
244 | 427 | self.assertEqual(obj.sumargs(1, 2, 3, 4), 10) | ||
245 | 428 | utils.patch_method(self.cls, 'sumargs')(patch_fn) | ||
246 | 429 | self.assertEqual(obj.sumargs(1, 2, 3, 4), 20) | ||
247 | 430 | |||
248 | 431 | def test_doesnt_call_original_implicitly(self): | ||
249 | 432 | """ | ||
250 | 433 | Original fn must be called explicitly from patched to be | ||
251 | 434 | executed. | ||
252 | 435 | """ | ||
253 | 436 | def patch_fn(original_fn, self, *args, **kwargs): | ||
254 | 437 | return 10 | ||
255 | 438 | |||
256 | 439 | with self.assertRaises(ValueError): | ||
257 | 440 | obj = self.cls() | ||
258 | 441 | obj.badfn(1, 2) | ||
259 | 442 | |||
260 | 443 | utils.patch_method(self.cls, 'badfn')(patch_fn) | ||
261 | 444 | self.assertEqual(obj.badfn(1, 2), 10) | ||
262 | 445 | |||
263 | 446 | def test_args_kwargs_are_honored(self): | ||
264 | 447 | """ | ||
265 | 448 | Args and kwargs must be honored between calls from the patched to | ||
266 | 449 | the original version. | ||
267 | 450 | """ | ||
268 | 451 | def patch_fn(original_fn, self, *args, **kwargs): | ||
269 | 452 | return original_fn(self, *args, **kwargs) | ||
270 | 453 | |||
271 | 454 | utils.patch_method(self.cls, 'sumargs')(patch_fn) | ||
272 | 455 | obj = self.cls() | ||
273 | 456 | self.assertEqual(obj.sumargs(1, 2), 10) | ||
274 | 457 | self.assertEqual(obj.sumargs(1, 1, d=1), 6) | ||
275 | 458 | self.assertEqual(obj.sumargs(1, 1, 1, 1), 4) | ||
276 | 459 | |||
277 | 460 | def test_patched_fn_can_receive_arbitrary_arguments(self): | ||
278 | 461 | """ | ||
279 | 462 | Args and kwargs can be received arbitrarily with no contraints on | ||
280 | 463 | the patched fn, even if the original_fn had a fixed set of | ||
281 | 464 | allowed args and kwargs. | ||
282 | 465 | """ | ||
283 | 466 | def patch_fn(original_fn, self, *args, **kwargs): | ||
284 | 467 | return args, kwargs | ||
285 | 468 | |||
286 | 469 | utils.patch_method(self.cls, 'badfn')(patch_fn) | ||
287 | 470 | obj = self.cls() | ||
288 | 471 | self.assertEqual(obj.badfn(1, d=2), ((1,), {'d': 2})) | ||
289 | 472 | self.assertEqual(obj.badfn(1, d=2), ((1,), {'d': 2})) | ||
290 | 473 | self.assertEqual(obj.badfn(1, 2, c=1, d=2), ((1, 2), {'c': 1, 'd': 2})) | ||
291 | 474 | |||
292 | 475 | |||
293 | 476 | class TestCursorWrapperPatching(TestCase): | ||
294 | 477 | |||
295 | 478 | def test_patched_callproc_calls_timer(self): | ||
296 | 479 | with mock.patch.object(statsd, 'timer') as timer: | ||
297 | 480 | db = mock.Mock(executable_name='name', alias='alias') | ||
298 | 481 | instance = mock.Mock(db=db) | ||
299 | 482 | patched_callproc(lambda *args, **kwargs: None, instance) | ||
300 | 483 | self.assertEqual(timer.call_count, 1) | ||
301 | 484 | |||
302 | 485 | def test_patched_execute_calls_timer(self): | ||
303 | 486 | with mock.patch.object(statsd, 'timer') as timer: | ||
304 | 487 | db = mock.Mock(executable_name='name', alias='alias') | ||
305 | 488 | instance = mock.Mock(db=db) | ||
306 | 489 | patched_execute(lambda *args, **kwargs: None, instance) | ||
307 | 490 | self.assertEqual(timer.call_count, 1) | ||
308 | 491 | |||
309 | 492 | def test_patched_executemany_calls_timer(self): | ||
310 | 493 | with mock.patch.object(statsd, 'timer') as timer: | ||
311 | 494 | db = mock.Mock(executable_name='name', alias='alias') | ||
312 | 495 | instance = mock.Mock(db=db) | ||
313 | 496 | patched_executemany(lambda *args, **kwargs: None, instance) | ||
314 | 497 | self.assertEqual(timer.call_count, 1) | ||
315 | 498 | |||
316 | 499 | @mock.patch( | ||
317 | 500 | 'django_statsd.patches.db.pre_django_1_6_cursorwrapper_getattr') | ||
318 | 501 | @mock.patch('django_statsd.patches.db.patched_executemany') | ||
319 | 502 | @mock.patch('django_statsd.patches.db.patched_execute') | ||
320 | 503 | @mock.patch('django.db.backends.util.CursorDebugWrapper') | ||
321 | 504 | @skipUnless(VERSION < (1, 6, 0), "CursorWrapper Patching for Django<1.6") | ||
322 | 505 | def test_cursorwrapper_patching(self, | ||
323 | 506 | CursorDebugWrapper, | ||
324 | 507 | execute, | ||
325 | 508 | executemany, | ||
326 | 509 | _getattr): | ||
327 | 510 | try: | ||
328 | 511 | from django.db.backends import util | ||
329 | 512 | |||
330 | 513 | # We need to patch CursorWrapper like this because setting | ||
331 | 514 | # __getattr__ on Mock instances raises AttributeError. | ||
332 | 515 | class CursorWrapper(object): | ||
333 | 516 | pass | ||
334 | 517 | |||
335 | 518 | _CursorWrapper = util.CursorWrapper | ||
336 | 519 | util.CursorWrapper = CursorWrapper | ||
337 | 520 | |||
338 | 521 | from django_statsd.patches.db import patch | ||
339 | 522 | execute.__name__ = 'execute' | ||
340 | 523 | executemany.__name__ = 'executemany' | ||
341 | 524 | _getattr.__name__ = '_getattr' | ||
342 | 525 | execute.return_value = 'execute' | ||
343 | 526 | executemany.return_value = 'executemany' | ||
344 | 527 | _getattr.return_value = 'getattr' | ||
345 | 528 | patch() | ||
346 | 529 | |||
347 | 530 | self.assertEqual(CursorDebugWrapper.execute(), 'execute') | ||
348 | 531 | self.assertEqual(CursorDebugWrapper.executemany(), 'executemany') | ||
349 | 532 | self.assertEqual(CursorWrapper.__getattr__(), 'getattr') | ||
350 | 533 | finally: | ||
351 | 534 | util.CursorWrapper = _CursorWrapper | ||
352 | 535 | |||
353 | 536 | @mock.patch('django_statsd.patches.db.patched_callproc') | ||
354 | 537 | @mock.patch('django_statsd.patches.db.patched_executemany') | ||
355 | 538 | @mock.patch('django_statsd.patches.db.patched_execute') | ||
356 | 539 | @mock.patch('django.db.backends.util.CursorWrapper') | ||
357 | 540 | @skipUnless(VERSION >= (1, 6, 0), "CursorWrapper Patching for Django>=1.6") | ||
358 | 541 | def test_cursorwrapper_patching16(self, | ||
359 | 542 | CursorWrapper, | ||
360 | 543 | execute, | ||
361 | 544 | executemany, | ||
362 | 545 | callproc): | ||
363 | 546 | from django_statsd.patches.db import patch | ||
364 | 547 | execute.__name__ = 'execute' | ||
365 | 548 | executemany.__name__ = 'executemany' | ||
366 | 549 | callproc.__name__ = 'callproc' | ||
367 | 550 | execute.return_value = 'execute' | ||
368 | 551 | executemany.return_value = 'executemany' | ||
369 | 552 | callproc.return_value = 'callproc' | ||
370 | 553 | patch() | ||
371 | 554 | |||
372 | 555 | self.assertEqual(CursorWrapper.execute(), 'execute') | ||
373 | 556 | self.assertEqual(CursorWrapper.executemany(), 'executemany') | ||
374 | 557 | self.assertEqual(CursorWrapper.callproc(), 'callproc') | ||
375 | 410 | 558 | ||
376 | === modified file 'docs/index.rst' | |||
377 | --- docs/index.rst 2014-04-07 18:40:13 +0000 | |||
378 | +++ docs/index.rst 2014-05-01 19:34:04 +0000 | |||
379 | @@ -16,6 +16,10 @@ | |||
380 | 16 | Changes | 16 | Changes |
381 | 17 | ------- | 17 | ------- |
382 | 18 | 18 | ||
383 | 19 | 0.3.12: | ||
384 | 20 | |||
385 | 21 | - Event better Django 1.6 support for the patches, with tests. | ||
386 | 22 | |||
387 | 19 | 0.3.11: | 23 | 0.3.11: |
388 | 20 | 24 | ||
389 | 21 | - Django 1.6 support | 25 | - Django 1.6 support |
390 | @@ -133,7 +137,7 @@ | |||
391 | 133 | statsd.incr('response.200') | 137 | statsd.incr('response.200') |
392 | 134 | 138 | ||
393 | 135 | Django statsd will choose the client as specified in your config and send the | 139 | Django statsd will choose the client as specified in your config and send the |
395 | 136 | data to it. You can change you client by specifying it in the config, the | 140 | data to it. You can change your client by specifying it in the config, the |
396 | 137 | default is:: | 141 | default is:: |
397 | 138 | 142 | ||
398 | 139 | STATSD_CLIENT = 'django_statsd.clients.normal' | 143 | STATSD_CLIENT = 'django_statsd.clients.normal' |
399 | @@ -308,6 +312,13 @@ | |||
400 | 308 | }, | 312 | }, |
401 | 309 | } | 313 | } |
402 | 310 | 314 | ||
403 | 315 | Testing | ||
404 | 316 | ======= | ||
405 | 317 | |||
406 | 318 | You can run tests with the following command: | ||
407 | 319 | |||
408 | 320 | DJANGO_SETTINGS_MODULE='django_statsd.test_settings' nosetests | ||
409 | 321 | |||
410 | 311 | Nose | 322 | Nose |
411 | 312 | ==== | 323 | ==== |
412 | 313 | 324 | ||
413 | @@ -331,6 +342,10 @@ | |||
414 | 331 | * tomchristie | 342 | * tomchristie |
415 | 332 | * diox | 343 | * diox |
416 | 333 | * frewsxcv | 344 | * frewsxcv |
417 | 345 | * fud | ||
418 | 346 | * ftobia | ||
419 | 347 | * jawnb | ||
420 | 348 | * fgallina | ||
421 | 334 | 349 | ||
422 | 335 | See: | 350 | See: |
423 | 336 | 351 | ||
424 | 337 | 352 | ||
425 | === modified file 'requirements.txt' | |||
426 | --- requirements.txt 2013-03-28 14:50:25 +0000 | |||
427 | +++ requirements.txt 2014-05-01 19:34:04 +0000 | |||
428 | @@ -1,4 +1,5 @@ | |||
429 | 1 | mock | 1 | mock |
430 | 2 | nose | 2 | nose |
431 | 3 | unittest2 | ||
432 | 3 | statsd==1.0.0 | 4 | statsd==1.0.0 |
433 | 4 | django<1.5 | 5 | django<1.5 |
434 | 5 | 6 | ||
435 | === modified file 'setup.py' | |||
436 | --- setup.py 2014-04-07 18:40:13 +0000 | |||
437 | +++ setup.py 2014-05-01 19:34:04 +0000 | |||
438 | @@ -4,7 +4,7 @@ | |||
439 | 4 | setup( | 4 | setup( |
440 | 5 | # Because django-statsd was taken, I called this django-statsd-mozilla. | 5 | # Because django-statsd was taken, I called this django-statsd-mozilla. |
441 | 6 | name='django-statsd-mozilla', | 6 | name='django-statsd-mozilla', |
443 | 7 | version='0.3.11', | 7 | version='0.3.12', |
444 | 8 | description='Django interface with statsd', | 8 | description='Django interface with statsd', |
445 | 9 | long_description=open('README.rst').read(), | 9 | long_description=open('README.rst').read(), |
446 | 10 | author='Andy McKay', | 10 | author='Andy McKay', |