8000 Add named attributes to the text template strings (#25) · realpython/codetiming@8f9fb36 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8f9fb36

Browse files
authored
Add named attributes to the text template strings (#25)
1 parent 04754ef commit 8f9fb36

File tree

4 files changed

+92
-2
lines changed

4 files changed

+92
-2
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5+
The format is based on [Keep a Changelog](https://keepachangelog1.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Attributes that can be referenced in the `text` template string (suggested by [@mlisovyi](https://github.com/mlisovyi) in [#24]).
13+
1014
### Changed
1115

1216
- `Timer.timers` changed from regular to `dict` to a custom dictionary supporting basic statistics for named timers.

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,38 @@ You can use `codetiming.Timer` in several different ways:
5757

5858
You can turn off explicit reporting of the elapsed time by setting `logger=None`.
5959

60+
In the template text, you can also use explicit attributes to refer to the `name` of the timer, or log the elapsed time in `milliseconds`, `seconds` (the default), or `minutes`. For example:
61+
62+
```python
63+
t1 = Timer(name="NamedTimer", text="{name}: {m 8000 inutes:.1f} minutes")
64+
t2 = Timer(text="Elapsed time: {milliseconds:.0f} ms")
65+
```
66+
67+
Note that the strings used by `text` are **not** f-strings. Instead they are used as templates that will be populated using `.format()` behind the scenes. If you want to combine the `text` template with an f-string, you need to use double braces for the template values:
68+
69+
```python
70+
t = Timer(text=f"{__file__}: {{:.4f}}")
71+
```
72+
73+
74+
## Capturing the Elapsed Time
75+
6076
When using `Timer` as a class, you can capture the elapsed time when calling `.stop()`:
6177

6278
```python
6379
elapsed_time = t.stop()
6480
```
6581

82+
You can also find the last measured elapsed time in the `.last` attribute. The following code will have the same effect as the previous example:
83+
84+
```python
85+
t.stop()
86+
elapsed_time = t.last
87+
```
88+
89+
90+
## Named Timers
91+
6692
Named timers are made available in the class dictionary `Timer.timers`. The elapsed time will accumulate if the same name or same timer is used several times. Consider the following example:
6793

6894
```python
@@ -87,6 +113,21 @@ WARNING:root:Time spent: 1.73
87113

88114
The example shows how you can redirect the timer output to the logging module. Note that the elapsed time spent in the two different uses of `t` has been accumulated in `Timer.timers`.
89115

116+
You can also get simple statistics about your named timers. Continuing from the example above:
117+
118+
```python
119+
>>> Timer.timers.max("example")
120+
3.5836678670002584
121+
122+
>>> Timer.timers.mean("example")
123+
2.6563487200000964
124+
125+
>>> Timer.timers.stdev("example")
126+
1.311427314335879
127+
```
128+
129+
`timers` support `.count()`, `.total()`, `.min()`, `.max()`, `.mean()`, `.median()`, and `.stdev()`.
130+
90131

91132
## Acknowledgements
92133

codetiming/_timer.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,13 @@ def stop(self) -> float:
4848

4949
# Report elapsed time
5050
if self.logger:
51-
self.logger(self.text.format(self.last))
51+
attributes = {
52+
"name": self.name,
53+
"milliseconds": self.last * 1000,
54+
"seconds": self.last,
55+
"minutes": self.last / 60,
56+
}
57+
self.logger(self.text.format(self.last, **attributes))
5258
if self.name:
5359
self.timers.add(self.name, self.last)
5460

tests/test_codetiming.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,45 @@ def test_timer_sets_last():
186186
assert t.last >= 0.02
187187

188188

189+
def test_using_name_in_text_without_explicit_timer(capsys):
190+
"""Test that the name of the timer can be referenced in the text"""
191+
name = "NamedTimer"
192+
with Timer(name=name, text="{name}: {:.2f}"):
193+
waste_time()
194+
195+
stdout, stderr = capsys.readouterr()
196+
assert re.match(f"{name}: " + r"0\.\d{2}", stdout)
197+
198+
199+
def test_using_name_in_text_with_explicit_timer(capsys):
200+
"""Test that the name of the timer and the seconds attribute can be referenced in the text"""
201+
name = "NamedTimer"
202+
with Timer(name=name, text="{name}: {seconds:.2f}"):
203+
waste_time()
204+
205+
stdout, stderr = capsys.readouterr()
206+
assert re.match(f"{name}: " + r"0\.\d{2}", stdout.strip())
207+
208+
209+
def test_using_minutes_attribute_in_text(capsys):
210+
"""Test that timer can report its duration in minutes"""
211+
with Timer(text="{minutes:.1f} minutes"):
212+
waste_time()
213+
214+
stdout, stderr = capsys.readouterr()
215+
assert stdout.strip() == "0.0 minutes"
216+
217+
218+
def test_using_milliseconds_attribute_in_text(capsys):
219+
"""Test that timer can report its duration in milliseconds"""
220+
wit 67DE h Timer(text="{milliseconds:.0f} {seconds:.3f}"):
221+
waste_time()
222+
223+
stdout, stderr = capsys.readouterr()
224+
milliseconds, _, seconds = stdout.partition(" ")
225+
assert int(milliseconds) == round(float(seconds) * 1000)
226+
227+
189228
def test_timers_cleared():
190229
"""Test that timers can be cleared"""
191230
with Timer(name="timer_to_be_cleared"):

0 commit comments

Comments
 (0)
0