bs-python-utils 0.0.1__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.
- bs_python_utils/Timer.py +76 -0
- bs_python_utils/__init__.py +0 -0
- bs_python_utils/bs_altair.py +927 -0
- bs_python_utils/bs_logging.py +100 -0
- bs_python_utils/bs_mathstr.py +130 -0
- bs_python_utils/bs_mem.py +148 -0
- bs_python_utils/bs_opt.py +518 -0
- bs_python_utils/bs_plots.py +2 -0
- bs_python_utils/bs_seaborn.py +174 -0
- bs_python_utils/bs_sparse_gaussian.py +46 -0
- bs_python_utils/bsmplutils.py +34 -0
- bs_python_utils/bsnputils.py +957 -0
- bs_python_utils/bssputils.py +79 -0
- bs_python_utils/bsstats.py +463 -0
- bs_python_utils/bsutils.py +363 -0
- bs_python_utils/distance_covariances.py +258 -0
- bs_python_utils/example_opt.py +71 -0
- bs_python_utils/examples_altair.py +195 -0
- bs_python_utils/examples_distance_covariances.py +32 -0
- bs_python_utils/examples_mem.py +25 -0
- bs_python_utils/examples_seaborn.py +37 -0
- bs_python_utils/examples_sklearn.py +33 -0
- bs_python_utils/pandas_utils.py +239 -0
- bs_python_utils/sklearn_utils.py +74 -0
- bs_python_utils-0.0.1.dist-info/LICENSE +21 -0
- bs_python_utils-0.0.1.dist-info/METADATA +71 -0
- bs_python_utils-0.0.1.dist-info/RECORD +28 -0
- bs_python_utils-0.0.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
""" Utilities for logging
|
|
2
|
+
"""
|
|
3
|
+
import functools
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def init_logger(
|
|
10
|
+
logger_name: str,
|
|
11
|
+
log_level_for_console: str = "info",
|
|
12
|
+
log_level_for_file: str = "debug",
|
|
13
|
+
save_dir: str = None,
|
|
14
|
+
) -> logging.Logger:
|
|
15
|
+
"""
|
|
16
|
+
Initialize a logger
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
logger_name: name for the logger
|
|
20
|
+
log_level_for_console: minimum level of messages logged to the console logging
|
|
21
|
+
log_level_for_file:
|
|
22
|
+
save_dir:
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
the logger
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
logger_dir = "logs"
|
|
29
|
+
logger_name = "check_log"
|
|
30
|
+
logger = init_logger(logger_name, save_dir=logger_dir)
|
|
31
|
+
logger = get_logger(logger_name)
|
|
32
|
+
|
|
33
|
+
will create two logs:
|
|
34
|
+
|
|
35
|
+
* one printed to console where we run the code (the `StreamHandler`),
|
|
36
|
+
* and one that will be saved to file `save_dir/logger_name.txt` (the `FileHandler`).
|
|
37
|
+
|
|
38
|
+
`'logger.propagate = False'` makes sure that the logs sent to file will not be printed to console.
|
|
39
|
+
|
|
40
|
+
We use the `Formatter` class to define the format of the logs.
|
|
41
|
+
Here:
|
|
42
|
+
* The time of the log in a human-readable format, `asctime`
|
|
43
|
+
* `levelname` is the level of the log, one out of `INFO, DEBUG, WARNING, ERROR, CRITICAL`.
|
|
44
|
+
* The name of the file, `filename`, from which the log was generated,
|
|
45
|
+
and the line number, `lineno`.
|
|
46
|
+
* Lastly, the message itself — `message`.
|
|
47
|
+
|
|
48
|
+
The default has only `INFO` logs and above (i.e., also `WARNING, ERROR` and `CRITICAL`)
|
|
49
|
+
displayed in the console; the file will also include `DEBUG` logs.
|
|
50
|
+
"""
|
|
51
|
+
logger = logging.getLogger()
|
|
52
|
+
logger.setLevel(level=logging.DEBUG)
|
|
53
|
+
logger.propagate = False
|
|
54
|
+
|
|
55
|
+
formatter = logging.Formatter(
|
|
56
|
+
"%(asctime)s [%(levelname)s] %(filename)s %(lineno)d - %(message)s",
|
|
57
|
+
"%Y-%m-%d %H:%M:%S",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
ch = logging.StreamHandler()
|
|
61
|
+
ch.setLevel(log_level_for_console.upper())
|
|
62
|
+
ch.setFormatter(formatter)
|
|
63
|
+
logger.addHandler(ch)
|
|
64
|
+
|
|
65
|
+
if save_dir is not None:
|
|
66
|
+
Path(save_dir).mkdir(exist_ok=True, parents=True)
|
|
67
|
+
fh = logging.FileHandler(save_dir + f"/{logger_name}.txt")
|
|
68
|
+
fh.setLevel(log_level_for_file.upper())
|
|
69
|
+
fh.setFormatter(formatter)
|
|
70
|
+
logger.addHandler(fh)
|
|
71
|
+
|
|
72
|
+
return logger
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def log_execution(func: Callable) -> Callable:
|
|
76
|
+
"""Decorator to log the execution of a function
|
|
77
|
+
Only records entry to and exit from the function, to the console
|
|
78
|
+
"""
|
|
79
|
+
loglevel = logging.info
|
|
80
|
+
|
|
81
|
+
@functools.wraps(func)
|
|
82
|
+
def wrapper(*args, **kwargs):
|
|
83
|
+
loglevel(f"Executing {func.__name__}")
|
|
84
|
+
result = func(*args, **kwargs)
|
|
85
|
+
loglevel(f"Finished executing {func.__name__}")
|
|
86
|
+
return result
|
|
87
|
+
|
|
88
|
+
return wrapper
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_logger(logger_name: str) -> logging.Logger:
|
|
92
|
+
"""Get a logger
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
logger_name: name you want for the logger
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
the logger
|
|
99
|
+
"""
|
|
100
|
+
return logging.getLogger(logger_name)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Some useful strings for math formulae.
|
|
2
|
+
|
|
3
|
+
Attributes:
|
|
4
|
+
str_beta0 (str): the LaTeX string `\\beta_0`
|
|
5
|
+
|
|
6
|
+
str_beta1 (str): the LaTeX string `\\beta_1`
|
|
7
|
+
|
|
8
|
+
str_pi (str): the LaTeX string `\\pi`
|
|
9
|
+
|
|
10
|
+
str_sigma (str): the LaTeX string `\\sigma`
|
|
11
|
+
|
|
12
|
+
str_sigma2 (str): the LaTeX string `\\sigma^2`
|
|
13
|
+
|
|
14
|
+
uni_beta0 (str): the Unicode string `\\beta_0`
|
|
15
|
+
|
|
16
|
+
uni_beta1 (str): the Unicode string `\\beta_1`
|
|
17
|
+
|
|
18
|
+
uni_pi (str): the Unicode string `\\pi`
|
|
19
|
+
|
|
20
|
+
uni_sigma (str): the Unicode string `\\sigma`
|
|
21
|
+
|
|
22
|
+
uni_sigma2 (str): the Unicode string `\\sigma^2`
|
|
23
|
+
|
|
24
|
+
uni_s2 (str): the Unicode string `s^2`
|
|
25
|
+
|
|
26
|
+
uni_R2 (str): the Unicode string `R^2`
|
|
27
|
+
|
|
28
|
+
sub_sub_scripts (dict): a dictionary of Unicodes for subscripts and superscripts;
|
|
29
|
+
e.g `a^b` would be `"a" + sub_sup_scripts['b'][0]`
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
# LaTeX strings
|
|
33
|
+
str_beta0 = r"$\beta_0$"
|
|
34
|
+
str_beta1 = r"$\beta_1$"
|
|
35
|
+
str_pi = r"$\pi$"
|
|
36
|
+
str_sigma = r"$\sigma$"
|
|
37
|
+
str_sigma2 = r"$\sigma^2$"
|
|
38
|
+
|
|
39
|
+
# Unicode
|
|
40
|
+
uni_beta0 = "\N{GREEK SMALL LETTER BETA}\N{SUBSCRIPT ZERO}"
|
|
41
|
+
uni_beta1 = "\N{GREEK SMALL LETTER BETA}\N{SUBSCRIPT ONE}"
|
|
42
|
+
uni_pi = "\N{GREEK SMALL LETTER PI}"
|
|
43
|
+
uni_sigma = "\N{GREEK SMALL LETTER SIGMA}"
|
|
44
|
+
uni_sigma2 = "\N{GREEK SMALL LETTER SIGMA}\N{SUPERSCRIPT TWO}"
|
|
45
|
+
uni_s2 = "s\N{SUPERSCRIPT TWO}"
|
|
46
|
+
uni_R2 = "R\N{SUPERSCRIPT TWO}"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
sub_sup_scripts = {
|
|
50
|
+
# superscript subscript
|
|
51
|
+
"0": ("\u2070", "\u2080"),
|
|
52
|
+
"1": ("\u00B9", "\u2081"),
|
|
53
|
+
"2": ("\u00B2", "\u2082"),
|
|
54
|
+
"3": ("\u00B3", "\u2083"),
|
|
55
|
+
"4": ("\u2074", "\u2084"),
|
|
56
|
+
"5": ("\u2075", "\u2085"),
|
|
57
|
+
"6": ("\u2076", "\u2086"),
|
|
58
|
+
"7": ("\u2077", "\u2087"),
|
|
59
|
+
"8": ("\u2078", "\u2088"),
|
|
60
|
+
"9": ("\u2079", "\u2089"),
|
|
61
|
+
"a": ("\u1d43", "\u2090"),
|
|
62
|
+
"b": ("\u1d47", "?"),
|
|
63
|
+
"c": ("\u1d9c", "?"),
|
|
64
|
+
"d": ("\u1d48", "?"),
|
|
65
|
+
"e": ("\u1d49", "\u2091"),
|
|
66
|
+
"f": ("\u1da0", "?"),
|
|
67
|
+
"g": ("\u1d4d", "?"),
|
|
68
|
+
"h": ("\u02b0", "\u2095"),
|
|
69
|
+
"i": ("\u2071", "\u1d62"),
|
|
70
|
+
"j": ("\u02b2", "\u2c7c"),
|
|
71
|
+
"k": ("\u1d4f", "\u2096"),
|
|
72
|
+
"l": ("\u02e1", "\u2097"),
|
|
73
|
+
"m": ("\u1d50", "\u2098"),
|
|
74
|
+
"n": ("\u207f", "\u2099"),
|
|
75
|
+
"o": ("\u1d52", "\u2092"),
|
|
76
|
+
"p": ("\u1d56", "\u209a"),
|
|
77
|
+
"q": ("?", "?"),
|
|
78
|
+
"r": ("\u02b3", "\u1d63"),
|
|
79
|
+
"s": ("\u02e2", "\u209b"),
|
|
80
|
+
"t": ("\u1d57", "\u209c"),
|
|
81
|
+
"u": ("\u1d58", "\u1d64"),
|
|
82
|
+
"v": ("\u1d5b", "\u1d65"),
|
|
83
|
+
"w": ("\u02b7", "?"),
|
|
84
|
+
"x": ("\u02e3", "\u2093"),
|
|
85
|
+
"y": ("\u02b8", "?"),
|
|
86
|
+
"z": ("?", "?"),
|
|
87
|
+
"A": ("\u1d2c", "?"),
|
|
88
|
+
"B": ("\u1d2e", "?"),
|
|
89
|
+
"C": ("?", "?"),
|
|
90
|
+
"D": ("\u1d30", "?"),
|
|
91
|
+
"E": ("\u1d31", "?"),
|
|
92
|
+
"F": ("?", "?"),
|
|
93
|
+
"G": ("\u1d33", "?"),
|
|
94
|
+
"H": ("\u1d34", "?"),
|
|
95
|
+
"I": ("\u1d35", "?"),
|
|
96
|
+
"J": ("\u1d36", "?"),
|
|
97
|
+
"K": ("\u1d37", "?"),
|
|
98
|
+
"L": ("\u1d38", "?"),
|
|
99
|
+
"M": ("\u1d39", "?"),
|
|
100
|
+
"N": ("\u1d3a", "?"),
|
|
101
|
+
"O": ("\u1d3c", "?"),
|
|
102
|
+
"P": ("\u1d3e", "?"),
|
|
103
|
+
"Q": ("?", "?"),
|
|
104
|
+
"R": ("\u1d3f", "?"),
|
|
105
|
+
"S": ("?", "?"),
|
|
106
|
+
"T": ("\u1d40", "?"),
|
|
107
|
+
"U": ("\u1d41", "?"),
|
|
108
|
+
"V": ("\u2c7d", "?"),
|
|
109
|
+
"W": ("\u1d42", "?"),
|
|
110
|
+
"X": ("?", "?"),
|
|
111
|
+
"Y": ("?", "?"),
|
|
112
|
+
"Z": ("?", "?"),
|
|
113
|
+
"+": ("\u207A", "\u208A"),
|
|
114
|
+
"-": ("\u207B", "\u208B"),
|
|
115
|
+
"=": ("\u207C", "\u208C"),
|
|
116
|
+
"(": ("\u207D", "\u208D"),
|
|
117
|
+
")": ("\u207E", "\u208E"),
|
|
118
|
+
":alpha": ("\u1d45", "?"),
|
|
119
|
+
":beta": ("\u1d5d", "\u1d66"),
|
|
120
|
+
":gamma": ("\u1d5e", "\u1d67"),
|
|
121
|
+
":delta": ("\u1d5f", "?"),
|
|
122
|
+
":epsilon": ("\u1d4b", "?"),
|
|
123
|
+
":theta": ("\u1dbf", "?"),
|
|
124
|
+
":iota": ("\u1da5", "?"),
|
|
125
|
+
":pho": ("?", "\u1d68"),
|
|
126
|
+
":phi": ("\u1db2", "?"),
|
|
127
|
+
":psi": ("\u1d60", "\u1d69"),
|
|
128
|
+
":chi": ("\u1d61", "\u1d6a"),
|
|
129
|
+
":coffee": ("\u2615", "\u2615"),
|
|
130
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import linecache
|
|
2
|
+
import sys
|
|
3
|
+
import tracemalloc
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from bs_python_utils.bsutils import print_stars
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _obj_size_fmt(num: int) -> str:
|
|
11
|
+
"""
|
|
12
|
+
format sizes from bytes to appropriate strings depending on size
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
num: size of object in bytes
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
its formatted size
|
|
19
|
+
"""
|
|
20
|
+
if num < 10**3:
|
|
21
|
+
return "{:.2f}{}".format(num, "B")
|
|
22
|
+
elif (num >= 10**3) & (num < 10**6):
|
|
23
|
+
return "{:.2f}{}".format(num / (1.024 * 10**3), "KB")
|
|
24
|
+
elif (num >= 10**6) & (num < 10**9):
|
|
25
|
+
return "{:.2f}{}".format(num / (1.024 * 10**6), "MB")
|
|
26
|
+
else:
|
|
27
|
+
return "{:.2f}{}".format(num / (1.024 * 10**9), "GB")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def memory_usage(n: int | None = 10) -> None:
|
|
31
|
+
"""
|
|
32
|
+
dataframe of the top `n` largest global items in memory
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
n: we report the size of the largest `n` global items
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
nothing
|
|
39
|
+
"""
|
|
40
|
+
memory_usage_by_variable = pd.DataFrame(
|
|
41
|
+
{k: sys.getsizeof(v) for (k, v) in globals().items()}, index=["Size"]
|
|
42
|
+
)
|
|
43
|
+
memory_usage_by_variable = memory_usage_by_variable.T
|
|
44
|
+
total_usage = _obj_size_fmt(memory_usage_by_variable["Size"].sum())
|
|
45
|
+
memory_usage_by_variable = memory_usage_by_variable.sort_values(
|
|
46
|
+
by="Size", ascending=False
|
|
47
|
+
).head(n)
|
|
48
|
+
memory_usage_by_variable["Size"] = memory_usage_by_variable["Size"].apply(
|
|
49
|
+
lambda x: _obj_size_fmt(x)
|
|
50
|
+
)
|
|
51
|
+
print_stars(
|
|
52
|
+
f"Currently used memory = {total_usage}\n\t\t\t\t Top {n} global objects:"
|
|
53
|
+
)
|
|
54
|
+
print(memory_usage_by_variable)
|
|
55
|
+
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def memory_display_top(
|
|
60
|
+
snapshot: tracemalloc.Snapshot, key_type: str = "lineno", limit: int | None = 5
|
|
61
|
+
) -> None:
|
|
62
|
+
"""
|
|
63
|
+
prints out the lines with the top `limit` allocations of memory since tracemalloc.start()
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
snapshot: obtained from tracemalloc.take_snapshot()
|
|
67
|
+
key_type: 'lineno' gives file and line number; 'traceback' gives all
|
|
68
|
+
limit: how many top allocations we want
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
just prints
|
|
72
|
+
|
|
73
|
+
Example:
|
|
74
|
+
tracemalloc.start()
|
|
75
|
+
.... execute ...
|
|
76
|
+
snapshot = tracemalloc.take_snapshot()
|
|
77
|
+
memory_display_top(snapshot)
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
top_stats = snapshot.statistics(key_type)
|
|
81
|
+
|
|
82
|
+
print_stars(f"Top {limit} memory allocations")
|
|
83
|
+
for index, stat in enumerate(top_stats[:limit], 1):
|
|
84
|
+
frame = stat.traceback[0]
|
|
85
|
+
print(
|
|
86
|
+
"#%s: %s:%s: %.1f KiB"
|
|
87
|
+
% (index, frame.filename, frame.lineno, stat.size / 1024)
|
|
88
|
+
)
|
|
89
|
+
line = linecache.getline(frame.filename, frame.lineno).strip()
|
|
90
|
+
if line:
|
|
91
|
+
print(" %s" % line)
|
|
92
|
+
|
|
93
|
+
other = top_stats[limit:]
|
|
94
|
+
if other:
|
|
95
|
+
size = sum(stat.size for stat in other)
|
|
96
|
+
print(f"{len(other)} other: {size / 1024:.1f} KiB")
|
|
97
|
+
total = sum(stat.size for stat in top_stats)
|
|
98
|
+
print("Total allocated size: %.1f KiB" % (total / 1024))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def memory_display_top_diffs(
|
|
102
|
+
snapshot1: tracemalloc.Snapshot,
|
|
103
|
+
snapshot2: tracemalloc.Snapshot,
|
|
104
|
+
key_type: str = "lineno",
|
|
105
|
+
limit: int = 5,
|
|
106
|
+
) -> None:
|
|
107
|
+
"""
|
|
108
|
+
prints out the lines with the top `limit` allocations \
|
|
109
|
+
between the two snapshots
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
snapshot1: previous snapshot
|
|
113
|
+
snapshot2: new snapshot
|
|
114
|
+
key_type: 'lineno' gives file and line number; 'traceback' gives all
|
|
115
|
+
limit: how many top allocations we want
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
just prints
|
|
119
|
+
|
|
120
|
+
Example:
|
|
121
|
+
tracemalloc.start()
|
|
122
|
+
.... execute ...
|
|
123
|
+
snapshot1 = tracemalloc.take_snapshot()
|
|
124
|
+
.... execute ...
|
|
125
|
+
snapshot2 = tracemalloc.take_snapshot()
|
|
126
|
+
memory_display_top_diffs(snapshot1, snapshot2)
|
|
127
|
+
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
top_stats = snapshot2.compare_to(snapshot1, key_type)
|
|
131
|
+
|
|
132
|
+
print_stars(f"Top {limit} new memory allocations")
|
|
133
|
+
for index, stat in enumerate(top_stats[:limit], 1):
|
|
134
|
+
frame = stat.traceback[0]
|
|
135
|
+
print(
|
|
136
|
+
"#%s: %s:%s: %.1f KiB"
|
|
137
|
+
% (index, frame.filename, frame.lineno, stat.size / 1024)
|
|
138
|
+
)
|
|
139
|
+
line = linecache.getline(frame.filename, frame.lineno).strip()
|
|
140
|
+
if line:
|
|
141
|
+
print(" %s" % line)
|
|
142
|
+
|
|
143
|
+
other = top_stats[limit:]
|
|
144
|
+
if other:
|
|
145
|
+
size = sum(stat.size for stat in other)
|
|
146
|
+
print(f"{len(other)} other: {size / 1024:.1f} KiB")
|
|
147
|
+
total = sum(stat.size for stat in top_stats)
|
|
148
|
+
print("Total allocated size: %.1f KiB" % (total / 1024))
|