pylemetry 0.1.3__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pylemetry-0.1.3 → pylemetry-0.1.4}/.github/workflows/release.yaml +4 -1
- {pylemetry-0.1.3 → pylemetry-0.1.4}/PKG-INFO +35 -5
- {pylemetry-0.1.3 → pylemetry-0.1.4}/README.md +34 -4
- {pylemetry-0.1.3 → pylemetry-0.1.4}/pyproject.toml +1 -1
- pylemetry-0.1.4/src/pylemetry/decorators/count.py +35 -0
- pylemetry-0.1.4/src/pylemetry/decorators/time.py +34 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/pylemetry/meters/timer.py +19 -1
- {pylemetry-0.1.3 → pylemetry-0.1.4}/test/test_pylemetry/decorators/test_count.py +11 -1
- {pylemetry-0.1.3 → pylemetry-0.1.4}/test/test_pylemetry/decorators/test_time.py +11 -1
- {pylemetry-0.1.3 → pylemetry-0.1.4}/test/test_pylemetry/meters/test_timer.py +16 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/uv.lock +1 -1
- pylemetry-0.1.3/src/pylemetry/decorators/count.py +0 -32
- pylemetry-0.1.3/src/pylemetry/decorators/time.py +0 -31
- {pylemetry-0.1.3 → pylemetry-0.1.4}/.github/actions/configure-uv/action.yaml +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/.github/workflows/ci.yaml +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/.gitignore +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/LICENSE +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/py.typed +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/__init__.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/pylemetry/__init__.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/pylemetry/decorators/__init__.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/pylemetry/meters/__init__.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/pylemetry/meters/counter.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/pylemetry/meters/gauge.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/src/pylemetry/registry.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/test/conftest.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/test/test_pylemetry/meters/test_counter.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/test/test_pylemetry/meters/test_gauge.py +0 -0
- {pylemetry-0.1.3 → pylemetry-0.1.4}/test/test_pylemetry/test_registry.py +0 -0
|
@@ -42,6 +42,8 @@ jobs:
|
|
|
42
42
|
|
|
43
43
|
steps:
|
|
44
44
|
- uses: actions/checkout@v5
|
|
45
|
+
with:
|
|
46
|
+
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
|
45
47
|
|
|
46
48
|
- uses: ./.github/actions/configure-uv
|
|
47
49
|
|
|
@@ -72,4 +74,5 @@ jobs:
|
|
|
72
74
|
- name: Commit Version Bump
|
|
73
75
|
uses: EndBug/add-and-commit@v9
|
|
74
76
|
with:
|
|
75
|
-
message: "Bump project version following release"
|
|
77
|
+
message: "Bump project version following release [skip ci]"
|
|
78
|
+
default_author: github_actions
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pylemetry
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A Python metrics library
|
|
5
5
|
Project-URL: Homepage, https://pypi.org/project/pylemetry/
|
|
6
6
|
Project-URL: Repository, https://github.com/amurphy4/pylemetry
|
|
@@ -22,6 +22,13 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
|
|
23
23
|
# Pylemetry
|
|
24
24
|
|
|
25
|
+
[](https://github.com/astral-sh/uv)
|
|
26
|
+
[](https://github.com/astral-sh/ruff)
|
|
27
|
+
[](https://pypi.python.org/pypi/pylemetry)
|
|
28
|
+
[](https://pypi.python.org/pypi/pylemetry)
|
|
29
|
+
[](https://pypi.python.org/pypi/pylemetry)
|
|
30
|
+
[](https://github.com/amurphy4/pylemetry/actions/workflows/release.yaml)
|
|
31
|
+
|
|
25
32
|
Add metrics to your Python applications with Pylemetry
|
|
26
33
|
|
|
27
34
|
Currently, three meters are supported, `Counter`, `Gauge`, and `Timer`
|
|
@@ -51,20 +58,29 @@ from pylemetry import Registry
|
|
|
51
58
|
from pylemetry.decorators import count
|
|
52
59
|
|
|
53
60
|
|
|
54
|
-
@count
|
|
61
|
+
@count()
|
|
55
62
|
def some_method() -> None:
|
|
56
63
|
...
|
|
57
64
|
|
|
58
65
|
|
|
66
|
+
@count("named_counter")
|
|
67
|
+
def another_method() -> None:
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
|
|
59
71
|
def main() -> None:
|
|
60
72
|
for _ in range(100):
|
|
61
73
|
some_method()
|
|
74
|
+
another_method()
|
|
62
75
|
|
|
63
76
|
counter = Registry().get_counter("some_method")
|
|
64
77
|
counter.get_count() # 100
|
|
78
|
+
|
|
79
|
+
counter = Registry.get_counter("named_counter")
|
|
80
|
+
counter.get_count() # 100
|
|
65
81
|
```
|
|
66
82
|
|
|
67
|
-
When using this meter via a decorator, the meter gets added to the global `Registry`, with the method name it's decorating as the meter name
|
|
83
|
+
When using this meter via a decorator, the meter gets added to the global `Registry`, with the method name it's decorating as the meter name. Alternatively, you can provide a name for the meter as a parameter to the decorator
|
|
68
84
|
|
|
69
85
|
## Gauge
|
|
70
86
|
|
|
@@ -95,7 +111,7 @@ gauge.get_value() # 11.5
|
|
|
95
111
|
|
|
96
112
|
gauge.subtract(10)
|
|
97
113
|
gauge -= 8.5
|
|
98
|
-
gauge.get_value() # -
|
|
114
|
+
gauge.get_value() # -8
|
|
99
115
|
|
|
100
116
|
gauge.set_value(7.5)
|
|
101
117
|
gauge.get_value() # 7.5
|
|
@@ -127,20 +143,34 @@ from pylemetry import Registry
|
|
|
127
143
|
from pylemetry.decorators import time
|
|
128
144
|
|
|
129
145
|
|
|
130
|
-
@time
|
|
146
|
+
@time()
|
|
131
147
|
def some_method() -> None:
|
|
132
148
|
...
|
|
133
149
|
|
|
134
150
|
|
|
151
|
+
@time("named_timer")
|
|
152
|
+
def another_method() -> None:
|
|
153
|
+
...
|
|
154
|
+
|
|
155
|
+
|
|
135
156
|
def main() -> None:
|
|
136
157
|
for _ in range(100):
|
|
137
158
|
some_method()
|
|
159
|
+
another_method()
|
|
138
160
|
|
|
139
161
|
timer = Registry().get_timer("some_method")
|
|
140
162
|
timer.get_count() # 100
|
|
141
163
|
timer.get_mean_tick_time() # Mean execution time of the some_method function
|
|
164
|
+
timer.get_max_tick_time() # Maximum execution time of the some_method function
|
|
165
|
+
timer.get_min_tick_time() # Minimum execution time of the some_method function
|
|
166
|
+
|
|
167
|
+
timer = Registry().get_timer("named_timer")
|
|
168
|
+
timer.get_count() # 100
|
|
169
|
+
...
|
|
142
170
|
```
|
|
143
171
|
|
|
172
|
+
When using this meter via a decorator, the meter gets added to the global `Registry`, with the method name it's decorating as the meter name. Alternatively, you can provide a name for the meter as a parameter to the decorator
|
|
173
|
+
|
|
144
174
|
## The Registry
|
|
145
175
|
|
|
146
176
|
Pylemetry maintains a global registry of meters, allowing you to share a meter across multiple files, or reference metrics from a central location.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Pylemetry
|
|
2
2
|
|
|
3
|
+
[](https://github.com/astral-sh/uv)
|
|
4
|
+
[](https://github.com/astral-sh/ruff)
|
|
5
|
+
[](https://pypi.python.org/pypi/pylemetry)
|
|
6
|
+
[](https://pypi.python.org/pypi/pylemetry)
|
|
7
|
+
[](https://pypi.python.org/pypi/pylemetry)
|
|
8
|
+
[](https://github.com/amurphy4/pylemetry/actions/workflows/release.yaml)
|
|
9
|
+
|
|
3
10
|
Add metrics to your Python applications with Pylemetry
|
|
4
11
|
|
|
5
12
|
Currently, three meters are supported, `Counter`, `Gauge`, and `Timer`
|
|
@@ -29,20 +36,29 @@ from pylemetry import Registry
|
|
|
29
36
|
from pylemetry.decorators import count
|
|
30
37
|
|
|
31
38
|
|
|
32
|
-
@count
|
|
39
|
+
@count()
|
|
33
40
|
def some_method() -> None:
|
|
34
41
|
...
|
|
35
42
|
|
|
36
43
|
|
|
44
|
+
@count("named_counter")
|
|
45
|
+
def another_method() -> None:
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
|
|
37
49
|
def main() -> None:
|
|
38
50
|
for _ in range(100):
|
|
39
51
|
some_method()
|
|
52
|
+
another_method()
|
|
40
53
|
|
|
41
54
|
counter = Registry().get_counter("some_method")
|
|
42
55
|
counter.get_count() # 100
|
|
56
|
+
|
|
57
|
+
counter = Registry.get_counter("named_counter")
|
|
58
|
+
counter.get_count() # 100
|
|
43
59
|
```
|
|
44
60
|
|
|
45
|
-
When using this meter via a decorator, the meter gets added to the global `Registry`, with the method name it's decorating as the meter name
|
|
61
|
+
When using this meter via a decorator, the meter gets added to the global `Registry`, with the method name it's decorating as the meter name. Alternatively, you can provide a name for the meter as a parameter to the decorator
|
|
46
62
|
|
|
47
63
|
## Gauge
|
|
48
64
|
|
|
@@ -73,7 +89,7 @@ gauge.get_value() # 11.5
|
|
|
73
89
|
|
|
74
90
|
gauge.subtract(10)
|
|
75
91
|
gauge -= 8.5
|
|
76
|
-
gauge.get_value() # -
|
|
92
|
+
gauge.get_value() # -8
|
|
77
93
|
|
|
78
94
|
gauge.set_value(7.5)
|
|
79
95
|
gauge.get_value() # 7.5
|
|
@@ -105,20 +121,34 @@ from pylemetry import Registry
|
|
|
105
121
|
from pylemetry.decorators import time
|
|
106
122
|
|
|
107
123
|
|
|
108
|
-
@time
|
|
124
|
+
@time()
|
|
109
125
|
def some_method() -> None:
|
|
110
126
|
...
|
|
111
127
|
|
|
112
128
|
|
|
129
|
+
@time("named_timer")
|
|
130
|
+
def another_method() -> None:
|
|
131
|
+
...
|
|
132
|
+
|
|
133
|
+
|
|
113
134
|
def main() -> None:
|
|
114
135
|
for _ in range(100):
|
|
115
136
|
some_method()
|
|
137
|
+
another_method()
|
|
116
138
|
|
|
117
139
|
timer = Registry().get_timer("some_method")
|
|
118
140
|
timer.get_count() # 100
|
|
119
141
|
timer.get_mean_tick_time() # Mean execution time of the some_method function
|
|
142
|
+
timer.get_max_tick_time() # Maximum execution time of the some_method function
|
|
143
|
+
timer.get_min_tick_time() # Minimum execution time of the some_method function
|
|
144
|
+
|
|
145
|
+
timer = Registry().get_timer("named_timer")
|
|
146
|
+
timer.get_count() # 100
|
|
147
|
+
...
|
|
120
148
|
```
|
|
121
149
|
|
|
150
|
+
When using this meter via a decorator, the meter gets added to the global `Registry`, with the method name it's decorating as the meter name. Alternatively, you can provide a name for the meter as a parameter to the decorator
|
|
151
|
+
|
|
122
152
|
## The Registry
|
|
123
153
|
|
|
124
154
|
Pylemetry maintains a global registry of meters, allowing you to share a meter across multiple files, or reference metrics from a central location.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Callable, Any, Optional
|
|
2
|
+
|
|
3
|
+
from functools import wraps
|
|
4
|
+
|
|
5
|
+
from pylemetry import Registry
|
|
6
|
+
from pylemetry.meters import Counter
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def count(name: Optional[str] = None) -> Callable[..., Any]:
|
|
10
|
+
"""
|
|
11
|
+
Decorator to count the number of invocations of a given callable. Creates a Counter meter in the Registry
|
|
12
|
+
with either the provided name or the fully qualified name of the callable object as the metric name.
|
|
13
|
+
|
|
14
|
+
:param name: Name of the meter to create, if None the function name is used
|
|
15
|
+
:return: Result of the wrapped function
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
19
|
+
@wraps(f)
|
|
20
|
+
def wrapper() -> Any:
|
|
21
|
+
counter_name = f.__qualname__ if name is None else name
|
|
22
|
+
|
|
23
|
+
counter = Registry().get_counter(counter_name)
|
|
24
|
+
|
|
25
|
+
if not counter:
|
|
26
|
+
counter = Counter()
|
|
27
|
+
Registry().add_counter(counter_name, counter)
|
|
28
|
+
|
|
29
|
+
counter += 1
|
|
30
|
+
|
|
31
|
+
return f()
|
|
32
|
+
|
|
33
|
+
return wrapper
|
|
34
|
+
|
|
35
|
+
return decorator
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import Callable, Any, Optional
|
|
2
|
+
|
|
3
|
+
from functools import wraps
|
|
4
|
+
|
|
5
|
+
from pylemetry import Registry
|
|
6
|
+
from pylemetry.meters import Timer
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def time(name: Optional[str] = None) -> Callable[..., Any]:
|
|
10
|
+
"""
|
|
11
|
+
Decorator to time the invocations of a given callable. Creates a Timer meter in the Registry with either the
|
|
12
|
+
provided name or the fully qualified name of the callable object as the metric name.
|
|
13
|
+
|
|
14
|
+
:param name: Name of the meter to create, if None the function name is used
|
|
15
|
+
:return: Result of the wrapped function
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
19
|
+
@wraps(f)
|
|
20
|
+
def wrapper() -> Any:
|
|
21
|
+
time_name = f.__qualname__ if name is None else name
|
|
22
|
+
|
|
23
|
+
_timer = Registry().get_timer(time_name)
|
|
24
|
+
|
|
25
|
+
if not _timer:
|
|
26
|
+
_timer = Timer()
|
|
27
|
+
Registry().add_timer(time_name, _timer)
|
|
28
|
+
|
|
29
|
+
with _timer.time():
|
|
30
|
+
return f()
|
|
31
|
+
|
|
32
|
+
return wrapper
|
|
33
|
+
|
|
34
|
+
return decorator
|
|
@@ -24,7 +24,7 @@ class Timer:
|
|
|
24
24
|
@contextmanager
|
|
25
25
|
def time(self) -> Generator[None, None, None]:
|
|
26
26
|
"""
|
|
27
|
-
Context manager to time a code block and add the result to the internal ticks list
|
|
27
|
+
Context manager to time in seconds a code block and add the result to the internal ticks list
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
30
|
start_time = time.perf_counter()
|
|
@@ -53,3 +53,21 @@ class Timer:
|
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
55
|
return sum(self.ticks) / len(self.ticks)
|
|
56
|
+
|
|
57
|
+
def get_max_tick_time(self) -> float:
|
|
58
|
+
"""
|
|
59
|
+
Get the maximum tick time from the list of ticks within this timer
|
|
60
|
+
|
|
61
|
+
:return: Maximum tick time
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
return max(self.ticks)
|
|
65
|
+
|
|
66
|
+
def get_min_tick_time(self) -> float:
|
|
67
|
+
"""
|
|
68
|
+
Get the minimum tick time from the list of ticks within this timer
|
|
69
|
+
|
|
70
|
+
:return: Minimum tick time
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
return min(self.ticks)
|
|
@@ -5,7 +5,7 @@ from pylemetry.decorators import count
|
|
|
5
5
|
from pylemetry.meters import Counter
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
@count
|
|
8
|
+
@count()
|
|
9
9
|
def mock_function() -> str:
|
|
10
10
|
return "A function decorated with the count decorator"
|
|
11
11
|
|
|
@@ -36,3 +36,13 @@ def test_count_decorator_updates_existing_counter(call_count: int) -> None:
|
|
|
36
36
|
|
|
37
37
|
assert isinstance(counter, Counter)
|
|
38
38
|
assert counter.get_count() == call_count
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_count_decorator_with_name() -> None:
|
|
42
|
+
@count(name="test_count_meter")
|
|
43
|
+
def mock() -> None:
|
|
44
|
+
print("Mock method")
|
|
45
|
+
|
|
46
|
+
mock()
|
|
47
|
+
|
|
48
|
+
assert "test_count_meter" in Registry().counters
|
|
@@ -5,7 +5,7 @@ from pylemetry.decorators import time
|
|
|
5
5
|
from pylemetry.meters import Timer
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
@time
|
|
8
|
+
@time()
|
|
9
9
|
def mock_function() -> str:
|
|
10
10
|
return "A function decorated with the timer decorator"
|
|
11
11
|
|
|
@@ -38,3 +38,13 @@ def test_count_decorator_updates_existing_counter(call_count: int) -> None:
|
|
|
38
38
|
assert isinstance(timer, Timer)
|
|
39
39
|
assert timer.get_count() == call_count
|
|
40
40
|
assert 0 < timer.get_mean_tick_time() < 0.05
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_time_decorator_with_name() -> None:
|
|
44
|
+
@time(name="test_timer_meter")
|
|
45
|
+
def mock() -> None:
|
|
46
|
+
print("Mock method")
|
|
47
|
+
|
|
48
|
+
mock()
|
|
49
|
+
|
|
50
|
+
assert "test_timer_meter" in Registry().timers
|
|
@@ -36,3 +36,19 @@ def test_get_mean_tick_time() -> None:
|
|
|
36
36
|
timer.ticks = [1, 2, 3, 4, 5]
|
|
37
37
|
|
|
38
38
|
assert timer.get_mean_tick_time() == 3
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_get_max_tick_time() -> None:
|
|
42
|
+
timer = Timer()
|
|
43
|
+
|
|
44
|
+
timer.ticks = [1, 2, 3, 4, 5]
|
|
45
|
+
|
|
46
|
+
assert timer.get_max_tick_time() == 5
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_get_min_tick_time() -> None:
|
|
50
|
+
timer = Timer()
|
|
51
|
+
|
|
52
|
+
timer.ticks = [1, 2, 3, 4, 5]
|
|
53
|
+
|
|
54
|
+
assert timer.get_min_tick_time() == 1
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
from typing import Callable, Any
|
|
2
|
-
|
|
3
|
-
from functools import wraps
|
|
4
|
-
|
|
5
|
-
from pylemetry import Registry
|
|
6
|
-
from pylemetry.meters import Counter
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def count(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
10
|
-
"""
|
|
11
|
-
Decorator to count the number of invocations of a given callable. Creates a Counter meter in the Registry
|
|
12
|
-
with the fully qualified name of the callable object as the metric name.
|
|
13
|
-
|
|
14
|
-
:param f: Callable to wrap
|
|
15
|
-
:return: Result of f
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
@wraps(f)
|
|
19
|
-
def wrapper() -> Any:
|
|
20
|
-
counter_name = f.__qualname__
|
|
21
|
-
|
|
22
|
-
counter = Registry().get_counter(counter_name)
|
|
23
|
-
|
|
24
|
-
if not counter:
|
|
25
|
-
counter = Counter()
|
|
26
|
-
Registry().add_counter(counter_name, counter)
|
|
27
|
-
|
|
28
|
-
counter += 1
|
|
29
|
-
|
|
30
|
-
return f()
|
|
31
|
-
|
|
32
|
-
return wrapper
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from typing import Callable, Any
|
|
2
|
-
|
|
3
|
-
from functools import wraps
|
|
4
|
-
|
|
5
|
-
from pylemetry import Registry
|
|
6
|
-
from pylemetry.meters import Timer
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def time(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
10
|
-
"""
|
|
11
|
-
Decorator to time the invocations of a given callable. Creates a Timer meter in the Registry with the fully
|
|
12
|
-
qualified name of the callable object as the metric name.
|
|
13
|
-
|
|
14
|
-
:param f: Callable to wrap
|
|
15
|
-
:return: Result of f
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
@wraps(f)
|
|
19
|
-
def wrapper() -> Any:
|
|
20
|
-
time_name = f.__qualname__
|
|
21
|
-
|
|
22
|
-
_timer = Registry().get_timer(time_name)
|
|
23
|
-
|
|
24
|
-
if not _timer:
|
|
25
|
-
_timer = Timer()
|
|
26
|
-
Registry().add_timer(time_name, _timer)
|
|
27
|
-
|
|
28
|
-
with _timer.time():
|
|
29
|
-
return f()
|
|
30
|
-
|
|
31
|
-
return wrapper
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|