easy-kit 0.0.3__tar.gz → 0.0.4.dev0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: easy-kit
3
- Version: 0.0.3
3
+ Version: 0.0.4.dev0
4
4
  Summary: Python toolkit
5
5
  Author: flegac
6
6
  Author-email: flegac <florent.legac@gmail.com>
File without changes
@@ -0,0 +1,39 @@
1
+ from typing import Callable
2
+
3
+
4
+ class Event:
5
+ IS_ENABLED = False
6
+
7
+ @staticmethod
8
+ def enable(status: bool = True):
9
+ Event.IS_ENABLED = status
10
+
11
+ def __init__(self, name: str = 'EventDefault'):
12
+ self.name = name
13
+ self.observer: list[Callable[[...], ...]] = []
14
+ self.enabled = True
15
+ self.verbose = False
16
+
17
+ def emitter(self, *args, **kwargs):
18
+ def _fun():
19
+ self.emit(*args, **kwargs)
20
+
21
+ return _fun
22
+
23
+ def emit(self, *args, **kwargs):
24
+ if self.enabled:
25
+ for _ in self.observer:
26
+ _(*args, **kwargs)
27
+
28
+ def connect[** P, T](self, func: Callable[P, T]) -> Callable[P, T]:
29
+ if Event.IS_ENABLED:
30
+ self.observer.append(func)
31
+ return func
32
+
33
+ def observe[** P, T](self, func: Callable[P, T]) -> Callable[P, T]:
34
+ def _fun(*args, **kwargs) -> T:
35
+ res = func(*args, **kwargs)
36
+ self.emit(res)
37
+ return res
38
+
39
+ return _fun
@@ -0,0 +1,177 @@
1
+ import inspect
2
+ import statistics
3
+ import time
4
+ from collections import defaultdict
5
+ from contextlib import contextmanager
6
+ from dataclasses import dataclass, field
7
+ from functools import wraps
8
+ from pprint import pprint
9
+ from typing import Callable
10
+ from unittest import TestCase
11
+
12
+ HEADERS = ['label', 'total (s)', 'count', 'min', 'max', 'mean', 'std']
13
+
14
+
15
+ def _tabulate(headers: list[str], data: list[list[str]]):
16
+ try:
17
+ from tabulate import tabulate
18
+ return tabulate(
19
+ headers=headers,
20
+ floatfmt='.5f',
21
+ tabular_data=data,
22
+ )
23
+ except:
24
+ pass
25
+
26
+ raw = [
27
+ headers,
28
+ *[
29
+ [f'{_:5}' for _ in row]
30
+ for row in data
31
+ ]
32
+ ]
33
+
34
+ lengths = [
35
+ max(len(raw[row][col]) for row in range(len(raw)))
36
+ for col in range(len(headers))
37
+ ]
38
+
39
+ raw.insert(1, ['-' * _ for _ in lengths])
40
+
41
+ return '\n'.join([
42
+ ' '.join([_.ljust(l) for _, l in zip(row, lengths)])
43
+ for row in raw
44
+ ])
45
+
46
+
47
+ @dataclass
48
+ class TimeEntry:
49
+ events: list[float] = field(default_factory=list)
50
+
51
+ def raw_line(self, key: str):
52
+ return [key, self.total, self.count, self.min, self.max, self.mean, self.std]
53
+
54
+ @property
55
+ def total(self):
56
+ return sum(self.events)
57
+
58
+ @property
59
+ def count(self):
60
+ return len(self.events)
61
+
62
+ @property
63
+ def min(self):
64
+ return self._undefined(min(self.events))
65
+
66
+ @property
67
+ def max(self):
68
+ return self._undefined(max(self.events))
69
+
70
+ @property
71
+ def mean(self):
72
+ return self._undefined(statistics.mean(self.events))
73
+
74
+ @property
75
+ def std(self):
76
+ return self._undefined(statistics.pstdev(self.events))
77
+
78
+ def _undefined(self, value: float):
79
+ if len(self.events) <= 1:
80
+ return ''
81
+ return value
82
+
83
+
84
+ class DefaultLogger:
85
+ debug = print
86
+ info = print
87
+ warning = print
88
+
89
+
90
+ class Timings:
91
+ def __init__(self):
92
+ self.db: dict[str, TimeEntry] = defaultdict(lambda: TimeEntry())
93
+ self.active = False
94
+ self.logs = False
95
+ self.logger = DefaultLogger
96
+
97
+ @contextmanager
98
+ def timing(self, name: str = None):
99
+ if name is None:
100
+ name = inspect.stack()[11].function
101
+ start = self._before(name)
102
+ yield
103
+ self._after(name, start)
104
+
105
+ def time_func[** P, R](self, func: Callable[P, R]) -> Callable[P, R]:
106
+ @wraps(func)
107
+ def inner(*args: P.args, **kwargs: P.kwargs) -> R:
108
+ with self.timing(func.__qualname__):
109
+ return func(*args, **kwargs)
110
+
111
+ return inner
112
+
113
+ def show_timing(self):
114
+ if not self.active:
115
+ return
116
+
117
+ try:
118
+ self.logger.info('\n' + self.format_table())
119
+ except Exception as e:
120
+ self.logger.warning(f'Warning: {e}')
121
+
122
+ def raw_table(self):
123
+ return sorted([
124
+ entry.raw_line(key)
125
+ for key, entry in self.db.items()
126
+ ], key=lambda row: row[1], reverse=True)
127
+
128
+ def format_table(self):
129
+ return _tabulate(headers=HEADERS, data=self.raw_table())
130
+
131
+ def setup_timing(self, status: bool = True, logs: bool = False):
132
+ self.active = status
133
+ self.logs = logs
134
+
135
+ def tree_structure(self):
136
+ groups = {}
137
+
138
+ for key, entry in self.db.items():
139
+ try:
140
+ major, minor = key.split('.', maxsplit=1)
141
+ except:
142
+ major = '___'
143
+ minor = key
144
+ if major not in groups:
145
+ groups[major] = {}
146
+ groups[major][minor] = entry
147
+ return groups
148
+
149
+ def _before(self, name: str):
150
+ if self.logs:
151
+ self.logger.debug(f'+ {name}')
152
+ if self.active:
153
+ return time.time()
154
+
155
+ def _after(self, name: str, start: float | None):
156
+ if self.logs:
157
+ self.logger.debug(f'- {name}')
158
+ if start is not None:
159
+ total = time.time() - start
160
+ self.db[name].events.append(total)
161
+
162
+
163
+ _TIMING = Timings()
164
+ timing = _TIMING.timing
165
+ time_func = _TIMING.time_func
166
+ show_timing = _TIMING.show_timing
167
+ setup_timing = _TIMING.setup_timing
168
+
169
+
170
+ class TimingTestCase(TestCase):
171
+ @classmethod
172
+ def setUpClass(cls):
173
+ setup_timing()
174
+
175
+ @classmethod
176
+ def tearDownClass(cls):
177
+ show_timing()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: easy-kit
3
- Version: 0.0.3
3
+ Version: 0.0.4.dev0
4
4
  Summary: Python toolkit
