David Blume commited on 2021-01-09 17:52:58
Showing 5 changed files, with 64 additions and 14 deletions.
... | ... |
@@ -1 +0,0 @@ |
1 |
-__all__ = ["counter", ] |
... | ... |
@@ -0,0 +1,47 @@ |
1 |
+#!/usr/bin/env python3 |
|
2 |
+""" |
|
3 |
+A profiler decorator. |
|
4 |
+ |
|
5 |
+Author: Giampaolo Rodola' <g.rodola [AT] gmail [DOT] com> |
|
6 |
+License: MIT |
|
7 |
+""" |
|
8 |
+import cProfile |
|
9 |
+import tempfile |
|
10 |
+import pstats |
|
11 |
+from typing import Union, Optional, Tuple, List, Callable |
|
12 |
+ |
|
13 |
+ |
|
14 |
+def profile(sort: Union[Tuple, List, str]='cumulative', |
|
15 |
+ lines_to_print: Union[int, float]=20, |
|
16 |
+ strip_dirs: bool=True, |
|
17 |
+ filename: Optional[str]=None) -> Callable: |
|
18 |
+ """A decorator which profiles a callable. |
|
19 |
+ Output goes to stdout if filename is None, otherwise to filename.""" |
|
20 |
+ def outer(fun: Callable) -> Callable: |
|
21 |
+ def inner(*args, **kwargs): |
|
22 |
+ prof = cProfile.Profile() |
|
23 |
+ ret = prof.runcall(fun, *args, **kwargs) |
|
24 |
+ if filename is None: |
|
25 |
+ stats = pstats.Stats(prof) |
|
26 |
+ else: |
|
27 |
+ statsfile = open(filename, 'a') |
|
28 |
+ stats = pstats.Stats(prof, stream=statsfile) |
|
29 |
+ if strip_dirs: |
|
30 |
+ stats.strip_dirs() |
|
31 |
+ if isinstance(sort, (tuple, list)): |
|
32 |
+ stats.sort_stats(*sort) |
|
33 |
+ else: |
|
34 |
+ stats.sort_stats(sort) |
|
35 |
+ stats.print_stats(lines_to_print) |
|
36 |
+ if filename is not None: |
|
37 |
+ statsfile.close() |
|
38 |
+ |
|
39 |
+ return ret |
|
40 |
+ return inner |
|
41 |
+ |
|
42 |
+ # in case this is defined as "@profile" instead of "@profile()" |
|
43 |
+ if hasattr(sort, '__call__'): |
|
44 |
+ fun = sort |
|
45 |
+ sort = 'cumulative' |
|
46 |
+ outer = outer(fun) |
|
47 |
+ return outer |
... | ... |
@@ -0,0 +1,14 @@ |
1 |
+import time |
|
2 |
+import functools |
|
3 |
+from typing import Callable |
|
4 |
+ |
|
5 |
+ |
|
6 |
+def timeit(f: Callable) -> Callable: |
|
7 |
+ """Decorator that prints the duration of the decorated function.""" |
|
8 |
+ @functools.wraps(f) |
|
9 |
+ def wrapper(*args, **kwargs): |
|
10 |
+ s = time.time() |
|
11 |
+ r = f(*args, **kwargs) |
|
12 |
+ print(f'{f.__name__} took {time.time() - s:1.3f}s.') |
|
13 |
+ return r |
|
14 |
+ return wrapper |
... | ... |
@@ -1 +0,0 @@ |
1 |
-__all__ = ["sitesize", ] |
... | ... |
@@ -8,17 +8,7 @@ from argparse import ArgumentParser |
8 | 8 |
import counter.counter |
9 | 9 |
import sitesize.sitesize |
10 | 10 |
from typing import Optional, Callable |
11 |
- |
|
12 |
- |
|
13 |
-def timeit(f: Callable) -> Callable: |
|
14 |
- """Decorator that prints the duration of the decorated function.""" |
|
15 |
- @functools.wraps(f) |
|
16 |
- def wrapper(*args, **kwargs): |
|
17 |
- s = time.time() |
|
18 |
- r = f(*args, **kwargs) |
|
19 |
- print(f'{f.__name__} took {time.time() - s:1.3f}s.') |
|
20 |
- return r |
|
21 |
- return wrapper |
|
11 |
+from decorators import timeit, profile |
|
22 | 12 |
|
23 | 13 |
|
24 | 14 |
v_print:Callable |
... | ... |
@@ -50,7 +40,8 @@ class Coffee: |
50 | 40 |
raise ValueError("price must be a non-negative float.") |
51 | 41 |
|
52 | 42 |
|
53 |
-@timeit |
|
43 |
+@timeit.timeit |
|
44 |
+@profile.profile # may invoke with parameters, too |
|
54 | 45 |
def main(debug: bool) -> None: |
55 | 46 |
script_dir = os.path.abspath(os.path.dirname(sys.argv[0])) |
56 | 47 |
print(f'{sys.argv[0]} is in {script_dir}.') |
57 | 48 |