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 ...@@ -4,9 +4,11 @@ Features
-------- --------
* Nesting of timers - higher level timers continue to tick during lower-level timers starting/stopping. * Nesting of timers - higher level timers continue to tick during lower-level timers starting/stopping.
* Timing storage in a SQLite DB. * Timing storage in a SQLite DB.
* Can be used as a decorator -or- a context manager.
Usage Usage
----- -----
As a context manager:
```python ```python
from code_block_timer import CodeBlockTimer from code_block_timer import CodeBlockTimer
...@@ -23,11 +25,36 @@ for __ in xrange(2): ...@@ -23,11 +25,36 @@ for __ in xrange(2):
``` ```
In the SQLite DB, you'll now see six rows, similar to these: 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 1|1|all blocks:block1|4003.94415855408|2015-02-15 18:30:32
2|1|all blocks:block2|516.492|2014-10-12 12:26:01 2|1|all blocks:block2|5003.18717956543|2015-02-15 18:30:37
3|1|all blocks|916.54|2014-10-12 12:26:01 3|1|all blocks|11016.9990062714|2015-02-15 18:30:37
4|2|all blocks:block1|199.16|2014-10-12 12:26:04 4|2|all blocks:block1|4003.73291969299|2015-02-15 18:30:43
5|2|all blocks:block2|505.142|2014-10-12 12:26:04 5|2|all blocks:block2|5003.61299514771|2015-02-15 18:30:48
6|2|all blocks|903.212|2014-10-12 12:26:04 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 @@ ...@@ -12,11 +12,9 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import functools
import threading import threading
from timeit import default_timer from timeit import default_timer
from code_block_timer.storage import TimingDataStorage
import storage
class Globals(threading.local): class Globals(threading.local):
...@@ -69,12 +67,8 @@ class CodeBlockTimer(object): ...@@ -69,12 +67,8 @@ class CodeBlockTimer(object):
self.block_desc, self.elapsed self.block_desc, self.elapsed
) )
def __call__(self, func):
def code_block_timer(block_desc, **cbt_kwargs): def wrapper(*args, **kwargs):
def outer(func): with self:
@functools.wraps(func)
def inner(*args, **kwargs):
with CodeBlockTimer(block_desc, **cbt_kwargs):
return func(*args, **kwargs) return func(*args, **kwargs)
return inner return wrapper
return outer
import mock
import os import os
import unittest import unittest
import random import random
import math import math
import sqlite3 import sqlite3
from code_block_timer import CodeBlockTimer, code_block_timer, _m import mock
import ddt import ddt
from code_block_timer import CodeBlockTimer, _m
@ddt.ddt @ddt.ddt
...@@ -37,14 +37,17 @@ class TestCodeBlockTimer(unittest.TestCase): ...@@ -37,14 +37,17 @@ class TestCodeBlockTimer(unittest.TestCase):
z = math.factorial(10) z = math.factorial(10)
self._verifyEvents(run_id, ['test', ] + ["test:{}".format(x) for x in iterations]) 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): 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() #@code_block_timer('decorator_test', db_name=self.db_name)
mock_class.return_value = store @CodeBlockTimer('decorator_test', db_name=self.db_name)
store.run_id.return_value = 45
@code_block_timer('decorator_test', db_name=self.db_name)
def wrapped_thing(*args, **kwargs): def wrapped_thing(*args, **kwargs):
self.assertEquals(args, ('an_arg',)) self.assertEquals(args, ('an_arg',))
self.assertEquals(kwargs, {'a_dict': {}}) self.assertEquals(kwargs, {'a_dict': {}})
...@@ -52,9 +55,12 @@ class TestCodeBlockTimer(unittest.TestCase): ...@@ -52,9 +55,12 @@ class TestCodeBlockTimer(unittest.TestCase):
test_dict = {} test_dict = {}
run_id = wrapped_thing('an_arg', a_dict=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) mock_class.assert_called_once_with(db_name=self.db_name)
# Was wrapped_thing() called -and- did it complete?
self.assertTrue(test_dict['entered']) 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): def test_exception_handled(self):
msg = "exception_but_still_timed" msg = "exception_but_still_timed"
...@@ -74,8 +80,8 @@ class TestCodeBlockTimer(unittest.TestCase): ...@@ -74,8 +80,8 @@ class TestCodeBlockTimer(unittest.TestCase):
z = math.factorial(10) z = math.factorial(10)
self._verifyEvents(run_id, ['test', 'test:delimiter']) self._verifyEvents(run_id, ['test', 'test:delimiter'])
@ddt.data(':::::', '%', '-', '/') @ddt.data(':::::', '%', '-', '/', '')
def test_delimiters(self, delimiter): def test_arbitrary_delimiters(self, delimiter):
with CodeBlockTimer("test", delimiter=delimiter, db_name=self.db_name) as timer: with CodeBlockTimer("test", delimiter=delimiter, db_name=self.db_name) as timer:
run_id = _m.run_id run_id = _m.run_id
with CodeBlockTimer("delimiter", delimiter=delimiter, db_name=self.db_name) as inner: with CodeBlockTimer("delimiter", delimiter=delimiter, db_name=self.db_name) as inner:
......
# Packages needed for testing only.
ddt==1.0.0 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