5
5
  Author: flegac
6
6
  Author-email: flegac <florent.legac@gmail.com>
@@ -2,6 +2,9 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  setup.py
5
+ easy_kit/__init__.py
6
+ easy_kit/event.py
7
+ easy_kit/timing.py
5
8
  easy_kit.egg-info/PKG-INFO
6
9
  easy_kit.egg-info/SOURCES.txt
7
10
  easy_kit.egg-info/dependency_links.txt
@@ -0,0 +1 @@
1
+ easy_kit
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "easy-kit"
3
- version = "0.0.3"
3
+ version = "0.0.4.dev0"
4
4
  authors = [
5
5
  { name="flegac", email="florent.legac@gmail.com" },
6
6
  ]
@@ -1,6 +1,4 @@
1
- from pathlib import Path
2
-
3
- from setuptools import setup, find_packages
1
+ from setuptools import setup
4
2
 
5
3
  with open("README.md", "r", encoding="utf-8") as fh:
6
4
  long_description = fh.read()
@@ -17,7 +15,7 @@ setup(
17
15
  "License :: OSI Approved :: MIT License",
18
16
  "Operating System :: OS Independent",
19
17
  ],
20
- packages=find_packages(),
18
+ packages=['easy_kit'],
21
19
  # install_requires=[line for line in open('requirements.txt')],
22
20
  python_requires=">=3.7",
23
21
  include_package_data=True
File without changes
File without changes
File without changes