kbasic 0.1.2__tar.gz → 0.1.4__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.
- {kbasic-0.1.2 → kbasic-0.1.4}/PKG-INFO +7 -2
- kbasic-0.1.4/README.md +5 -0
- {kbasic-0.1.2 → kbasic-0.1.4}/pyproject.toml +2 -2
- kbasic-0.1.4/src/kbasic/Tex.py +46 -0
- kbasic-0.1.4/src/kbasic/__init__.py +8 -0
- kbasic-0.1.4/src/kbasic/array.py +79 -0
- kbasic-0.1.4/src/kbasic/audio/sound.py +28 -0
- kbasic-0.1.4/src/kbasic/bar.py +81 -0
- kbasic-0.1.4/src/kbasic/parsing.py +159 -0
- {kbasic-0.1.2 → kbasic-0.1.4}/src/kbasic/shell.py +34 -27
- kbasic-0.1.4/src/kbasic/typing.py +38 -0
- kbasic-0.1.4/src/kbasic/user_input.py +42 -0
- {kbasic-0.1.2 → kbasic-0.1.4}/src/kbasic/vectors.py +4 -8
- kbasic-0.1.2/README.md +0 -0
- kbasic-0.1.2/src/kbasic/Tex.py +0 -23
- kbasic-0.1.2/src/kbasic/__init__.py +0 -6
- kbasic-0.1.2/src/kbasic/array.py +0 -25
- kbasic-0.1.2/src/kbasic/audio/sound.py +0 -8
- kbasic-0.1.2/src/kbasic/bar.py +0 -43
- kbasic-0.1.2/src/kbasic/py.typed +0 -0
- kbasic-0.1.2/src/kbasic/typing.py +0 -13
- kbasic-0.1.2/src/kbasic/user_input.py +0 -23
- {kbasic-0.1.2 → kbasic-0.1.4}/src/kbasic/audio/__init__.py +0 -0
- {kbasic-0.1.2 → kbasic-0.1.4}/src/kbasic/audio/lib/Caroline Rose - year of the slug - 01 everything in its right place.wav +0 -0
- {kbasic-0.1.2 → kbasic-0.1.4}/src/kbasic/audio/lib/success.mp3 +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: kbasic
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Keyan's basic utility functions.
|
|
5
5
|
Requires-Dist: numpy>=2.4.2
|
|
6
6
|
Requires-Dist: pylatexenc>=2.10
|
|
7
7
|
Requires-Dist: scipy>=1.17.0
|
|
@@ -9,3 +9,8 @@ Requires-Dist: tqdm>=4.67.3
|
|
|
9
9
|
Requires-Python: >=3.11
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
|
|
12
|
+
# KBasic
|
|
13
|
+
The core utility functions that Keyan is sick of rewriting in every project :-)
|
|
14
|
+
```
|
|
15
|
+
pip install kbasic
|
|
16
|
+
```
|
kbasic-0.1.4/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
from fractions import Fraction
|
|
5
|
+
import warnings
|
|
6
|
+
# Syntax warnings show up everytime you \something so we ignore all of em, hope this doesn't fuck anything up!
|
|
7
|
+
warnings.filterwarnings(action='ignore', category=SyntaxWarning)
|
|
8
|
+
from pylatexenc.latex2text import LatexNodes2Text
|
|
9
|
+
|
|
10
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
11
|
+
# >-|===|> Types <|===|-<
|
|
12
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
13
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
14
|
+
# >-|===|> Definitions <|===|-<
|
|
15
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
16
|
+
l2t = LatexNodes2Text().latex_to_text
|
|
17
|
+
|
|
18
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
19
|
+
# >-|===|> Functions <|===|-<
|
|
20
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
21
|
+
def texfraction(num) -> str:
|
|
22
|
+
f = Fraction(str(num))
|
|
23
|
+
return r"$\frac{" + str(f.numerator) + "}{" + str(f.denominator) + r"}$"
|
|
24
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
25
|
+
# >-|===|> Decorators <|===|-<
|
|
26
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
27
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
28
|
+
# >-|===|> Classes <|===|-<
|
|
29
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
30
|
+
class Tex(str):
|
|
31
|
+
def __init__(self, x):
|
|
32
|
+
x = x.strip(' $')
|
|
33
|
+
if x[-1]=='\n': x = x[:-1]
|
|
34
|
+
if x[-2:]=='.0': x = x[:-2]
|
|
35
|
+
# replace wonky \ letter commands with raw versions
|
|
36
|
+
# WARNING: DOES NOT WORK WITH \U OR \X BECAUSE THESE ARE UNICODE THINGS AND IDK HOW TO OVERRIDE THAT BEHAVIOR
|
|
37
|
+
x = x.replace("\a", r"\a").replace("\b", r"\b").replace("\f", r"\f").replace("\n", r"\n").replace("\r", r"\r").replace("\t", r"\t").replace("\v", r"\v")
|
|
38
|
+
# make compatible with fstring
|
|
39
|
+
x = x.replace("[", "{").replace("]", "}")
|
|
40
|
+
# get rid of extraneous .0's
|
|
41
|
+
x = x.replace(".0 ", " ").replace(".0}", "}").replace(".0$", "$").replace(".0\n", "\n")
|
|
42
|
+
self.string = fr"{l2t(x)}"
|
|
43
|
+
self.wrap = "$"+self.string+"$"
|
|
44
|
+
|
|
45
|
+
def __repr__(self): return self.string.strip("$")
|
|
46
|
+
def __str__(self): return self.string
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
from typing import Callable
|
|
5
|
+
from numpy import ndarray, argmin, abs, where, nanmean, nanmin, nanmax, linspace, nanstd, array, isnan, arange, mgrid
|
|
6
|
+
from scipy.interpolate import RegularGridInterpolator
|
|
7
|
+
|
|
8
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
9
|
+
# >-|===|> Types <|===|-<
|
|
10
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
11
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
12
|
+
# >-|===|> Definitions <|===|-<
|
|
13
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
14
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
|
+
# >-|===|> Functions <|===|-<
|
|
16
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
17
|
+
def tile(arr: ndarray) -> ndarray:
|
|
18
|
+
"""take an image and create a 3x3 grid of that image"""
|
|
19
|
+
return np.r_[np.c_[arr, arr, arr], np.c_[arr, arr, arr], np.c_[arr, arr, arr]]
|
|
20
|
+
def where_closest(arr:ndarray, x): return int(argmin(abs(arr-x)))
|
|
21
|
+
def where_between(arr:ndarray, low, high): return where((arr>=low)&(arr<=high))
|
|
22
|
+
def bin_this(
|
|
23
|
+
x, y,
|
|
24
|
+
n_bins: int = 50,
|
|
25
|
+
func: Callable = nanmean
|
|
26
|
+
) -> tuple[ndarray]:
|
|
27
|
+
"""a function to rebin x, y data and calculate errors.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
x: the axis you want to bin
|
|
31
|
+
y: the data associated with each bin
|
|
32
|
+
n_bins (int, optional): desired number of bins. Defaults to 50.
|
|
33
|
+
func (Callable, optional): the function to call on the members of each bin. Defaults to numpy.nanmean.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
x_binned (ndarray): the bins.
|
|
37
|
+
y_binned (ndarray): func(members of each bin).
|
|
38
|
+
bin_errors (ndarray): standard error of the mean for each bin
|
|
39
|
+
"""
|
|
40
|
+
xbins = linspace(nanmin(x),nanmax(x),n_bins)
|
|
41
|
+
Y,error = list(),list()
|
|
42
|
+
for i,low_edge in enumerate(xbins[:-1]):
|
|
43
|
+
high_edge = xbins[i+1]
|
|
44
|
+
mask = (low_edge<x)&(x<high_edge)
|
|
45
|
+
yin = y[mask]
|
|
46
|
+
Y.append(func(yin))
|
|
47
|
+
error.append(nanstd(yin)/sqrt(len(yin)))
|
|
48
|
+
x_binned, y_binned, bin_errors = array(xbins)[:-1],array(Y),array(error)
|
|
49
|
+
return x_binned, y_binned, bin_errors
|
|
50
|
+
def nan_clip(*args):
|
|
51
|
+
"""
|
|
52
|
+
take a series of arrays and only return the indicies where ALL members are finite
|
|
53
|
+
"""
|
|
54
|
+
mask = ~any([isnan(a) for a in args], axis=0)
|
|
55
|
+
nanless_args = tuple([array(a)[mask] for a in args])
|
|
56
|
+
return nanless_args
|
|
57
|
+
def interpolate2d(
|
|
58
|
+
data, factor: int,
|
|
59
|
+
method: str = 'linear'
|
|
60
|
+
) -> ndarray:
|
|
61
|
+
"""interpolate 2d data on a regular grid by an even factor
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
data (ndarray[ndarray]): 2d data on a regular grid
|
|
65
|
+
factor (int): how many new grid points per old grid points
|
|
66
|
+
method (str, optional): the interpolation method. Defaults to 'linear'.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
ndarray[ndarray]: an interpolated grid of data
|
|
70
|
+
"""
|
|
71
|
+
Nx, Ny = array(data).shape
|
|
72
|
+
return RegularGridInterpolator((arange(Nx), arange(Ny)), data, method=method)(mgrid[:Nx-1:1/factor, :Ny-1:1/factor].T).T
|
|
73
|
+
|
|
74
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
75
|
+
# >-|===|> Decorators <|===|-<
|
|
76
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
77
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
78
|
+
# >-|===|> Classes <|===|-<
|
|
79
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
from os import system
|
|
5
|
+
|
|
6
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
7
|
+
# >-|===|> Types <|===|-<
|
|
8
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
9
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
10
|
+
# >-|===|> Definitions <|===|-<
|
|
11
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
12
|
+
audioDir = '/Users/keyan/code/packages/keyutils/audio/lib/'
|
|
13
|
+
rightplace = '"Caroline Rose - year of the slug - 01 everything in its right place.wav"'
|
|
14
|
+
success = 'success.mp3'
|
|
15
|
+
|
|
16
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
17
|
+
# >-|===|> Functions <|===|-<
|
|
18
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
19
|
+
def play(file: str):
|
|
20
|
+
system(f"afplay {audioDir}{file}")
|
|
21
|
+
def success(): system(f"afplay {audioDir}success.mp3")
|
|
22
|
+
|
|
23
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
24
|
+
# >-|===|> Decorators <|===|-<
|
|
25
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
26
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
27
|
+
# >-|===|> Classes <|===|-<
|
|
28
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
from kbasic.typing import Number
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
import inspect
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
9
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
10
|
+
# >-|===|> Types <|===|-<
|
|
11
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
12
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
13
|
+
# >-|===|> Definitions <|===|-<
|
|
14
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
16
|
+
# >-|===|> Functions <|===|-<
|
|
17
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
18
|
+
def bar(
|
|
19
|
+
x: Number, total: Number,
|
|
20
|
+
width: int = 20, border="|", block="▉"
|
|
21
|
+
) -> str:
|
|
22
|
+
"""create a string representing a progress bar set at 100 * x / total % full.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
x (Number): x out of total
|
|
26
|
+
total (_type_): x out of total
|
|
27
|
+
width (int, optional): how many characters wide the bar should be. Defaults to 20.
|
|
28
|
+
border (str, optional): the character to represent the border of the bar. Defaults to "|".
|
|
29
|
+
block (str, optional): the character representing a full part of the bar. Defaults to "▉".
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
str: a progress bar
|
|
33
|
+
"""
|
|
34
|
+
full = int((x/total) * width // 1)
|
|
35
|
+
empty = width - full
|
|
36
|
+
bar = border + full*block + empty*" " + border
|
|
37
|
+
return bar
|
|
38
|
+
@contextmanager
|
|
39
|
+
def redirect_to_tqdm():
|
|
40
|
+
"""maybe make print statements show up below the bar without fucking everything up?
|
|
41
|
+
idk tbh im not sure how this works exactly I got it from stack exchange.
|
|
42
|
+
"""
|
|
43
|
+
# Store builtin print
|
|
44
|
+
old_print = print
|
|
45
|
+
def new_print(*args, **kwargs):
|
|
46
|
+
# If tqdm.tqdm.write raises error, use builtin print
|
|
47
|
+
try:
|
|
48
|
+
tqdm.write(*args, **kwargs)
|
|
49
|
+
except:
|
|
50
|
+
old_print(*args, ** kwargs)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
# Globaly replace print with new_print
|
|
54
|
+
inspect.builtins.print = new_print
|
|
55
|
+
yield
|
|
56
|
+
finally:
|
|
57
|
+
inspect.builtins.print = old_print
|
|
58
|
+
def progress_bar(iterator, **kwargs):
|
|
59
|
+
"""tqdm with print redirected to tqdm.write
|
|
60
|
+
"""
|
|
61
|
+
with redirect_to_tqdm():
|
|
62
|
+
for x in tqdm(iterator, **kwargs):
|
|
63
|
+
yield x
|
|
64
|
+
def verbose_bar(iterator, verbose, **kwargs):
|
|
65
|
+
"""just a progress bar if verbose is true.
|
|
66
|
+
"""
|
|
67
|
+
return progress_bar(iterator, **kwargs) if verbose else iterator
|
|
68
|
+
|
|
69
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
70
|
+
# >-|===|> Decorators <|===|-<
|
|
71
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
72
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
73
|
+
# >-|===|> Classes <|===|-<
|
|
74
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
75
|
+
class ProgressBar(tqdm):
|
|
76
|
+
def __init__(self, *args, **kwargs):
|
|
77
|
+
super().__init__(self, *args, **kwargs)
|
|
78
|
+
self.iter = self.initial
|
|
79
|
+
def update(self, iter: int):
|
|
80
|
+
super().update(n=iter-self.iter)
|
|
81
|
+
self.iter = iter
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
#pysim imports
|
|
5
|
+
from kbasic.user_input import yesno
|
|
6
|
+
#nonpysim imports
|
|
7
|
+
import numpy as np
|
|
8
|
+
from glob import glob
|
|
9
|
+
from shutil import copy, move, copytree, rmtree
|
|
10
|
+
from os.path import isdir, isfile, exists, abspath
|
|
11
|
+
from os import mkdir, remove
|
|
12
|
+
from functools import cached_property
|
|
13
|
+
|
|
14
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
|
+
# >-|===|> Definitions <|===|-<
|
|
16
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
17
|
+
unreadable_file_types = ['gz', 'tar', 'zip']
|
|
18
|
+
|
|
19
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
20
|
+
# >-|===|> Functions <|===|-<
|
|
21
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
22
|
+
def ensure_path(path: str) -> None:
|
|
23
|
+
"""make sure that a path exists
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
path (str): the path you want to exist
|
|
27
|
+
"""
|
|
28
|
+
parts = path.strip().split('/')
|
|
29
|
+
for i in range(len(parts)):
|
|
30
|
+
if "/".join(parts[:i]) in "/home/x-kgootkin/": continue
|
|
31
|
+
if not exists("/".join(parts[:i])):
|
|
32
|
+
mkdir("/".join(parts[:i]))
|
|
33
|
+
|
|
34
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
35
|
+
# >-|===|> Classes <|===|-<
|
|
36
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
37
|
+
class File:
|
|
38
|
+
def __init__(self, path:str, master=None, executable:bool=False, verbose:bool=False) -> None:
|
|
39
|
+
"""A convenience class to deal with file io
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
path (str): the location of the file.
|
|
43
|
+
master (str, optional): the path to the template to restore this file from if necessary. Defaults to None.
|
|
44
|
+
executable (bool, optional): is this file an executable. Defaults to False.
|
|
45
|
+
verbose (bool, optional): should this file be annoying. Defaults to False.
|
|
46
|
+
"""
|
|
47
|
+
self.path: str = abspath(path.replace("\\", "/").replace('//', '/'))
|
|
48
|
+
pathlist: list[str] = self.path.split("/")
|
|
49
|
+
self.parent = Folder("/".join(pathlist[:-1]))
|
|
50
|
+
self.grandparent = Folder("/".join(pathlist[:-2])) if len(pathlist)>3 else None
|
|
51
|
+
self.greatgrandparent = Folder("/".join(pathlist[:-3])) if len(pathlist)>4 else None
|
|
52
|
+
self.name = self.path.split("/")[-1]
|
|
53
|
+
self.extension = self.name.split(".")[-1] if "." in self.name else None
|
|
54
|
+
self.master = master if not isinstance(master, str) else File(master)
|
|
55
|
+
self.executable = executable
|
|
56
|
+
self.verbose = verbose
|
|
57
|
+
def __repr__(self) -> str: return self.path
|
|
58
|
+
def __str__(self) -> str: return "\n".join(self.lines)
|
|
59
|
+
def __add__(self, other):
|
|
60
|
+
match other:
|
|
61
|
+
case list():
|
|
62
|
+
other.append(self)
|
|
63
|
+
return other
|
|
64
|
+
case File(): return [self, other]
|
|
65
|
+
|
|
66
|
+
case _: raise NotImplementedError(f"can't add object of type: {type(other)} to a Folder object: {repr(self)}")
|
|
67
|
+
def __radd__(self, other):
|
|
68
|
+
if other==0: return self
|
|
69
|
+
return self.__add__(other)
|
|
70
|
+
@property
|
|
71
|
+
def exists(self) -> bool: return exists(self.path)
|
|
72
|
+
def copy(self, destination:str): copy(self.path, destination)
|
|
73
|
+
def move(self, destination:str):
|
|
74
|
+
move(self.path, destination)
|
|
75
|
+
self = File.__init__(destination, master=self.master, executable=self.executable)
|
|
76
|
+
def update(self) -> None:
|
|
77
|
+
if self.verbose: print(f'updating {self.name}...')
|
|
78
|
+
assert self.master is not None, "No master copy to update from."
|
|
79
|
+
if self.exists: self.delete(interactive=False)
|
|
80
|
+
self.master.copy(self.path)
|
|
81
|
+
self = File(self.path, master=self.master)
|
|
82
|
+
def delete(self, interactive=True) -> None:
|
|
83
|
+
if interactive and not yesno(f"Are you sure you want to permanently delete {self.path} and all of its contents?\n"): return None
|
|
84
|
+
else: remove(self.path)
|
|
85
|
+
def read(self) -> None:
|
|
86
|
+
if not self.exists: return []
|
|
87
|
+
with open(self.path, 'r') as file:
|
|
88
|
+
self.lines = [f.strip('\n') for f in file.readlines()]
|
|
89
|
+
def save(self, interactive=True):
|
|
90
|
+
if interactive and not yesno(f"Are you sure you want to permanently overwrite {self.path}?\n"):
|
|
91
|
+
return None
|
|
92
|
+
with open(self.path, 'w+') as file:
|
|
93
|
+
if not file.writable: raise PermissionError(f"attempted to save unwritable file: {self.path}")
|
|
94
|
+
file.writelines("\n".join(self.lines))
|
|
95
|
+
|
|
96
|
+
class Folder:
|
|
97
|
+
def __init__(self, path:str, master=None) -> None:
|
|
98
|
+
self.path = '/' if path=='' else abspath(path.replace("\\", "/").replace('//', '/'))
|
|
99
|
+
self.name = self.path.split("/")[-1] if len(self.path.split('/')[-1])>0 else self.path.split("/")[-2]
|
|
100
|
+
self.master = master if not isinstance(master, str) else Folder(master)
|
|
101
|
+
def __repr__(self) -> str: return self.path
|
|
102
|
+
def __len__(self) -> int: return len(self.children)
|
|
103
|
+
def __iter__(self):
|
|
104
|
+
self.index = 0
|
|
105
|
+
return self
|
|
106
|
+
def __next__(self):
|
|
107
|
+
if self.index < len(self):
|
|
108
|
+
i = self.index
|
|
109
|
+
self.index += 1
|
|
110
|
+
return Folder(self.children[i]) if isdir(self.children[i]) else File(self.children[i])
|
|
111
|
+
else: raise StopIteration
|
|
112
|
+
def __add__(self, other):
|
|
113
|
+
match other:
|
|
114
|
+
case str():
|
|
115
|
+
p = f"{self.path}/{other}"
|
|
116
|
+
return Folder(p) if isdir(p) else File(p) if isfile(p) else None
|
|
117
|
+
case File(): return self.children+[other]
|
|
118
|
+
case Folder(): return self.children + other.children
|
|
119
|
+
case list(): return self.children + other
|
|
120
|
+
case _: raise NotImplementedError(f"can't add object of type: {type(other)} to a Folder object: {repr(self)}")
|
|
121
|
+
def __radd__(self, other):
|
|
122
|
+
if other==0: return [self]
|
|
123
|
+
return self.__add__(other)
|
|
124
|
+
@property
|
|
125
|
+
def exists(self) -> bool: return exists(self.path)
|
|
126
|
+
@property
|
|
127
|
+
def children(self) -> list: return glob(self.path+"/*" if self.path!='/' else "/*")
|
|
128
|
+
def ls(self) -> None: print("\n".join(self.children))
|
|
129
|
+
def make(self) -> None: ensure_path(self.path)
|
|
130
|
+
def copy(self, destination:str) -> None: copytree(self.path, destination)
|
|
131
|
+
def revert(self) -> None:
|
|
132
|
+
assert self.master, "No master copy to update from."
|
|
133
|
+
if self.exists: self.delete(interactive=False)
|
|
134
|
+
self.master.copy(self.path)
|
|
135
|
+
self = Folder(self.path, master=self.master)
|
|
136
|
+
def delete(self, interactive=True) -> None:
|
|
137
|
+
if interactive and not yesno(f"Are you sure you want to permanently delete {self.path} and all of its contents?\n"):
|
|
138
|
+
return None
|
|
139
|
+
rmtree(self.path)
|
|
140
|
+
|
|
141
|
+
def parse(path: str | list[str]) -> Folder | File:
|
|
142
|
+
"""take a path or list of paths and turn them into Folder or File objects as appropriate.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
path (str | list[str]): the path you want to be a File/Folder object
|
|
146
|
+
|
|
147
|
+
Raises:
|
|
148
|
+
FileNotFoundError: if you can't match path
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Folder | File: path as a Folder/File.
|
|
152
|
+
"""
|
|
153
|
+
match path:
|
|
154
|
+
case str():
|
|
155
|
+
if isdir(path): return Folder(path)
|
|
156
|
+
if isfile(path): return File(path)
|
|
157
|
+
case list()|np.ndarray():
|
|
158
|
+
return [Folder(p) if isdir(p) else File(p) if isfile(p) else None for p in path]
|
|
159
|
+
raise FileNotFoundError(f"Unable to parse path(s): {path}")
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
3
4
|
from kbasic.bar import ProgressBar, redirect_to_tqdm
|
|
4
5
|
from kbasic.audio import success
|
|
5
|
-
from
|
|
6
|
+
# from kgsim.dhybridr.io import dHybridRinput
|
|
7
|
+
from subprocess import check_output, DEVNULL
|
|
6
8
|
from tqdm import tqdm
|
|
7
9
|
from time import sleep
|
|
8
|
-
|
|
9
10
|
import asyncio
|
|
11
|
+
import numpy as np
|
|
10
12
|
|
|
13
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
14
|
+
# >-|===|> Types <|===|-<
|
|
15
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
16
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
17
|
+
# >-|===|> Definitions <|===|-<
|
|
18
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
11
19
|
_USERNAME_ = 'x-kgootkin'
|
|
12
|
-
|
|
13
20
|
bad = ['\x1b[31m', '\x1b[34m', '\x1b[m']
|
|
14
21
|
|
|
22
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
23
|
+
# >-|===|> Functions <|===|-<
|
|
24
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
25
|
def parse_shell_output(output):
|
|
16
26
|
match output:
|
|
17
27
|
case str(): return output
|
|
@@ -22,7 +32,6 @@ def parse_shell_output(output):
|
|
|
22
32
|
if b in output[i]:
|
|
23
33
|
output[i] = output[i].strip(b)
|
|
24
34
|
return output
|
|
25
|
-
|
|
26
35
|
def system(cmd: str):
|
|
27
36
|
print(cmd)
|
|
28
37
|
command = cmd.split(' ') if type(cmd)==str else cmd
|
|
@@ -37,17 +46,19 @@ def system(cmd: str):
|
|
|
37
46
|
for j in range(start_quote+1, end_quote+1): del command[j]
|
|
38
47
|
output = parse_shell_output(check_output(command, stderr=DEVNULL).decode().splitlines())
|
|
39
48
|
return output
|
|
40
|
-
|
|
41
49
|
def anvil(cmd: str):
|
|
42
50
|
output = parse_shell_output(check_output(['ssh', 'x-kgootkin@anvil.rcac.purdue.edu', *cmd.split(' ')], stderr=DEVNULL).decode().splitlines())
|
|
43
51
|
return output
|
|
44
|
-
|
|
45
52
|
async def anvil_async(cmd: str): asyncio.to_thread(anvil, cmd)
|
|
46
|
-
|
|
47
|
-
|
|
48
53
|
def anvil_queue(username=_USERNAME_): return anvil(f"squeue -u {username}")
|
|
49
|
-
qs = anvil_queue
|
|
50
|
-
|
|
54
|
+
qs = anvil_queue
|
|
55
|
+
|
|
56
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
57
|
+
# >-|===|> Decorators <|===|-<
|
|
58
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
59
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
60
|
+
# >-|===|> Classes <|===|-<
|
|
61
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
51
62
|
class AnvilJob:
|
|
52
63
|
def __init__(self, queue_row: str, sep="DISTINCTSEPERATOR"):
|
|
53
64
|
self.sep = sep
|
|
@@ -66,32 +77,28 @@ class AnvilJob:
|
|
|
66
77
|
|
|
67
78
|
def __repr__(self): return "-"*30 + f"\n{self.name}: {self.status}\n\t{self.time}/{self.time_limit}"
|
|
68
79
|
|
|
69
|
-
def update(self, input=True, iter=True):
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
# def update(self, input=True, iter=True):
|
|
81
|
+
# match input, iter:
|
|
82
|
+
# case True, True:
|
|
83
|
+
# x = anvil(f"cat /anvil/scratch/{self.username}/sims/{self.name}/input/input; echo {self.sep}; ls /anvil/scratch/{self.username}/sims/{self.name}/Output/Fields/Magnetic/Total/x/")
|
|
84
|
+
# input_lines = "\n".join(x).split(self.sep)[0].split('\n')
|
|
85
|
+
# self.input = dHybridRinput(input_lines)
|
|
86
|
+
# self.iter = int(x[-1][5:-3])
|
|
87
|
+
# case True, False:
|
|
88
|
+
# self.input = dHybridRinput(anvil(f"cat /anvil/scratch/{self.username}/sims/{self.name}/input/input"))
|
|
89
|
+
# case False, True:
|
|
90
|
+
# self.iter = int(anvil(f"ls /anvil/scratch/{self.username}/sims/{self.name}/Output/Fields/Magnetic/Total/x/")[-1][5:-3])
|
|
81
91
|
def get_anvil_jobs(username=_USERNAME_):
|
|
82
92
|
q = anvil(f"squeue -u {username}")
|
|
83
93
|
if type(q)==str: return []
|
|
84
94
|
return [AnvilJob(x) for x in q[1:]]
|
|
85
|
-
|
|
86
95
|
async def get_anvil_jobs_async(username=_USERNAME_):
|
|
87
96
|
q = await asyncio.to_thread(anvil, f"squeue -u {username}")
|
|
88
97
|
if type(q)==str: return []
|
|
89
98
|
return [AnvilJob(x) for x in q[1:]]
|
|
90
|
-
|
|
91
99
|
async def get_anvil_sim_iter(name: str):
|
|
92
100
|
iter = int(await asyncio.to_thread(anvil, f"ls /anvil/scratch/{username}/sims/{name}/Output/Fields/Magnetic/Total/x/")[-1][5:-3])
|
|
93
101
|
return iter
|
|
94
|
-
|
|
95
102
|
class AnvilQueue:
|
|
96
103
|
def __init__(self, username=_USERNAME_):
|
|
97
104
|
self.username = username
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
I don't like type checking in python, so the way i decided to do it is if i want
|
|
3
|
+
to see if something looks like a number (int, float, complex or numpy variants)
|
|
4
|
+
i would say ->
|
|
5
|
+
if type(x) in Number.types: do_something()
|
|
6
|
+
elif type(x) in Iterable.types: do_something_else()
|
|
7
|
+
"""
|
|
8
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
9
|
+
# >-|===|> Imports <|===|-<
|
|
10
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
11
|
+
from numpy import ndarray, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float16, float32, float64, longdouble, complex64, complex128, clongdouble
|
|
12
|
+
|
|
13
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
14
|
+
# >-|===|> Types <|===|-<
|
|
15
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
16
|
+
class Number:
|
|
17
|
+
types: list = [
|
|
18
|
+
int, int8, uint8, int16, uint16, int32, uint32, int64, uint64,
|
|
19
|
+
float, float16, float32, float64, longdouble,
|
|
20
|
+
complex, complex64, complex128, clongdouble
|
|
21
|
+
]
|
|
22
|
+
class Iterable:
|
|
23
|
+
types: list = [
|
|
24
|
+
list, set, dict, tuple, ndarray
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
28
|
+
# >-|===|> Definitions <|===|-<
|
|
29
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
30
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
31
|
+
# >-|===|> Functions <|===|-<
|
|
32
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
33
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
34
|
+
# >-|===|> Decorators <|===|-<
|
|
35
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
36
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
37
|
+
# >-|===|> Classes <|===|-<
|
|
38
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
|
+
# >-|===|> Imports <|===|-<
|
|
3
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
5
|
+
# >-|===|> Types <|===|-<
|
|
6
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
7
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
8
|
+
# >-|===|> Definitions <|===|-<
|
|
9
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
10
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
11
|
+
# >-|===|> Functions <|===|-<
|
|
12
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
13
|
+
def yesno(prompt: str):
|
|
14
|
+
"""
|
|
15
|
+
prompt the user to either reply yes or no
|
|
16
|
+
:param prompt: the yes/no question to be answered
|
|
17
|
+
:return: True if yes False if no
|
|
18
|
+
"""
|
|
19
|
+
response = input(prompt).lower()
|
|
20
|
+
if 'y' in response and not 'n' in response:
|
|
21
|
+
return True
|
|
22
|
+
elif 'n' in response and not 'y' in response:
|
|
23
|
+
return False
|
|
24
|
+
else:
|
|
25
|
+
def retry_yesno():
|
|
26
|
+
retry_prompt = "Sorry I couldn't read that please respond with yes or no\n" + prompt
|
|
27
|
+
retry_response = input(retry_prompt).lower()
|
|
28
|
+
if 'y' in retry_response and not 'n' in retry_response:
|
|
29
|
+
return True
|
|
30
|
+
elif 'n' in retry_response and not 'y' in retry_response:
|
|
31
|
+
return False
|
|
32
|
+
else:
|
|
33
|
+
raise ValueError("need a response with either y or n in it.")
|
|
34
|
+
|
|
35
|
+
return retry_yesno()
|
|
36
|
+
|
|
37
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
38
|
+
# >-|===|> Decorators <|===|-<
|
|
39
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
40
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
41
|
+
# >-|===|> Classes <|===|-<
|
|
42
|
+
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
2
2
|
# >-|===|> Imports <|===|-<
|
|
3
3
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
4
|
-
from numpy import array,
|
|
4
|
+
from numpy import array, cos, sin, sqrt, exp
|
|
5
5
|
from typing import Self
|
|
6
6
|
from collections.abc import Generator
|
|
7
|
+
from kbasic.typing import Number, Iterable
|
|
8
|
+
|
|
7
9
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
8
10
|
# >-|===|> Definitions <|===|-<
|
|
9
11
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
10
|
-
class Number:
|
|
11
|
-
types: list = [float, float64, float32, int, complex, complex128]
|
|
12
|
-
class Iterable:
|
|
13
|
-
types: list = [list, ndarray, tuple, Generator]
|
|
14
12
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
15
13
|
# >-|===|> Functions <|===|-<
|
|
16
14
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -30,6 +28,7 @@ def organize_components(components) -> tuple[float|int]:
|
|
|
30
28
|
case (Generator(),): return tuple(components[0])
|
|
31
29
|
case (Vector(),): return components[0].components
|
|
32
30
|
case _: raise TypeError(f"{components} cannot be matched")
|
|
31
|
+
|
|
33
32
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
34
33
|
# >-|===|> Classes <|===|-<
|
|
35
34
|
# !==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==!==
|
|
@@ -92,7 +91,6 @@ class Vector:
|
|
|
92
91
|
match other:
|
|
93
92
|
case 0: return self
|
|
94
93
|
case _: return self.__floordiv__(other)
|
|
95
|
-
|
|
96
94
|
class Norm(Vector):
|
|
97
95
|
def __init__(self, *components):
|
|
98
96
|
components: tuple = organize_components(components)
|
|
@@ -105,7 +103,6 @@ class Quaternion(Norm):
|
|
|
105
103
|
self.axis = sin(angle/2)*Vector(axis)
|
|
106
104
|
self.axis *= sqrt(1-q0**2)/abs(self.axis)
|
|
107
105
|
Norm.__init__(self, q0, *self.axis.components)
|
|
108
|
-
|
|
109
106
|
class R2(Vector):
|
|
110
107
|
def __init__(self, *components):
|
|
111
108
|
self.components: tuple[Number] = organize_components(components)
|
|
@@ -136,7 +133,6 @@ class R3(Vector):
|
|
|
136
133
|
rotation_inverse = array([rotation[0], *-rotation[1:]])
|
|
137
134
|
rotated_vector = hamilton_product(hamilton_product(rotation, qs), rotation_inverse)[1:]
|
|
138
135
|
self.__init__(*rotated_vector)
|
|
139
|
-
|
|
140
136
|
class Matrix:
|
|
141
137
|
def __init__(self, array):
|
|
142
138
|
self.array = array
|
kbasic-0.1.2/README.md
DELETED
|
File without changes
|
kbasic-0.1.2/src/kbasic/Tex.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import warnings
|
|
2
|
-
# Syntax warnings show up everytime you \something so we ignore all of em, hope this doesn't fuck anything up!
|
|
3
|
-
warnings.filterwarnings(action='ignore', category=SyntaxWarning)
|
|
4
|
-
from pylatexenc.latex2text import LatexNodes2Text
|
|
5
|
-
l2t = LatexNodes2Text().latex_to_text
|
|
6
|
-
|
|
7
|
-
class Tex(str):
|
|
8
|
-
def __init__(self, x):
|
|
9
|
-
x = x.strip(' $')
|
|
10
|
-
if x[-1]=='\n': x = x[:-1]
|
|
11
|
-
if x[-2:]=='.0': x = x[:-2]
|
|
12
|
-
# replace wonky \ letter commands with raw versions
|
|
13
|
-
# WARNING: DOES NOT WORK WITH \U OR \X BECAUSE THESE ARE UNICODE THINGS AND IDK HOW TO OVERRIDE THAT BEHAVIOR
|
|
14
|
-
x = x.replace("\a", r"\a").replace("\b", r"\b").replace("\f", r"\f").replace("\n", r"\n").replace("\r", r"\r").replace("\t", r"\t").replace("\v", r"\v")
|
|
15
|
-
# make compatible with fstring
|
|
16
|
-
x = x.replace("[", "{").replace("]", "}")
|
|
17
|
-
# get rid of extraneous .0's
|
|
18
|
-
x = x.replace(".0 ", " ").replace(".0}", "}").replace(".0$", "$").replace(".0\n", "\n")
|
|
19
|
-
self.string = fr"{l2t(x)}"
|
|
20
|
-
self.wrap = "$"+self.string+"$"
|
|
21
|
-
|
|
22
|
-
def __repr__(self): return self.string.strip("$")
|
|
23
|
-
def __str__(self): return self.string
|
kbasic-0.1.2/src/kbasic/array.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from scipy.interpolate import RegularGridInterpolator
|
|
3
|
-
|
|
4
|
-
def where_closest(arr:np.ndarray, x): return np.argmin(np.abs(arr-x))
|
|
5
|
-
def where_between(arr:np.ndarray, low, high): return np.where((arr>=low)&(arr<=high))
|
|
6
|
-
|
|
7
|
-
def bin_this(x, y, n_bins=50, func=np.nanmean):
|
|
8
|
-
xbins = np.linspace(np.nanmin(x),np.nanmax(x),n_bins)
|
|
9
|
-
Y,error = list(),list()
|
|
10
|
-
for i,low_edge in enumerate(xbins[:-1]):
|
|
11
|
-
high_edge = xbins[i+1]
|
|
12
|
-
mask = (low_edge<x)&(x<high_edge)
|
|
13
|
-
yin = y[mask]
|
|
14
|
-
Y.append(func(yin))
|
|
15
|
-
error.append(np.nanstd(yin)/np.sqrt(len(yin)))
|
|
16
|
-
return np.array(xbins)[:-1],np.array(Y),np.array(error)
|
|
17
|
-
|
|
18
|
-
def nan_clip(*args):
|
|
19
|
-
mask = ~np.any([np.isnan(a) for a in args], axis=0)
|
|
20
|
-
nanless_args = tuple([np.array(a)[mask] for a in args])
|
|
21
|
-
return nanless_args
|
|
22
|
-
|
|
23
|
-
def interpolate2d(data, factor, method='cubic'):
|
|
24
|
-
Nx, Ny = np.array(data).shape
|
|
25
|
-
return RegularGridInterpolator((np.arange(Nx), np.arange(Ny)), data, method=method)(np.mgrid[:Nx-1:1/factor, :Ny-1:1/factor].T).T
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
from os import system
|
|
2
|
-
audioDir = '/Users/keyan/code/packages/keyutils/audio/lib/'
|
|
3
|
-
rightplace = '"Caroline Rose - year of the slug - 01 everything in its right place.wav"'
|
|
4
|
-
success = 'success.mp3'
|
|
5
|
-
|
|
6
|
-
def play(file: str):
|
|
7
|
-
system(f"afplay {audioDir}{file}")
|
|
8
|
-
def success(): system(f"afplay {audioDir}success.mp3")
|
kbasic-0.1.2/src/kbasic/bar.py
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
from contextlib import contextmanager
|
|
2
|
-
import inspect
|
|
3
|
-
from tqdm import tqdm
|
|
4
|
-
|
|
5
|
-
def bar(x, total, width: int = 20, border="|", block="▉"):
|
|
6
|
-
full = int((x/total) * width // 1)
|
|
7
|
-
empty = width - full
|
|
8
|
-
bar = border + full*block + empty*" " + border
|
|
9
|
-
return bar
|
|
10
|
-
|
|
11
|
-
@contextmanager
|
|
12
|
-
def redirect_to_tqdm():
|
|
13
|
-
# Store builtin print
|
|
14
|
-
old_print = print
|
|
15
|
-
def new_print(*args, **kwargs):
|
|
16
|
-
# If tqdm.tqdm.write raises error, use builtin print
|
|
17
|
-
try:
|
|
18
|
-
tqdm.write(*args, **kwargs)
|
|
19
|
-
except:
|
|
20
|
-
old_print(*args, ** kwargs)
|
|
21
|
-
|
|
22
|
-
try:
|
|
23
|
-
# Globaly replace print with new_print
|
|
24
|
-
inspect.builtins.print = new_print
|
|
25
|
-
yield
|
|
26
|
-
finally:
|
|
27
|
-
inspect.builtins.print = old_print
|
|
28
|
-
|
|
29
|
-
def progress_bar(iterator, **kwargs):
|
|
30
|
-
with redirect_to_tqdm():
|
|
31
|
-
for x in tqdm(iterator, **kwargs):
|
|
32
|
-
yield x
|
|
33
|
-
|
|
34
|
-
def verbose_bar(iterator, verbose, **kwargs):
|
|
35
|
-
return progress_bar(iterator, **kwargs) if verbose else iterator
|
|
36
|
-
|
|
37
|
-
class ProgressBar(tqdm):
|
|
38
|
-
def __init__(self, *args, **kwargs):
|
|
39
|
-
super().__init__(self, *args, **kwargs)
|
|
40
|
-
self.iter = self.initial
|
|
41
|
-
def update(self, iter: int):
|
|
42
|
-
super().update(n=iter-self.iter)
|
|
43
|
-
self.iter = iter
|
kbasic-0.1.2/src/kbasic/py.typed
DELETED
|
File without changes
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from numpy import ndarray, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float16, float32, float64, longdouble, complex64, complex128, clongdouble
|
|
2
|
-
|
|
3
|
-
class Number:
|
|
4
|
-
types: list = [
|
|
5
|
-
int, int8, uint8, int16, uint16, int32, uint32, int64, uint64,
|
|
6
|
-
float, float16, float32, float64, longdouble,
|
|
7
|
-
complex, complex64, complex128, clongdouble
|
|
8
|
-
]
|
|
9
|
-
|
|
10
|
-
class Iterable:
|
|
11
|
-
types: list = [
|
|
12
|
-
list, set, dict, tuple, ndarray
|
|
13
|
-
]
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
def yesno(prompt: str):
|
|
2
|
-
"""
|
|
3
|
-
prompt the user to either reply yes or no
|
|
4
|
-
:param prompt: the yes/no question to be answered
|
|
5
|
-
:return: True if yes False if no
|
|
6
|
-
"""
|
|
7
|
-
response = input(prompt).lower()
|
|
8
|
-
if 'y' in response and not 'n' in response:
|
|
9
|
-
return True
|
|
10
|
-
elif 'n' in response and not 'y' in response:
|
|
11
|
-
return False
|
|
12
|
-
else:
|
|
13
|
-
def retry_yesno():
|
|
14
|
-
retry_prompt = "Sorry I couldn't read that please respond with yes or no\n" + prompt
|
|
15
|
-
retry_response = input(retry_prompt).lower()
|
|
16
|
-
if 'y' in retry_response and not 'n' in retry_response:
|
|
17
|
-
return True
|
|
18
|
-
elif 'n' in retry_response and not 'y' in retry_response:
|
|
19
|
-
return False
|
|
20
|
-
else:
|
|
21
|
-
raise ValueError("need a response with either y or n in it.")
|
|
22
|
-
|
|
23
|
-
return retry_yesno()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|