dycw-utilities 0.125.21__py3-none-any.whl → 0.125.22__py3-none-any.whl
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.
- {dycw_utilities-0.125.21.dist-info → dycw_utilities-0.125.22.dist-info}/METADATA +1 -1
- {dycw_utilities-0.125.21.dist-info → dycw_utilities-0.125.22.dist-info}/RECORD +6 -5
- utilities/__init__.py +1 -1
- utilities/psutil.py +115 -0
- {dycw_utilities-0.125.21.dist-info → dycw_utilities-0.125.22.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.125.21.dist-info → dycw_utilities-0.125.22.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=mOuoQC76dPEs9bAglMk52el5SSD3hguWO9Zm_CqFpl4,61
|
2
2
|
utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
|
3
3
|
utilities/asyncio.py,sha256=pQ5GRcNyBqmDyeAeSarYugrjSNxmX3E0G9pye-kkPt4,51085
|
4
4
|
utilities/atomicwrites.py,sha256=geFjn9Pwn-tTrtoGjDDxWli9NqbYfy3gGL6ZBctiqSo,5393
|
@@ -50,6 +50,7 @@ utilities/platform.py,sha256=48IOKx1IC6ZJXWG-b56ZQptITcNFhWRjELW72o2dGTA,2398
|
|
50
50
|
utilities/polars.py,sha256=QlmUpYTqHNkcLnWOQh1TW22W2QyLzvifCvBcbsqhpdE,63272
|
51
51
|
utilities/polars_ols.py,sha256=Uc9V5kvlWZ5cU93lKZ-cfAKdVFFw81tqwLW9PxtUvMs,5618
|
52
52
|
utilities/pqdm.py,sha256=foRytQybmOQ05pjt5LF7ANyzrIa--4ScDE3T2wd31a4,3118
|
53
|
+
utilities/psutil.py,sha256=0dXHKW7t9J3uzY3YtHGiRiZVRWr0uozccioZRCVFQfk,3761
|
53
54
|
utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
55
|
utilities/pydantic.py,sha256=f6qtR5mO2YMuyvNmbaEj5YeD9eGA4YYfb7Bjzh9jUs0,1845
|
55
56
|
utilities/pyinstrument.py,sha256=OJFDh4o1CWIa4aYPYURdQjgap_nvP45KUsCEe94rQHY,829
|
@@ -89,7 +90,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
89
90
|
utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
|
90
91
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
91
92
|
utilities/zoneinfo.py,sha256=-5j7IQ9nb7gR43rdgA7ms05im-XuqhAk9EJnQBXxCoQ,1874
|
92
|
-
dycw_utilities-0.125.
|
93
|
-
dycw_utilities-0.125.
|
94
|
-
dycw_utilities-0.125.
|
95
|
-
dycw_utilities-0.125.
|
93
|
+
dycw_utilities-0.125.22.dist-info/METADATA,sha256=1cHkVeipeZn1O9uboTuGQ1v8cOEjkg3GIBqUnmmaIow,12852
|
94
|
+
dycw_utilities-0.125.22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
95
|
+
dycw_utilities-0.125.22.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
96
|
+
dycw_utilities-0.125.22.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/psutil.py
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass, field
|
4
|
+
from json import dumps
|
5
|
+
from logging import getLogger
|
6
|
+
from math import isclose, nan
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import TYPE_CHECKING, Self, override
|
9
|
+
|
10
|
+
from psutil import swap_memory, virtual_memory
|
11
|
+
|
12
|
+
from utilities.asyncio import Looper
|
13
|
+
from utilities.contextlib import suppress_super_object_attribute_error
|
14
|
+
from utilities.datetime import SECOND, get_now
|
15
|
+
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
import datetime as dt
|
18
|
+
from logging import Logger
|
19
|
+
|
20
|
+
from utilities.types import Duration, PathLike
|
21
|
+
|
22
|
+
|
23
|
+
@dataclass(kw_only=True)
|
24
|
+
class MemoryMonitorService(Looper[None]):
|
25
|
+
"""Service to monitor memory usage."""
|
26
|
+
|
27
|
+
# base
|
28
|
+
freq: Duration = field(default=10 * SECOND, repr=False)
|
29
|
+
backoff: Duration = field(default=10 * SECOND, repr=False)
|
30
|
+
# self
|
31
|
+
console: str | None = field(default=None, repr=False)
|
32
|
+
path: PathLike = "memory.txt"
|
33
|
+
_console: Logger | None = field(init=False, repr=False)
|
34
|
+
_max_age: int | None = field(default=None, init=False, repr=False)
|
35
|
+
_path: Path = field(init=False, repr=False)
|
36
|
+
|
37
|
+
@override
|
38
|
+
def __post_init__(self) -> None:
|
39
|
+
super().__post_init__()
|
40
|
+
if self.console is not None:
|
41
|
+
self._console = getLogger(self.console)
|
42
|
+
self._path = Path(self.path)
|
43
|
+
|
44
|
+
@override
|
45
|
+
async def core(self) -> None:
|
46
|
+
await super().core()
|
47
|
+
memory = MemoryUsage.new()
|
48
|
+
mapping = {
|
49
|
+
"datetime": memory.datetime.strftime("%Y-%m-%d %H:%M:%S"),
|
50
|
+
"virtual used (mb)": memory.virtual_used_mb,
|
51
|
+
"virtual total (mb)": memory.virtual_total_mb,
|
52
|
+
"virtual (%)": memory.virtual_pct,
|
53
|
+
"swap used (mb)": memory.swap_used_mb,
|
54
|
+
"swap total (mb)": memory.swap_total_mb,
|
55
|
+
"swap (%)": memory.swap_pct,
|
56
|
+
}
|
57
|
+
ser = dumps(mapping)
|
58
|
+
with self._path.open(mode="a") as fh:
|
59
|
+
_ = fh.write(f"{ser}\n")
|
60
|
+
if self._console is not None:
|
61
|
+
self._console.info("%s", mapping)
|
62
|
+
|
63
|
+
|
64
|
+
##
|
65
|
+
|
66
|
+
|
67
|
+
@dataclass(kw_only=True)
|
68
|
+
class MemoryUsage:
|
69
|
+
"""A memory usage."""
|
70
|
+
|
71
|
+
datetime: dt.datetime = field(default_factory=get_now)
|
72
|
+
virtual_used: int = field(repr=False)
|
73
|
+
virtual_used_mb: int = field(init=False)
|
74
|
+
virtual_total: int = field(repr=False)
|
75
|
+
virtual_total_mb: int = field(init=False)
|
76
|
+
virtual_pct: float = field(init=False)
|
77
|
+
swap_used: int = field(repr=False)
|
78
|
+
swap_used_mb: int = field(init=False)
|
79
|
+
swap_total: int = field(repr=False)
|
80
|
+
swap_total_mb: int = field(init=False)
|
81
|
+
swap_pct: float = field(init=False)
|
82
|
+
|
83
|
+
def __post_init__(self) -> None:
|
84
|
+
with suppress_super_object_attribute_error():
|
85
|
+
super().__post_init__() # pyright: ignore[reportAttributeAccessIssue]
|
86
|
+
self.virtual_used_mb = self._to_mb(self.virtual_used)
|
87
|
+
self.virtual_total_mb = self._to_mb(self.virtual_total)
|
88
|
+
self.virtual_pct = (
|
89
|
+
nan
|
90
|
+
if isclose(self.virtual_total, 0.0)
|
91
|
+
else self.virtual_used / self.virtual_total
|
92
|
+
)
|
93
|
+
self.swap_used_mb = self._to_mb(self.swap_used)
|
94
|
+
self.swap_total_mb = self._to_mb(self.swap_total)
|
95
|
+
self.swap_pct = (
|
96
|
+
nan if isclose(self.swap_total, 0.0) else self.swap_used / self.swap_total
|
97
|
+
)
|
98
|
+
|
99
|
+
@classmethod
|
100
|
+
def new(cls) -> Self:
|
101
|
+
virtual = virtual_memory()
|
102
|
+
virtual_total = virtual.total
|
103
|
+
swap = swap_memory()
|
104
|
+
return cls(
|
105
|
+
virtual_used=virtual_total - virtual.available,
|
106
|
+
virtual_total=virtual_total,
|
107
|
+
swap_used=swap.used,
|
108
|
+
swap_total=swap.total,
|
109
|
+
)
|
110
|
+
|
111
|
+
def _to_mb(self, bytes_: int) -> int:
|
112
|
+
return round(bytes_ / (1024**2))
|
113
|
+
|
114
|
+
|
115
|
+
__all__ = ["MemoryMonitorService", "MemoryUsage"]
|
File without changes
|
File without changes
|