Commit dca04ff6 by John Eskew

Merge pull request #6 from doctoryes/doctoryes/combine_decorator_and_context_mgr

Merge context manager and decorator to single class.
parents 3882cc77 c20b6f70
......@@ -4,9 +4,11 @@ Features
--------
* Nesting of timers - higher level timers continue to tick during lower-level timers starting/stopping.
* Timing storage in a SQLite DB.
* Can be used as a decorator -or- a context manager.
Usage
-----
As a context manager:
```python
from code_block_timer import CodeBlockTimer
......@@ -23,11 +25,36 @@ for __ in xrange(2):
```
In the SQLite DB, you'll now see six rows, similar to these:
```
1|1|all blocks:block1|201.16|2014-10-12 12:26:01
2|1|all blocks:block2|516.492|2014-10-12 12:26:01
3|1|all blocks|916.54|2014-10-12 12:26:01
4|2|all blocks:block1|199.16|2014-10-12 12:26:04
5|2|all blocks:block2|505.142|2014-10-12 12:26:04
6|2|all blocks|903.212|2014-10-12 12:26:04
1|1|all blocks:block1|4003.94415855408|2015-02-15 18:30:32
2|1|all blocks:block2|5003.18717956543|2015-02-15 18:30:37
3|1|all blocks|11016.9990062714|2015-02-15 18:30:37
4|2|all blocks:block1|4003.73291969299|2015-02-15 18:30:43
5|2|all blocks:block2|5003.61299514771|2015-02-15 18:30:48
6|2|all blocks|11017.0860290527|2015-02-15 18:30:48
```
---
As a decorator:
```python
from code_block_timer import CodeBlockTimer
@CodeBlockTimer('method2')
def perform_another_lengthy_task():
# Do several things.
pass
@CodeBlockTimer('method1')
def perform_lengthy_task():
# Do several things.
perform_another_lengthy_task()
for __ in xrange(2):
perform_lengthy_task()
```
In the SQLite DB, you'll now see four rows, similar to these:
```
1|1|method1:method2|2000.66590309143|2015-02-15 18:38:40
2|1|method1|3005.31411170959|2015-02-15 18:38:40
3|2|method1:method2|2001.1157989502|2015-02-15 18:38:43
4|2|method1|3003.61204147339|2015-02-15 18:38:43
```
......@@ -12,11 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import threading
from timeit import default_timer
import storage
from code_block_timer.storage import TimingDataStorage
class Globals(threading.local):
......@@ -69,12 +67,8 @@ class CodeBlockTimer(object):
self.block_desc, self.elapsed
)
def code_block_timer(block_desc, **cbt_kwargs):
def outer(func):
@functools.wraps(func)
def inner(*args, **kwargs):
with CodeBlockTimer(block_desc, **cbt_kwargs):
def __call__(self, func):
def wrapper(*args, **kwargs):
with self:
return func(*args, **kwargs)
return inner
return outer
return wrapper
import mock
import os
import unittest
import random
import math
import sqlite3
from code_block_timer import CodeBlockTimer, code_block_timer, _m
import mock
import ddt
from code_block_timer import CodeBlockTimer, _m
@ddt.ddt
......@@ -37,14 +37,17 @@ class TestCodeBlockTimer(unittest.TestCase):
z = math.factorial(10)
self._verifyEvents(run_id, ['test', ] + ["test:{}".format(x) for x in iterations])
@mock.patch('code_block_timer.storage.TimingDataStorage')
@mock.patch('code_block_timer.TimingDataStorage')
def test_decorator(self, mock_class):
"""
Test the decorator for timing - but mock out the storage.
"""
timing_storage = mock.Mock()
timing_storage.run_id.return_value = 45
mock_class.return_value = timing_storage
store = mock.Mock()
mock_class.return_value = store
store.run_id.return_value = 45
@code_block_timer('decorator_test', db_name=self.db_name)
#@code_block_timer('decorator_test', db_name=self.db_name)
@CodeBlockTimer('decorator_test', db_name=self.db_name)
def wrapped_thing(*args, **kwargs):
self.assertEquals(args, ('an_arg',))
self.assertEquals(kwargs, {'a_dict': {}})
......@@ -52,9 +55,12 @@ class TestCodeBlockTimer(unittest.TestCase):
test_dict = {}
run_id = wrapped_thing('an_arg', a_dict=test_dict)
# Was the TimingStorage class itself constructed?
mock_class.assert_called_once_with(db_name=self.db_name)
# Was wrapped_thing() called -and- did it complete?
self.assertTrue(test_dict['entered'])
store.store.assert_called_with(45, 'decorator_test', mock.ANY)
# Did the TimingStorage.store() method get called with the proper params?
timing_storage.store.assert_called_with(45, 'decorator_test', mock.ANY)
def test_exception_handled(self):
msg = "exception_but_still_timed"
......@@ -74,8 +80,8 @@ class TestCodeBlockTimer(unittest.TestCase):
z = math.factorial(10)
self._verifyEvents(run_id, ['test', 'test:delimiter'])
@ddt.data(':::::', '%', '-', '/')
def test_delimiters(self, delimiter):
@ddt.data(':::::', '%', '-', '/', '')
def test_arbitrary_delimiters(self, delimiter):
with CodeBlockTimer("test", delimiter=delimiter, db_name=self.db_name) as timer:
run_id = _m.run_id
with CodeBlockTimer("delimiter", delimiter=delimiter, db_name=self.db_name) as inner:
......
# Packages needed for testing only.
ddt==1.0.0
path.py==7.2
mock==1.0.1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment