Skip to content

Commit 91e12fe

Browse files
authored
Merge pull request #32 from targhs/feature/add-sample-decorator
Add sample decorator
2 parents 372ad49 + a937f58 commit 91e12fe

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from unittest.mock import MagicMock
2+
3+
import pytest
4+
5+
from python_utils.decorators import sample
6+
7+
8+
@pytest.fixture
9+
def random(monkeypatch):
10+
mock = MagicMock()
11+
monkeypatch.setattr("python_utils.decorators.random.random", mock, raising=True)
12+
return mock
13+
14+
15+
def test_sample_called(random):
16+
demo_function = MagicMock()
17+
decorated = sample(0.5)(demo_function)
18+
random.return_value = 0.4
19+
decorated()
20+
random.return_value = 0.0
21+
decorated()
22+
args = [1, 2]
23+
kwargs = {"1": 1, "2": 2}
24+
decorated(*args, **kwargs)
25+
demo_function.assert_called_with(*args, **kwargs)
26+
assert demo_function.call_count == 3
27+
28+
29+
def test_sample_not_called(random):
30+
demo_function = MagicMock()
31+
decorated = sample(0.5)(demo_function)
32+
random.return_value = 0.5
33+
decorated()
34+
random.return_value = 1.0
35+
decorated()
36+
assert demo_function.call_count == 0

python_utils/decorators.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import functools
2+
import logging
3+
import random
24
from . import types
35

46

@@ -92,3 +94,30 @@ def __listify(*args, **kwargs):
9294
return __listify
9395

9496
return _listify
97+
98+
99+
def sample(sample_rate: float):
100+
'''
101+
Limit calls to a function based on given sample rate.
102+
Number of calls to the function will be roughly equal to
103+
sample_rate percentage.
104+
105+
Usage:
106+
107+
>>> @sample(0.5)
108+
... def demo_function(*args, **kwargs):
109+
... return 1
110+
111+
Calls to *demo_function* will be limited to 50% approximatly.
112+
113+
'''
114+
def _sample(function):
115+
@functools.wraps(function)
116+
def __sample(*args, **kwargs):
117+
if random.random() < sample_rate:
118+
return function(*args, **kwargs)
119+
else:
120+
logging.debug('Skipped execution of %r(%r, %r) due to sampling', function, args, kwargs) # noqa: E501
121+
122+
return __sample
123+
return _sample

0 commit comments

Comments
 (0)