Skip to content

Commit

Permalink
Merge pull request #42 from StasEvseev/feature/pass_func_into_hooks
Browse files Browse the repository at this point in the history
NEW: Pass func/method in hooks
  • Loading branch information
ricardosantosalves authored May 10, 2019
2 parents f2c99d0 + 9ccfaeb commit 0d1f1f1
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 17 deletions.
53 changes: 38 additions & 15 deletions tests/test_hooks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import unittest

import pytest
from fqn_decorators import get_fqn
from tests.conftest import go
from time_execution import settings, time_execution
Expand Down Expand Up @@ -33,7 +32,7 @@ def global_hook(**kwargs):
return dict(global_hook_key='global hook value')


class TestTimeExecution(unittest.TestCase):
class TestTimeExecution:
def test_custom_hook(self):
with settings(backends=[CollectorBackend()], hooks=[global_hook]):
collector = settings.backends[0]
Expand Down Expand Up @@ -146,18 +145,42 @@ def method_local_hook(self):
assert metadata["local_hook_key"] == "local hook value"
collector.clean()

def test_old_hooks(self):
def old_hook(response, exception, metric, func_args, func_kwargs):
return dict(old_hook='old_hook')

def new_hook(response, exception, metric, func, func_args, func_kwargs):
return dict(new_hook='new_hook', attribute_from_class=func.__self__.attr)

class Class:
attr = 1

@time_execution
def method(self):
return True

with settings(backends=[CollectorBackend()], hooks=[old_hook, new_hook]):
collector = settings.backends[0]
Class().method()

assert len(collector.metrics) == 1
metadata = collector.metrics[0][get_fqn(Class().method)]
assert "old_hook" in metadata
assert "new_hook" in metadata
assert metadata["attribute_from_class"] == Class.attr

def test_hook(self):
def test_args(**kwargs):
self.assertIn('response', kwargs)
self.assertIn('exception', kwargs)
self.assertIn('metric', kwargs)
assert 'response' in kwargs
assert 'exception' in kwargs
assert 'metric' in kwargs
return dict()

def test_metadata(*args, **kwargs):
return dict(test_key='test value')

def asserts(name, **data):
self.assertEqual(data['test_key'], 'test value')
assert data['test_key'] == 'test value'

with settings(backends=[AssertBackend(asserts)],
hooks=[test_args, test_metadata]):
Expand All @@ -170,19 +193,19 @@ class TimeExecutionException(Exception):
pass

def exception_hook(exception, **kwargs):
self.assertIsInstance(exception, TimeExecutionException)
assert isinstance(exception, (TimeExecutionException,))
return dict(exception_message=str(exception))

def asserts(name, **data):
self.assertEqual(data['exception_message'], message)
assert data['exception_message'] == message

@time_execution
def go():
raise TimeExecutionException(message)

with settings(backends=[AssertBackend(asserts)],
hooks=[exception_hook]):
with self.assertRaises(TimeExecutionException):
with pytest.raises(TimeExecutionException):
go()

def test_hook_exception_args(self):
Expand All @@ -193,19 +216,19 @@ def __init__(self, msg, required):
super(TimeExecutionException, self).__init__(msg)

def exception_hook(exception, **kwargs):
self.assertIsInstance(exception, TimeExecutionException)
assert isinstance(exception, (TimeExecutionException,))
return dict(exception_message=str(exception))

def asserts(name, **data):
self.assertEqual(data['exception_message'], message)
assert data['exception_message'] == message

@time_execution
def go():
raise TimeExecutionException(message, True)

with settings(backends=[AssertBackend(asserts)],
hooks=[exception_hook]):
with self.assertRaises(TimeExecutionException):
with pytest.raises(TimeExecutionException):
go()

def test_hook_func_args(self):
Expand All @@ -216,7 +239,7 @@ def go(param1):
return '200 OK'

def hook(response, exception, metric, func_args, func_kwargs):
self.assertEqual(func_args[0], param)
assert func_args[0] == param

with settings(hooks=[hook]):
go(param)
Expand All @@ -229,7 +252,7 @@ def go(param1):
return '200 OK'

def hook(response, exception, metric, func_args, func_kwargs):
self.assertEqual(func_kwargs['param1'], param)
assert func_kwargs['param1'] == param

with settings(hooks=[hook]):
go(param1=param)
22 changes: 20 additions & 2 deletions time_execution/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
"""
import socket
import time
import warnings

import six
from fqn_decorators import Decorator
from pkgsettings import Settings

from .constants import PY_35_GT
from .deprecation import HookDeprecatedWarning

warnings.simplefilter('once', HookDeprecatedWarning)

SHORT_HOSTNAME = socket.gethostname()

Expand All @@ -25,10 +29,23 @@ def write_metric(name, **metric):
backend.write(name, **metric)


def _apply_hooks(hooks, **kwargs):
def _apply_hooks(hooks, response, exception, metric, func, func_args, func_kwargs):
metadata = dict()
for hook in hooks:
hook_result = hook(**kwargs)
# backward compatibility with old hooks
try:
hook_result = hook(
response=response, exception=exception, metric=metric, func=func, func_args=func_args,
func_kwargs=func_kwargs
)
except TypeError:
warnings.warn(
"Hook %s is outdated. Update interface by adding one more argument `func` in it." % hook.__name__,
HookDeprecatedWarning)
hook_result = hook(
response=response, exception=exception, metric=metric, func_args=func_args, func_kwargs=func_kwargs
)

if hook_result:
metadata.update(hook_result)
return metadata
Expand Down Expand Up @@ -69,6 +86,7 @@ def after(self):
response=self.result,
exception=self.get_exception(),
metric=metric,
func=self.func,
func_args=self.args,
func_kwargs=self.kwargs
)
Expand Down
2 changes: 2 additions & 0 deletions time_execution/deprecation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class HookDeprecatedWarning(DeprecationWarning):
pass

0 comments on commit 0d1f1f1

Please sign in to comment.